PPR Hub

Product Modeler

Initializing the Applicative Container at Runtime

Performing runtime initialization tasks
Use Case
CAAPstIntegrateNewFeatures > CAAPstINFBuildCatalog > CAAPstINFCreateDocument > CAAPstINFInitCont > CAAPstINFNavigate > CAAPstINFVisu > CAAPstINFGraphicalProperties  > CAAPstINFEdit > CAAPstINFCCP > CAAPstINFDelete > CAAPstINFUpdate

Abstract

This article discusses the CAAPstINFInitCont use case. This use case explains what necessary initialization tasks must be performed in order for the provider and visualization mechanisms to be correctly declared to the document during the loading process. 


What You Will Learn With This Use Case

This use case is intended to illustrate how to program the necessary initialization tasks that must be performed in order for certain feature behaviors to function correctly at runtime. One of these initialization tasks concerns the declaration of providers. Because the features created in this use case are "from scratch" features, meaning that they do not derive from any existing feature that may already be known to the navigation, visualization or update processes, it is necessary to use providers in order to be able to take them into account. The declaration of providers is not persistent to the document. It is necessary, therefore, to declare them each time the document is opened.  Since providers refer to "from scratch" features that are stored in applicative containers, it seems reasonable, then, to perform the declaration of providers in the initialization process of the applicative container, which is called whenever the Product document is loaded into the session. Likewise, visualization connections between objects is also a non-persistent mechanism that has to be renewed at document load-time. Therefore, in this use case, you will see how to program the provider declarations that handle the integration of your new features in the navigation, visualization and update processes as well as how to connect the root features to the Product root and the aggregated features to their feature root in order to correctly structure the document for visualization purposes. 

You should already be familiar with the CAAPstIntegrateNewFeatures use case article [1] in order to more easily understand the context of this particular use case. A general pre-requisite knowledge of the Feature Modeler and of Providers may be required to fully understand this sample. You may want to review the basics of the Feature Modeler by looking over the "Feature Modeler Overview" technical article [2]. You may also want to look at the "Using the Provider Mechanism" use case [3] which describes the basics of the Provider mechanism. Finally, it may be useful for you to look over the "Product Structure Model" technical article [4] as well.

[Top]

The CAAPstINFInitCont Use Case

The CAAPstINFInitCont a use case that is part of the CAAPstIntegrateNewFeatures use case defined in the CAAProductStructure.edu framework that illustrates the integration of ObjectSpecsModeler, ObjectModelerBase and ProductStructure framework capabilities in the scope of a Product document.

[Top]

What Does the CAAPstINFInitCont Use Case Do

This use case essentially describes the applicative container's implementation of the CATInit interface in which the necessary provider declarations and feature inter-connections are performed.

Let's take a look at the contents of the Product document. Initially, the Product document is created and the "CAAPstINFCont" applicative container is created within it. Next, two "CAAPstINFRoot" features are instantiated in the applicative container, the first that will aggregate the other features and the second that will be used during the interactive scenario to demonstrate CCP capabilities. Five "CAAPstINFPoint" features are then instantiated in the applicative container, each having different coordinate values. A "CAAPstINFLine" feature is instantiated next, whose attribute values reference the first two "CAAPstINFPoint" features. Finally, a "CAAPstINFWire" feature is instantiated, whose attribute value references a list containing the last three "CAAPstINFPoint" features. The "CAAPstINFPoint", "CAAPstINFLine" and "CAAPstINFWire" features are then aggregated by the first "CAAPstINFRoot" feature. Here are the contents of the new Product document:

Fig. 1: Contents of the CAAPstINFDocument.CATProduct document.

As you can see, the "CAAPstINFPoint", "CAAPstINFLine" and "CAAPstINFWire" types of features are the elements in the list of components of the "CAAPstINFRoot1" feature. Also, notice that the "CAAPstINFLine1" attributes point to "CAAPstINFPoint1" and "CAAPstINFPoint2" through a "SpecObject" link and that the  "CAAPstINFWire1" attribute points to a list containing the "CAAPstINFPoint3", "CAAPstINFPoint4", "CAAPstINFPoint5" features also through a "SpecObject" link. 

