PPR Hub

Product Modeler

Enabling the Navigation of New Features in a Product Document

Integrating new features in the specs tree
Use Case
CAAPstIntegrateNewFeatures > CAAPstINFBuildCatalog > CAAPstINFCreateDocument > CAAPstINFInitCont > CAAPstINFNavigate > CAAPstINFVisu > CAAPstINFGraphicalProperties  > CAAPstINFEdit > CAAPstINFCCP > CAAPstINFDelete > CAAPstINFUpdate

Abstract

This article discusses the CAAPstINFNavigate use case. This use case explains how to integrate new features created "from scratch" in the product structure's specs tree.


What You Will Learn With This Use Case

This use case is intended to illustrate how new features created "from scratch" in an applicative container of a Product document can be integrated in the specs tree of the product structure. The specs tree is created through CATIA's navigation process. This is a mechanism that allows a feature to be visualized as the node of a tree and enables it to display its children as nodes as well. The native CATIA navigation process for each document type takes into account the different containers and features that are native to that particular document. However, it has no knowledge of features created in user-defined applicative containers. The purpose of this use case is to show how these types of features can nevertheless be displayed in the product structure specs tree under a product node in a Product document. 

For a better understanding of the navigation process, it may be helpful for you to look at the ObjectModelerBase use case article entitled "The Object Navigator" [1].

[Top]

The CAAPstINFNavigate Use Case

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

[Top]

What Does the CAAPstINFNavigate Use Case Do

This use case illustrates the integration in the navigation process of new features created in an applicative container within a Product document. Following are the contents of the applicative container we will be working with in the CAAPstINFDocument.CATProduct document supplied with this use case.

Fig. 1: Contents of the CAAPstINFCont applicative container.

As you can see, initially, we are basically working with eight features: two "CAAPstINFRoot" features, five "CAAPstINFPoint" features, one "CAAPstINFLine" feature and one "CAAPstINFWire" feature. None of these objects would natively appear in the product structure specs tree. Looking at this data, we can see that there would be two ways to add them to the specs tree:

  1. Integrate all of our eight features under a product node in the structure.
  2. Integrate the two root features under a product node in the structure and the other geometric features under the aggregating roots.

Given the way our data has been designed, the second choice seems to be the natural one: we have two root nodes, one of which aggregates five points, a line and a wire, the other being empty. The resulting product structure we would like to arrive at would look like this:

		ProductRoot
                |
                |____ CAAPstINFRoot1
                |     |
                |     |____ CAAPstINFPoint1              
                |           CAAPstINFPoint2
                |           CAAPstINFPoint3
                |           CAAPstINFPoint4
                |           CAAPstINFPoint5
                |           CAAPstINFLine1
                |           CAAPstINFWire1
                |      
                |____ CAAPstINFRoot2
 

So, basically, since the Product nodes are all natively taken into account by the navigation process, we would like to insert the "CAAPstINFRoot" features somehow under one of them, the Product root itself, for example. The solution to this is to use a navigation provider supplied by the ProductStructure framework. The interface corresponding to this provider is called CATINavigateProvider and corresponds to the CATINavigateObject interface. The native navigation process works by requesting each node it meets to list its children. Thus, the first node in the product structure, the Product root, would list all of the products it aggregates. Each product in turn would list its aggregated objects. When a navigation provider is active, it is called at each step as well. It is up to the navigation provider algorithm to decide to which caller it wants to return the list of its children.

In our example, the navigation provider algorithm returns the two "CAAPstINFRoot" features if it is called by the Product root. The navigation process then aggregates these features as nodes under the Product root. Once they are in the navigation process, the native CATINavigateObject interface implementation for the "CAAPstINFRoot" feature is called to request the list of its children.

This use case will explain how to program the navigation provider (CATINavigateProvider implementation) and the native navigation implementation (CATINavigateObject implementation) so that the features created in an applicative container can be correctly structured in the specs tree.

Here is an image of a CATIA session where the CAAPstINFDocument.CATProduct has been loaded. Notice that the navigation process has taken our initial scheme into account and has structured the new geometric features under "CAAPstINFRoot1" and both "CAAPstINFRoot" features under the Product root.

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

What is very important to remember is that provider implementations are runtime mechanisms. In order to activate them at runtime, it is necessary to declare them to the document during its initiation. Because our features are all created in the same applicative container, a natural place for declaring our providers would be during the initialization of the applicative container. This means implementing the CATInit::Init method for our applicative container. This code is described in the "Initializing the Applicative Container at Runtime" article [2] related to this use case.

[Top]

How to Launch the CAAPstINFNavigate 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 CATINavigateObject and CATINavigateProvider implementations are executed in order for the specs tree to be correctly initialized and to become navigatable. 

[Top]

Where to Find the CAAPstINFNavigate Code