You can see, in this case, that the "CAAPstINFRoot1" feature aggregates the other features, meaning that if "CAAPstINFRoot1" were to be deleted, all of the aggregated features would be deleted as well. The "CAAPstINFLine" object, on the other hand, only references the two points that make up its definition, meaning that if it is deleted, the two points continue to exist independently. Inversely, however, if ever one of the two points is deleted, it is necessary to delete the line as well, since its definition will no longer be valid.

Note that nowhere in this document have we specified where the "CAAPstINFRoot" nodes themselves are to be structured. This operation will take place during the initialization of the applicative container, at runtime. When the Product document is opened in the CATIA interactive session, the implementation of the CATInit::Init method for the "CAAPstINFCont" applicative container is executed. This method declares the provider implementations that will need to be executed during the navigation and visualization processes in order to structure the "CAAPstINFRoot" features under the Product root in the specs tree and to be able to visualize the geometry of the point and line features. So, when the document is finally visualized, it looks like this:

Fig. 2: Initial loading of CAAPstINFDocument.CATProduct document.

As you can see, the "CAAPstINFRoot1" and "CAAPstINFRoot2" features are structured directly under the Product root. This is defined in the navigation provider implementation. Remember that the navigation provider mechanism has been implemented for all products in a Product document. This means that during the navigation process, for each product node, any navigation provider that is currently declared to the document will be executed. So, in order to structure the "CAAPstINFRoot" features under the product root, the navigation provider code retrieves the "CAAPstINFRoot" types of features from the "CAAPstINFCont" applicative container and returns them as children nodes whenever the provider is called by the Product root object during the navigation process.

Note also that the geometry of the points, line and wire is also visualized, whereas these are applicative features stored in an applicative container and are not automatically taken into account during the visualization process. In order these objects to be treated, a visualization provider must also have been declared, which, when called, returns the list of the aggregating feature root nodes. Then, the CATI3DGeoVisu implementation for each feature root as well as for each aggreagted object in order to define the visualization.

Remember that "CAAPstINFLine1" is defined based on "CAAPstINFPoint1" and "CAAPstINFPoint2". If ever one of these point features were to be modified, the line feature would have to be updated. But, because any number of features could be dependent on the same point feature for their own definition, the update process is implemented at the Product root level. The Product root, however, does not have any knowledge of all of the different "from scratch" features that may exist in the document. It is necessary, therefore, to declare an update provider that will be called by the Product root whenever it is requested to update.

The scope of this use case, however, is not to illustrate the provider mechanism for these processes, but rather to demonstrate the construction of the document and the declaration of the necessary providers. Other use cases dealing with navigation [5], visualization [6] and update [7] will detail each of these processes.

[Top]

How to Launch the CAAPstINFInitCont Use Case

See the section entitled "How to Launch the CAAPstIntegrateNewFeatures Use Case" in the "Integrating New Features in a Product Structure" use case for a detailed description of how this use case should be launched.

Specifically, the code described in this article is executed upon loading the Product document (you can use the CAAPstINFDocument.CATProduct document that can be found in the CNext/resources/graphic directory of the CAAProductStructure.edu framework) into the CATIA session. It is during the loading process that the initialization of any applicative containers occurs. 

[Top]

Where to Find the CAAPstINFInitCont Code

This use case describes the implementation class of the CATInit interface, called CAAEPstINFInitCont, which is found in the CAAEPstINFInitCont.cpp source file and CAAEPstINFInitCont.h header file of the CAAPstINFModeler.m shared library.

Windows InstallRootDirectory\CAAProductStructure.edu\CAAPstINFModeler.m
Unix InstallRootDirectory/CAAProductStructure.edu/CAAPstINFModeler.m

where InstallRootDirectory is the directory where the CAA CD-ROM is installed.

[Top]

Step-by-Step

There are three logical steps in CAAPstINFInitCont:

  1. Declaring Available Providers to the Document
  2. Connecting Features to their Visualization Roots 
  3. Declaring the CCP Format