This use case describes the implementation class of the CATINavigateProvider interface, called CAAEPstINFNavigProviderRoot, which is found in the CAAEPstINFNavigProviderRoot.cpp source file and CAAEPstINFNavigProviderRoot.h header file. It also describes the implementation class of the CATINavigateObject interface, called CAAEPstINFNavigateObjectRoot, which is found in the CAAEPstINFNavigateObjectRoot.cpp source file and CAAEPstINFNavigateObjectRoot.h header file. Both implementations are found in 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 two logical steps to CAAPstINFNavigate:

  1. Coding a Navigation Provider Implementation of CATINavigateProvider
  2. Implementing CATINavigateObject on a New Feature Root

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

[Top]

Coding a Navigation Provider Implementation of CATINavigateProvider

The purpose of this navigation provider implementation is to return the list of "CAAPstINFRoot" features found in the "CAAPstINFCont" applicative container if called by the Product root in order to structure these features under the Product root in the specs tree. The navigation provider is a simple implementation (in other words, it is not an extension of an existing component) that implements the CATINavigateProvider interface. It contains only one method, GetChildren, which is described in detail below.

1. Verify that the caller object is the Product root.

HRESULT CAAPstINFNavigProviderRoot::GetChildren(CATBaseUnknown *pObj, CATLISTP(CATBaseUnknown) **pListChildren) 
{
    cout << "***** CAAPstINFNavigProviderRoot::GetChildren" << endl << flush;

    // Retrieve a CATIProduct handle on the caller object
    CATIProduct *piProductOnObj = NULL;
    HRESULT rc = pObj -> QueryInterface (IID_CATIProduct, 
		                                 (void**) &piProductOnObj);
    if (SUCCEEDED(rc))
    {
 	// Retrieve the father of the product: if it has none, this must be the root.
	CATIProduct *piFatherProd = piProductOnObj -> GetFatherProduct();
        piProductOnObj -> Release();
	piProductOnObj = NULL;
        if (piFatherProd != NULL) 
	{
            cout << "The caller is not the aggregating root product." << endl << flush;
	    return S_OK;
	}
	else cout << "The caller is the aggregating root product: continue" << endl;     
...

This provider is active only if the caller is the Product document's root object. In order to verify that this is the case, it is first necessary to retrieve at CATIProduct pointer on the caller object. Then, using the GetFatherProduct, we can determine if the caller object is the Product root by checking if it has a father. If it does not, it is itself the Product root.

[Top]

2. Retrieve the applicative container.

...
	// Retrieve a pointer to the applicative container.
	CATILinkableObject *piLinkableOnObj = NULL;
	rc = pObj -> QueryInterface (IID_CATILinkableObject,
     	                             (void**) &piLinkableOnObj);
	if (!SUCCEEDED(rc)) return E_FAIL;
	CATDocument* pDoc = piLinkableOnObj->GetDocument();
	piLinkableOnObj -> Release();
	piLinkableOnObj = NULL;
		
        CATUnicodeString appliContIdentifier("PstINFContainer");
        CATBaseUnknown *pApplicativeContainer = NULL;

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

The first step in retrieving the root features that must be attached to the Product root is to retrieve the applicative container. This is done using the CATGetApplicativeContainer of the current document, whose CATDocument pointer is retrieved through the GetDocument method of CATILinkableObject.

[Top]

3. Retrieve the "CAAPstINFRoot" features from the applicative container.

...
	// Retrieve a pointer to CATIClientContainer in order to list the members
	// of the applicative container.
        CATIClientContainer *piClientOnAppliCont = NULL;
        rc = pApplicativeContainer -> QueryInterface(IID_CATIClientContainer,
                                                     (void**) &piClientOnAppliCont);

        pApplicativeContainer -> Release();
        pApplicativeContainer = NULL;

        if (NULL == piClientOnAppliCont)
	{ 
           cout << "ERROR in retrieving container pointer" << endl << flush;
           return E_FAIL;
	}
	else cout << "CATIClientContainer pointer retrieved OK" << endl << flush;
	
	// Retrieve the list of features in the applicative container
	CATUnicodeString clientId("CAAPstINFClientId"); 
	CATListPtrCATBaseUnknown *pMemberList = NULL;
        rc = piClientOnAppliCont -> ListMembers(IID_CATISpecObject,
                                                clientId,  
                                                &pMemberList);
        piClientOnAppliCont -> Release();
        piClientOnAppliCont = NULL;

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

	cout << "Number of members in applicative container: " << pMemberList->Size() << endl;
      
	CATUnicodeString rootType("");
	CATISpecObject *piSpecMember = NULL;
	for(int i=1;i<=pMemberList->Size();i++)
	{
	   piSpecMember = (CATISpecObject *) (*pMemberList)[i];
	   rootType = piSpecMember -> GetType();
	   if (rootType == "CAAPstINFRoot")
	   {
	      (*pListChildren)->Append((*pMemberList)[i]);
           }
           (*pMemberList)[i] -> Release();
           (*pMemberList)[i] = NULL;
           piSpecMember = NULL;
        }
        delete pMemberList;
        pMemberList = NULL;
    }
    return S_OK;
}

In order to retrieve a list of the features contained in the applicative container, we need to get a CATIClientContainer pointer on it and execute the ListMembers method. Then, we can search through the returned list of features and using the GetType method of CATISpecObject, we can append the features of type "CAAPstINFRoot" to the list to be returned to the Product navigation implementation.

[Top]

Implementing CATINavigateObject on a New Feature Root

The CATINavigateObject interface is implemented on the feature root of type "CAAPstINFRoot". This interface has two methods:

  1. GetIdentificators - this method returns the display name of the feature root object.
  2. GetChildren - this method returns the list of the children aggregated by the feature root object. 

1. Implementing the GetIdentificators method.

...
CATListValCATUnicodeString * CAAEPstINFNavigateObjectRoot::GetIdentificators()
{
  cout << "***** CAAEPstINFNavigateObjectRoot: CAAEPstINFNavigateObjectRoot::GetIdentificators" << endl;

  CATListOfCATUnicodeString *pIdent = new CATListOfCATUnicodeString;

  CATISpecObject *piSpecObjectOnRoot = NULL;
  HRESULT rc = this -> QueryInterface(IID_CATISpecObject,
        			                  (void**)&piSpecObjectOnRoot);
  if (SUCCEEDED(rc))
  {
      // Retrieve the root's name
      CATUnicodeString rootId = piSpecObjectOnRoot -> GetDisplayName();
      piSpecObjectOnRoot -> Release();
      piSpecObjectOnRoot = NULL;

      // String added to the list 
      pIdent -> Append(rootId);
  }

  return pIdent;
}
...

This method returns the display name of the "CAAPstINFRoot" feature root object. To do this, it first retrieves a CATISpecObject pointer on the feature root ("this") and then executes the GetDisplayName method in order to retrieve the display name which it appends to the returned list.

[Top]

2. Implementing the GetChildren method.

...
CATListValCATBaseUnknown_var * CAAEPstINFNavigateObjectRoot::GetChildren()
{
  cout << "***** CAAEPstINFNavigateObjectRoot::GetChildren" << endl;

  CATListValCATBaseUnknown_var *pList = NULL ;
    
  CATISpecAttrAccess *piAttrAccessOnRoot = NULL;
  HRESULT rc = this -> QueryInterface(IID_CATISpecAttrAccess,
	                              (void**) &piAttrAccessOnRoot);
  if (FAILED(rc)) return pList;
  
  CATISpecAttrKey *piListComponentKey = NULL;
  piListComponentKey = piAttrAccessOnRoot -> GetAttrKey ("ListOfComponents");
  if (!piListComponentKey) return pList;
  
  pList = new CATListValCATBaseUnknown_var();

  CATISpecObject *piComponent = NULL;
  piAttrAccessOnRoot -> Beginning(piListComponentKey);
  while (piAttrAccessOnRoot -> Next(piListComponentKey))	
  {
     piComponent = piAttrAccessOnRoot -> GetSpecObject(piListComponentKey);	            
     if (NULL == piComponent)
     {
        cout << "Error in in retrieving component" << endl;
	piAttrAccessOnRoot -> Release();
	piAttrAccessOnRoot = NULL;
	piListComponentKey -> Release();
	piListComponentKey = NULL;
        return pList;  
     }
     else cout << "Component retrieved OK" << endl; 
     pList -> Append(piComponent);
     piComponent = NULL;
  }

  piAttrAccessOnRoot -> Release();
  piAttrAccessOnRoot = NULL;
  piListComponentKey -> Release();
  piListComponentKey = NULL;

  return pList;
}
...

This method returns a list of the features aggregated by the "CAAPstINFRoot" feature root. To do this, it must first retrieve a CATISpecAttrAccess pointer on the current object (feature root itself). Then, using the GetAttrKey method, it retrieves the attribute key pointing to the list of aggregated features. Using the Beginning and Next methods of CATISpecAttrAccess, it scans through this list and retrieves every aggregated features using the GetSpecObject method and appends the aggregated feature to the list to be returned to the navigation caller.

[Top]


In Short

The CAAPstINFNavigate use case has shown you how new features created "from scratch" in an applicative container can be taken into account by the navigation process in order to integrate them in the product structure specs tree of a Product document. You have seen how to code a provider implementation corresponding to CATINavigateProvider and how to implement the CATINavigateObject interface for a new feature root object.

[Top]


References

[1] The Object Navigator
[2] Initializing the Applicative Container at Runtime
[Top]

History

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

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