We will now comment each of these sections by looking at the code.

[Top]

Declaring Available Providers to the Document

The necessary declarations related to the applicative container that must be performed at runtime can be made in the implementation of the Init method of CATInit. This method is executed at the time the document is loaded into the interactive session. It essentially contains the declarations of the provider implementations that have been supplied in order to integrate new features in various CATIA mechanisms. In this use case, we illustrate the navigation, visualization and update providers. Following is the code of the implementation class called CAAEPstINFInitCont of the CATInit interface for the "CAAPstINFCont" applicative container defined in this use case. The code of this implementation can be found in the CAAEPstINFInitCont.cpp source file of the CAAPstINFModeler.m module.

void CAAEPstINFInitCont::Init (CATBoolean destroyExistingData)   
{
    cout << "***** CAAPstINFCont: CAAEPstINFInitCont::Init" << endl;

    // Retrieve the current document
    CATILinkableObject *piLinkableOnCont = NULL;
    HRESULT rc = this -> QueryInterface(IID_CATILinkableObject,
                                        (void**) &piLinkableOnCont);
    if (!SUCCEEDED(rc)) return;

    CATDocument *pDoc = piLinkableOnCont -> GetDocument();
    piLinkableOnCont -> Release();
    piLinkableOnCont = NULL;
    if (NULL == pDoc) return;
    cout << "Document retrieved OK" << endl << flush;


    // Retrieve a CATIProviders pointer on the current document
    CATIProviders *piProvidersOnDocument = NULL;
    rc = pDoc -> QueryInterface(IID_CATIProviders,
                                (void**) &piProvidersOnDocument);
    if (!SUCCEEDED(rc)) return;

    // Declare the navigation provider to list the feature root(s) 
    CAAPstINFNavigProviderRoot *pNavigProviderRoot = new CAAPstINFNavigProviderRoot();
    rc = piProvidersOnDocument -> AddProvider (CATINavigateProvider::ClassId(),
	                                       pNavigProviderRoot);
    pNavigProviderRoot -> Release();
    pNavigProviderRoot = NULL;

    if (!SUCCEEDED(rc)) return;
    else cout << "Navigation provider for root declared OK" << endl << flush; 

    // Declare the visualization provider to list the children of the applicative container 
    CAAPstINFVisuProviderRoot *pVisuProviderRoot = new CAAPstINFVisuProviderRoot();
    rc = piProvidersOnDocument -> AddProvider (CATI3DVisuProvider::ClassId(),
	                                       pVisuProviderRoot);
    pVisuProviderRoot -> Release();
    pVisuProviderRoot = NULL;

    if (!SUCCEEDED(rc)) return;
    else cout << "Visualization provider declared OK" << endl << flush; 

    // Declare the line and wire feature update provider to re-build line and wire after modification
    // of points 
    CAAPstINFUpdateProviderLine *pUpdateProviderLine = new CAAPstINFUpdateProviderLine();
    rc = piProvidersOnDocument -> AddProvider (CATIUpdateProvider::ClassId(),
	                                       pUpdateProviderLine);
    pUpdateProviderLine -> Release();
    pUpdateProviderLine = NULL;

    piProvidersOnDocument -> Release();
    piProvidersOnDocument = NULL;

    if (!SUCCEEDED(rc)) return;
    else cout << "Line and wire update provider declared OK" << endl << flush; 
...    

Essentially, this method performs the provider declarations for navigation, visualization and update. Remember that providers are declared to the document. Therefore, it is first necessary to retrieve a CATDocument pointer to the current document. This is done through the CATILinkableObject::GetDocument method. Then, a CATIProviders interface pointer can be retrieved on the document. Using this interface, we can execute the AddProvider method for each provider implementation. This method takes the following arguments:

[Top]

Connecting Features to their Visualization Roots

In this section you will see how each feature root is connected to the Product root and each aggregated feature is connected to its feature root. This connecting operation is necessary in order for the visualization process to work correctly.

1. Retrieve the Product root.

    // Retrieve the Product root

    CATIProduct *piRootProduct = NULL;
	
    CATIDocRoots* piDocRootsOnDoc = NULL;
    rc = pDoc -> QueryInterface(IID_CATIDocRoots,
                                (void**) &piDocRootsOnDoc);
    if (SUCCEEDED(rc))
    {
       // Retrieve the root product which is the first element of root elements
       CATListValCATBaseUnknown_var* pRootProducts = piDocRootsOnDoc -> GiveDocRoots();
       piDocRootsOnDoc -> Release();
       piDocRootsOnDoc = NULL;
       CATBaseUnknown *pBaseRootProduct = NULL;
   
       if (pRootProducts && pRootProducts->Size())
       {  
	  pBaseRootProduct = (*pRootProducts)[1];
	  delete pRootProducts;
	  pRootProducts = NULL;
	  rc = pBaseRootProduct -> QueryInterface(IID_CATIProduct,
	                                          (void**) &piRootProduct);
          if (FAILED(rc)) return;
       }
    }
    else return;
...  

It is necessary to first retrieve the Product document's root because all the feature roots will be connected to it. In order to retrieve the product roots, we first need to retrieve a CATIDocRoots pointer on the current document. Then, using the GiveDocRoots method, we retrieve a list of products, the first of which is the Product document's root. We then save this object in a CATIProduct pointer.

[Top]

2. Connect the features to their roots.

2.1 Retrieve a list of the applicative container's features.

...
    CATUnicodeString appliContIdentifier("PstINFContainer");
    CATBaseUnknown *pApplicativeContainer = NULL;

    rc = ::CATGetApplicativeContainer (&pApplicativeContainer,   
                                       pDoc,                     
	  			       IID_CATIClientContainer,  
                                       appliContIdentifier);     
    if (SUCCEEDED(rc)) cout << "Applicative container retrieved OK" << endl << flush;
    else
    {
       cout << "ERROR in retrieving applicative container" << endl << flush;
       return;
    }

    // Retrieve a pointer to CATIClientContainer in order to list the members
    // of the applicative container.

    CATIClientContainer *piClientOnAppliCont = (CATIClientContainer *) pApplicativeContainer;
    
    // Retrieve the list of features in the applicative container
    CATUnicodeString clientId("CAAPstINFClientId"); 
    CATListPtrCATBaseUnknown *pMemberList = new CATListPtrCATBaseUnknown();
    rc = piClientOnAppliCont -> ListMembers(IID_CATISpecObject,
                                            clientId,  
                                            &pMemberList);
    pApplicativeContainer -> Release();
    pApplicativeContainer = NULL;

    if (SUCCEEDED(rc)) cout << "Member list retrieved OK" << endl << flush;
    else
    { 
       cout << "ERROR in retrieving member list" << endl << flush;
       return;
    }

    cout << "Number of members in applicative container: " << pMemberList->Size() << endl << flush;
      
    // Retrieve a CATIModelEvents pointer to the Product root
    CATIModelEvents *piModelEventsOnProductRoot = NULL;
    rc = piRootProduct -> QueryInterface(IID_CATIModelEvents,
                                         (void**) &piModelEventsOnProductRoot);
    if (FAILED(rc)) return;
	
    piRootProduct -> Release();
    piRootProduct = NULL;
...	

In order to retrieve the contents of the applicative container, we first need to get a pointer to the applicative container itself, which can be done using the CATGetApplicativeContainer global function. Then, since the CATIClientContainer interface was requested in this call, we can simply cast the returned CATBaseUnknown pointer to CATIClientContainer in order to access the ListMembers method. This method returns a list of all of the features contained in the applicative container. Once we have retrieved all of our features, we can prepare to connect them first of all to the Product root by retrieving a CATIModelEvents pointer on the Product root itself.

[Top]

2.2 Connect the feature roots to the Product root.

...
    CATUnicodeString rootType("");
    CATISpecObject *piSpecMember = NULL;
    for(int i=1;i<=pMemberList->Size();i++)
    {
       piSpecMember = (CATISpecObject *) (*pMemberList)[i];
       rootType = piSpecMember -> GetType();
       if (rootType == "CAAPstINFRoot")
       {
 	  // Connect the feature root to the Product root
	  piModelEventsOnProductRoot -> ConnectTo((*pMemberList)[i]);       
...          

The list is scanned for "CAAPstINFRoot" feature types. When one is found, it is connected to the Product root using the ConnectTo method of CATIModelEvents.

[Top]

2.3 Connect every aggregated feature to its root.

...
          // Retrieve the list of aggregated or referenced features
          CATISpecAttrAccess *piSpecAttrAccessOnFeatureRoot = NULL;
	  rc = (*pMemberList)[i] -> QueryInterface(IID_CATISpecAttrAccess,
                                                   (void**) &piSpecAttrAccessOnFeatureRoot);
	  if (FAILED(rc)) return;

          CATUnicodeString keyName = "ListOfComponents";
	
          CATISpecAttrKey *piComponentKey = piSpecAttrAccessOnFeatureRoot -> GetAttrKey (keyName);
	  if (NULL == piComponentKey) return;
	      	  
	  CATIModelEvents *piModelEventsOnFeatureRoot = NULL;
	  rc = (*pMemberList)[i] -> QueryInterface(IID_CATIModelEvents,
                                                   (void**) &piModelEventsOnFeatureRoot);
	  if (FAILED(rc)) return;
          
	  CATISpecObject *piFeatureComponent = NULL;
          piSpecAttrAccessOnFeatureRoot -> Beginning(piComponentKey);
          while (piSpecAttrAccessOnFeatureRoot -> Next(piComponentKey))	
	  {
	     // Connect each feature to its root
	     piFeatureComponent = piSpecAttrAccessOnFeatureRoot -> GetSpecObject(piComponentKey);	
             piModelEventsOnFeatureRoot -> ConnectTo((CATBaseUnknown *)piFeatureComponent);
	     piFeatureComponent = NULL;
          }

          piSpecAttrAccessOnFeatureRoot -> Release();
          piSpecAttrAccessOnFeatureRoot = NULL;

	  piComponentKey -> Release();
	  piComponentKey = NULL;

	  piModelEventsOnFeatureRoot -> Release();
	  piModelEventsOnFeatureRoot = NULL;
   
      }
      (*pMemberList)[i] -> Release();
      (*pMemberList)[i] = NULL;
      piSpecMember = NULL;
    }
    piModelEventsOnProductRoot -> Release();
    piModelEventsOnProductRoot = NULL;
    delete pMemberList;
    pMemberList = NULL;
...   

For each feature root, we would now like to retrieve every feature it aggregates and connect this feature to it. In order to do this, we first need to get a CATISpecAttrAccess pointer on the feature root. Then, using the GetAttrKey method, we can retrieve the attribute key pointing to the list of features. Next, we prepare to connect the aggregated features by retrieving a CATIModelEvents pointer on the feature root. Note that an implementation of this interface for the feature root must already have been provided. Now we can scan through the list of features using the Beginning and Next methods of CATISpecAttrAccess and retrieve a pointer to each feature using the GetSpecObject method. Finally, each aggregated feature can be connected to its root using the ConnectTo method of CATIModelEvents

[Top]

Declaring the CCP Format

...
    // Declare the CCP Format
    ::SpecBindNativeFormat("CAAPstINFCont");
...    

In order for the Cut/Copy/Paste mechanism to function correctly on the applicative container, it is necessary to declare it as the CCP format using the SpecBindNativeFormat global function. 

[Top]


In Short

The CAAPstINFInitCont use case has shown you how to initialize the applicative container at runtime so that navigation, visualization and update processes can account for these new features through provider declarations and visualization connections. 

[Top]


References

[1] Integrating New Features in a Product Document
[2] Feature Modeler Overview
[3] Using the Provider Mechanism
[4] The Product Structure Model
[5] Enabling the Navigation of New Features in a Product Document
[6] Enabling the Visualization of New Features in a Product Document
[7] Enabling New Features in a Product Document to be Updated
[Top]

History

Version: 1 [June 2002] Document created
[Top]

Copyright © 2002, Dassault Systèmes. All rights reserved.