PPR Hub

Product Modeler

Creating New Features "From Scratch" in a Product Document

Instantiating new features in applicative containers

Use Case
CAAPstIntegrateNewFeatures > CAAPstINFBuildCatalog > CAAPstINFCreateDocument > CAAPstINFInitCont > CAAPstINFNavigate > CAAPstINFVisu > CAAPstINFGraphicalProperties  > CAAPstINFEdit > CAAPstINFCCP > CAAPstINFDelete > CAAPstINFUpdate

Abstract

This article discusses the CAAPstINFCreateDocument use case. This use case explains how to create a new applicative container in a Product document and how to instantiate new features in it. 


What You Will Learn With This Use Case

This use case is intended to illustrate how to instantiate new features in an applicative container of a Product document.

You should already be familiar with the CAAPstIntegrateNewFeatures use case article [1] in order to more easily understand the context of this 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].  Finally, it may be useful for you to look over the "Product Structure Model" technical article [3] as well.

[Top]

The CAAPstINFCreateDocument Use Case

The CAAPstINFCreateDocument is a use case that is part of the CAAPstIntegrateNewFeatures use case defined in the CAAProductStructure.edu framework that illustrates the integration of ObjectSpecsModeler framework capabilities in the scope of a Product document.

[Top]

What Does the CAAPstINFCreateDocument Use Case Do

This use case is made up of a batch program that creates a new Product document, a new applicative container within the Product document and a number of new features within the applicative container. The StartUps of these features were created by the CAAPstINFBuildCatalog use case [4]. Each new feature type implements its own interface whose methods manage the valuation and retrieval of the feature's attributes. These implementations will be looked at in detail in this use case as well.

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. Then, a "CAAPstINFLine" feature is also instantiated, whose attribute values reference the first two "CAAPstINFPoint" features. Finally, a "CAAPstINFWire" feature is instantiated and its attribute points to a list containing references to 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 five "CAAPstINFPoint" features, the "CAAPstINFLine" feature and "CAAPstINFWire" feature are the elements in the list of components of the "CAAPstINFRoot1" feature. Also, notice that the "CAAPstINFLine1" feature points to "CAAPstINFPoint1" and "CAAPstINFPoint2" through a "SpecObject" link and that the "CAAPstINFWire1" feature points to "CAAPstINFPoint3", "CAAPstINFPoint4", and "CAAPstINFPoint5" through a "SpecObject" link as well.

You can see, in this case, that "CAAPstINFRoot1" aggregates the other features, meaning that if "CAAPstINFRoot1" were to be deleted, all of the aggregated features would be deleted as well. The "CAAPstINFLine" and the "CAAPstINFWire" objects, on the other hand, only reference the points that make up their definitions, meaning that if they were to be deleted, the points would continue to exist independently. Inversely, however, in the case of the line, for example, if ever one of the points were to be deleted, it would be necessary to delete the line as well, since its definition would no longer be valid. 

[Top]

How to Launch the CAAPstINFCreateDocument 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.

The particular part of the use case described in this article is launched by executing the following command:

    mkrun -c "CAAPstINFCreateDocument CatalogName DocumentStorageName"

where:

[Top]

Where to Find the CAAPstINFCreateDocument Code

The CAAPstINFCreateDocument use case is made of two modules, CAAPstINFCreateDocument.m and CAAPstINFModeler.m, both found in the CAAProductStructure.edu framework. CAAPstINFCreateDocument.m is a load module containing a single source program, CAAPstINFMainCreateDocument.cpp which creates the new document. This program also references the implementation classes of the CAAIPstINFRoot, CAAIPstINFPoint and CAAIPstINFLine interfaces called CAAEPstINFRoot, CAAEPstINFPoint, CAAEPstINFLine and CAAEPstINFWire whose source files are called CAAEPstINFRoot.cpp, CAAEPstINFPoint.cpp, CAAEPstINFLine.cpp and CAAEPstINFWire.cpp and whose header files are called CAAEPstINFRoot.h, CAAEPstINFPoint.h, CAAEPstINFLine.h and CAAEPstINFWire.h. These files can be found in the CAAPstINFModeler.m module.

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

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

[Top]

Step-by-Step

There are seven logical steps in CAAPstINFCreateDocument:

  1. Creating a New Product Document
  2. Creating a New Applicative Container
  3. Opening the StartUp Catalog
  4. Instantiating New Features in the Applicative Container
  5. Valuating the New Feature's Attributes
  6. Aggregating the New Features to the Root Feature Node
  7. Saving the New Product Document

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

[Top]

Creating a New Product Document

...
CATDocument *pDoc = NULL;
rc = CATDocumentServices::New("Product",
                              pDoc);
...   

A new Product document is created using the New static method of CATDocumentServices and specifying a "Product" type of document. This method returns a CATDocument pointer to the new document that has been created.

[Top]

Creating a New Applicative Container

...   
CATIdent idAppliCont = "CAAPstINFCont";
CATUnicodeString appliContIdentifier = "PstINFContainer";
CATBaseUnknown *pINFAppliCont = NULL;
rc = ::CATCreateApplicativeContainer(&pINFAppliCont,       // appli cont created
                                     pDoc,                 // document 
                                     idAppliCont,          // type of appli cont
                                     IID_CATIContainer,    // interface type of appli cont
                                     "CATFeatCont",        // supertype of appli cont 
                                     appliContIdentifier); // name of appli cont
...

// Get a CATIContainer handle on the applicative container

CATIContainer *piINFAppliCont = (CATIContainer*) pINFAppliCont;

#ifdef INTERACTIVE_APPLICATION
// Initialize the applicative container
// For a product structure, the call to CATInit is only mandatory
// in interactive
CATInit * pInit = NULL ;
rc = piINFAppliCont->QueryInterface(IID_CATInit, (void**) &pInit);
...
pInit->Init(FALSE);
..

// Declare the container to the Undo/redo mechanism
// only in interactive otherwise the method returns E_FAIL
// (as there is no undo/redo management in batch mode)

rc = ::CATOmbPerformAfterContainerCreation(piINFAppliCont);
...
#endif
...

A new applicative container is created using the CATCreateApplicativeContainer global function. This function takes the following arguments:

Once the applicative container has been created, the CATBaseUnknown pointer to it can be directly cast to the requested interface, in this case, CATIContainer, which will be used to open the StartUp catalog. 

For interactive applications, additional steps are required for the applicative container (see "Creating Features in an Applicative Container"):

[Top]

Opening the StartUp Catalog

...
CATUnicodeString stgName = argv[1];
CATICatalog *piCatalog = NULL;
CATUnicodeString clientId("CAAPstINFClientId");
rc = ::AccessCatalog (&stgName,
                      &clientId,
                      piINFAppliCont,
                      &piCatalog); 
...   

An existing StartUp catalog can be opened using the AccessCatalog global function. This function takes the following arguments:

[Top]

Instantiating New Features in the Applicative Container

Instantiating a new feature in an applicative container is a two-step process: the StartUp must first be retrieved from the catalog and then it can be instantiated in the applicative container.

1. Retrieving a StartUp from the catalog.

...
CATBaseUnknown *pRootSU = NULL;
CATUnicodeString rootSUType("CAAPstINFRoot");
rc = piCatalog -> RetrieveSU(&pRootSU, 
                             &rootSUType,
                             "CATISpecObject");
...
// Get a CATISpecObject handle on the CAAPstINFRoot StartUp
CATISpecObject *piRootSU = (CATISpecObject*) pRootSU;
...   

In order to retrieve a StartUp from the catalog, use the RetrieveSU method of CATICatalog. This method takes the following arguments:

Once the StartUp has been retrieved, the CATBaseUnknown pointer can be directly cast to a pointer of the requested interface, in this case, CATISpecObject.

This example shows retrieving the "CAAPstINFRoot" StartUp. The retrieval of the "CAAPstINFPoint","CAAPstINFLine" and "CAAPstINFWire"  StartUps is done in exactly the same way.

[Top]

2. Instantiating the StartUp in the applicative container.

...
CATISpecObject *piRootInst1 = piRootSU -> Instanciate(CATUnicodeString("CAAPstINFRoot1"),
                                                      pINFAppliCont);
...   

A new feature is created using the Instanciate method of CATISpecObject. In this case, the CATISpecObject points to the StartUp that was previously retrieved. This method takes the following arguments:

In this use case, two "CAAPstINFRoot" features are created, "CAAPstINFRoot1" and "CAAPstINFRoot2". The first root feature will serve to aggregate the five "CAAPstINFPoint" features, the "CAAPstINFLine" feature, and the "CAAPstINFWire" feature which are all created here. The second root feature is created in order to demonstrate certain CCP operations during the interactive session. All of these features are instantiated in the same way and in the same applicative container, using the Instanciate method, as seen above.

[Top]

Valuating the New Feature's Attributes

1. Accessing "CAAPstINFPoint" attributes.

When creating new features, it is always a good idea to define specific interfaces for them in order to manipulate their data values in a proper way. The CAAIPstINFPoint interface is, therefore, defined to retrieve and set the "CAAPstINFPoint" attribute values.

1.1 Implementing the CAAIPstINFPoint interface.

The CAAIPstINFPoint interface is composed of six methods, the first three to retrieve the values of the point coordinates: GetX, GetY, and GetZ; the other three to set the values of the point coordinates: SetX, SetY and SetZ. The code example below is taken from the CAAEPstINFPoint implementation class found in the CAAEPstINFPoint.cpp source file of the CAAPstINFModeler.m module. Only the GetX and the SetX methods are shown, the others being practically identical to these.

HRESULT CAAEPstINFPoint::GetX(double *pX) 
{
    CATISpecAttrAccess *piSpecAttrAccessOnPoint = NULL;
    HRESULT rc = QueryInterface (IID_CATISpecAttrAccess,
	                        (void**) &piSpecAttrAccessOnPoint);
...

    CATISpecAttrKey *piXKey = piSpecAttrAccessOnPoint -> GetAttrKey ("X");
...
	
    *pX = piSpecAttrAccessOnPoint -> GetDouble(piXKey);

...
}

The GetX method returns a double-type pointer to the current "X" attribute value. To do this, first of all, it retrieves a CATISpecAttrAccess interface pointer on the current "CAAPstINFPoint" feature. Using this pointer, it executes the GetAttrKey method for the attribute called "X" in order to retrieve a CATISpecAttrKey pointer to the "X" attribute key. Then using this key as a parameter, it executes the GetDouble method of CATISpecAttrAccess in order to retrieve the value of the x coordinate of the point, which it then returns through a double-type pointer. 

HRESULT CAAEPstINFPoint::SetX(double iX)
{
    CATISpecAttrAccess *piSpecAttrAccessOnPoint = NULL;
    HRESULT rc = QueryInterface (IID_CATISpecAttrAccess,
	                         (void**) &piSpecAttrAccessOnPoint);
...

    CATISpecAttrKey *piXKey = piSpecAttrAccessOnPoint -> GetAttrKey ("X");
...
	
    piSpecAttrAccessOnPoint -> SetDouble( piXKey, iX );

...
}

The SetX method does exactly the same thing as the GetX method, except that it executes the SetDouble method of CATISpecAttrAccess, on the same attribute key as in GetX, in order to set a new value to the "X" attribute of the current "CAAPstINFPoint" feature. 

[Top]

1.2 Valuating "CAAPstINFPoint" attributes.

Valuating the "CAAPstINFPoint" features' attributes is done just after the instantiation of the features in the CAAPstINFMainCreateDocument.cpp file. This operation is simply performed by calling the "Set" methods defined in the CAAIPstINFPoint interface, whose implementation we just saw in the above section.

...
CAAIPstINFPoint *piPstINFPoint = NULL;
rc = piPointInst1 -> QueryInterface (IID_CAAIPstINFPoint,
                                     (void**) &piPstINFPoint);
...

rc = piPstINFPoint -> SetX (0.0);
...

rc = piPstINFPoint -> SetY (0.0);
...

rc = piPstINFPoint -> SetZ (0.0);

...

First of all, a CAAIPstINFPoint interface pointer is retrieved for the first instance of "CAAPstINFPoint". Then, the methods for valuating the point coordinates are called: SetX, SetY and SetZ. Exactly the same procedure is employed for the following instances of the "CAAPstINFPoint" feature.

[Top]

2. Accessing "CAAPstINFLine" attributes.

The CAAIPstINFLine interface is defined to retrieve and set the "CAAPstINFLine" attribute values.

2.1 Implementing the CAAIPstINFLine interface.

The CAAIPstINFLine interface is composed of two methods. The first, GetPoint, is used to retrieve the values of the first and second attributes pointing to the "CAAPstINFPoint" features that define the line. The second, SetPoint, is used to set these same values. The code example below is taken from the CAAEPstINFLine implementation class found in the CAAEPstINFLine.cpp source file of the CAAPstINFModeler.m module. 

HRESULT CAAEPstINFLine::GetPoint(int iNum, CATISpecObject **piPoint) 
{
    CATISpecAttrAccess *piSpecAttrAccessOnLine = NULL;
    HRESULT rc = QueryInterface (IID_CATISpecAttrAccess,
	                         (void**) &piSpecAttrAccessOnLine);
...
    CATUnicodeString keyName;
    keyName = (1 == iNum ? "Point1" : "Point2");

    CATISpecAttrKey *piPointKey = piSpecAttrAccessOnLine -> GetAttrKey (keyName);
...
	
    *piPoint = piSpecAttrAccessOnLine -> GetSpecObject(piPointKey);
	
...
}

The GetPoint method returns a CATISpecObject pointer to one of the "CAAPstINFPoint" features used to define the line, depending on whether the first or the second point was requested in the iNum input parameter. To do this, first of all, it retrieves a CATISpecAttrAccess interface pointer on the current "CAAPstINFLine" feature. Using this pointer, it executes the GetAttrKey method for the attribute called either "Point1" or "Point2" in order to retrieve a CATISpecAttrKey pointer to the attribute key. Then using this key as a parameter, it executes the GetSpecObject method of CATISpecAttrAccess in order to retrieve a CATISpecObject pointer to the "CAAPstINFPoint" feature defining the line and returns this value as an output parameter. 

HRESULT CAAEPstINFLine::SetPoint(int iNum, CATISpecObject *piPoint)
{
    CATISpecAttrAccess *piSpecAttrAccessOnLine = NULL;
    HRESULT rc = QueryInterface (IID_CATISpecAttrAccess,
	                         (void**) &piSpecAttrAccessOnLine);
...
    CATUnicodeString keyName;
    keyName = (1 == iNum ? "Point1" : "Point2");

    CATISpecAttrKey *piPointKey = piSpecAttrAccessOnLine -> GetAttrKey (keyName);
...		
    piSpecAttrAccessOnLine -> SetSpecObject(piPointKey, piPoint);
	
...
}

The SetPoint method does exactly the same thing as the GetPoint method, except that it executes the SetSpecObject method of CATISpecAttrAccess on the same attribute key, in order to set a new "CAAPstINFPoint" feature value to the attribute of the current "CAAPstINFLine" feature. 

[Top]

2.2 Valuating "CAAPstINFLine" attributes.

Now, once the "CAAPstINFPoint1" feature has been created, we want to valuate its attributes. Here is how this is done:

Valuating the "CAAPstINFLine" feature's attributes is done just after the instantiation of the feature in the CAAPstINFMainCreateDocument.cpp file. This operation is simply performed by calling the SetPoint method defined in the CAAIPstINFLine interface, whose implementation we just saw in the above section.

...
CAAIPstINFLine *piPstINFLine = NULL;
rc = piLineInst1 -> QueryInterface (IID_CAAIPstINFLine,
                                    (void**) &piPstINFLine);
...

rc = piPstINFLine -> SetPoint (1, piPointInst1);
...

rc = piPstINFLine -> SetPoint (2, piPointInst2);

...

First of all, a CAAIPstINFLine interface pointer is retrieved for the "CAAPstINFLine1" feature. Then, the SetPoint method is called twice with the two instances of the "CAAPstINFPoint" feature that define the line. 

[Top]

3. Accessing "CAAPstINFWire" attributes.

The CAAIPstINFWire interface is defined to retrieve and set the "CAAPstINFWire" attribute values.

3.1 Implementing the CAAIPstINFWire interface.

The CAAIPstINFWire interface is composed of two methods. The first, GetPoints, is used to retrieve the list of "CAAPstINFPoint" features that define the line. The second, SetPoints, is used to valuate this same list. The code example below is taken from the CAAEPstINFWire implementation class found in the CAAEPstINFWire.cpp source file of the CAAPstINFModeler.m module. 

HRESULT CAAEPstINFWire::GetPoints(CATListPtrCATISpecObject **pPointList) 
{
    CATISpecAttrAccess *piSpecAttrAccessOnWire = NULL;
    HRESULT rc = QueryInterface (IID_CATISpecAttrAccess,
		               (void**) &piSpecAttrAccessOnWire);
    
...
    // Retrieve the key to the feature's "Points" attribute
    CATUnicodeString keyName = "Points";
    CATISpecAttrKey *piPointKey = piSpecAttrAccessOnWire -> GetAttrKey (keyName);
...	
    // Scan through the list of features referenced by the attribute,
    // retrieve each feature and append it to the list to be returned to the caller.
    *pPointList = new CATListPtrCATISpecObject();

    CATISpecObject *piPoint = NULL;
    piSpecAttrAccessOnWire -> Beginning(piPointKey);

    while (piSpecAttrAccessOnWire -> Next(piPointKey))	{
        piPoint = piSpecAttrAccessOnWire -> GetSpecObject(piPointKey);	
        (*pPointList) -> Append(piPoint);
	piPoint = NULL;
    }

...
}

The GetPoint method returns a CATListPtrCATISpecObject pointer to the list containing the "CAAPstINFPoint" features used to define the wire. To do this, first of all, it retrieves a CATISpecAttrAccess interface pointer on the current "CAAPstINFWire" feature. Using this pointer, it executes the GetAttrKey method for the attribute called "Points" in order to retrieve a CATISpecAttrKey pointer to the attribute key. Then using this key as a parameter, it loops through the list of features using the Beginning and Next methods of CATISpecAttrAccess and executes the GetSpecObject method in order to retrieve each CATISpecObject pointer to the "CAAPstINFPoint" feature defining the line, which it appends to the list to be returned as an output parameter. 

HRESULT CAAEPstINFWire::SetPoints(CATListPtrCATISpecObject *pPointList)
{
    CATISpecAttrAccess *piSpecAttrAccessOnWire = NULL;
    HRESULT rc = QueryInterface (IID_CATISpecAttrAccess,
		               (void**) &piSpecAttrAccessOnWire);
...
    // Retrieve the key to the feature's "Points" attribute
    CATUnicodeString keyName = "Points";
    CATISpecAttrKey *piPointKey = piSpecAttrAccessOnWire -> GetAttrKey (keyName);
...
    // If the list of attributes is already valuated, initialize it to NULL in order
    // to entirely re-create it.
    int nb = piSpecAttrAccessOnWire -> GetListSize(piPointKey);
    if ( 0 != nb ) {
       piSpecAttrAccessOnWire -> UnsetAttributeValue(piPointKey);
    }   

    // Scan through the list of features passed in the argument,
    // retrieve each feature from the list and save it in the list of features
    // referenced by the "Points" attribute.
    CATISpecObject *piPoint = NULL;
    for (int i=1; i<=pPointList->Size(); i++) {
        piPoint = (*pPointList)[i] ;
        piSpecAttrAccessOnWire -> SetSpecObject(piPointKey, piPoint, 0);
        piPoint = NULL;
    }
...
}

The SetPoints method does exactly the same thing as the GetPoints method, except that it executes the SetSpecObject method of CATISpecAttrAccess on the same attribute key, in order to add the given number of "CAAPstINFPoint" features to the list attribute of the current "CAAPstINFWire" feature. Note that the list is entirely re-created every time the method is called. This is done by using the UnsetAttributeValue method of CATISpecAttrAccess in order to re-initialize the list of SpecObjects.

[Top]

3.2 Valuating "CAAPstINFWire" attributes.

Valuating the "CAAPstINFWire" feature's attributes is done just after the instantiation of the feature in the CAAPstINFMainCreateDocument.cpp file. This operation is simply performed by calling the SetPoints method defined in the CAAIPstINFWire interface, whose implementation we just saw in the above section.

...
CAAIPstINFWire *piPstINFWire = NULL;
rc = piWireInst1 -> QueryInterface (IID_CAAIPstINFWire,
                                    (void**) &piPstINFWire);
...

CATListPtrCATISpecObject pointList;
pointList.Append (piPointInst3);
pointList.Append (piPointInst4);
pointList.Append (piPointInst5);
cout << "Size of pointlist = " << pointList.Size() << endl;
rc = piPstINFWire -> SetPoints (&pointList);
	
...

First of all, a CAAIPstINFWire interface pointer is retrieved for the "CAAPstINFWire1" feature. Then, the SetPoints method is called with the list of  the "CAAPstINFPoint" features that define the wire. 

[Top]

Aggregating the New Features to the Root Feature Node

1. Implementing the CAAIPstINFRoot interface.

The CAAIPstINFRoot interface is composed of two methods. The first, AddChild, is used to aggregate a new feature to the "CAAPstINFRoot" feature representing a root node in the product structure. The second, GetChildren, retrieves the list of features aggregated by the "CAAPstINFRoot" feature. The code example below is taken from the CAAEPstINFRoot implementation class found in the CAAEPstINFRoot.cpp source file of the CAAPstINFModeler.m module. 

1.1 AddChild.

This method has three distinct parts. The first part deals with the data modifications that are necessary whenever a new feature is created and  aggregated to the "CAAPstINFRoot" node. The second part deals with the update of the specs tree to display the new feature. And finally, the third part deals with the necessary notification of the creation that needs to be sent so that the new feature can be visualized.

1.1.1 AddChild: Data modification.

...
HRESULT CAAEPstINFRoot::AddChild (CATISpecObject *piFeature)
{
    HRESULT rc;

    CATISpecAttrAccess *piAttrAccess = NULL;
    rc = this -> QueryInterface(IID_CATISpecAttrAccess,
	                       (void**) &piAttrAccess);
...

    // Retrieve the attribute key in order to access the list of aggregated features
    CATISpecAttrKey *piListKey = piAttrAccess -> GetAttrKey("ListOfComponents");
...

    // Add the new feature to the end of the list
    piAttrAccess -> SetSpecObject (piListKey,
	                          piFeature);
...  

Using a CATISpecAttrAccess pointer retrieved on the current root feature, we execute the GetAttrKey method in order to retrieve a CATISpecKey pointer to the "ListOfComponents" attribute defined for the "CAAPstINFRoot" feature. Then, using this key, we execute the SetSpecObject method of CATISpecAttrAccess, specifying the new feature that is to be aggregated (or, in other words, added to the list as a component feature).

[Top]

1.1.2 AddChild: Refresh of the specs tree.

...
    // Refresh the navigation tree
    CATIRedrawEvent *piRedrawOnRoot = NULL;
    rc = QueryInterface(IID_CATIRedrawEvent,
                        (void**) &piRedrawOnRoot);
...

    piRedrawOnRoot -> Redraw();
...

Once the data modifications are complete, in order to update the specs tree, we retrieve a CATIRedrawEvent pointer on the current "CAAPstINFRoot" feature and execute the Redraw method.

[Top]

1.1.3 AddChild: Refresh of the visualization.

...
    // Force the visualization of the new feature by sending an event on the Product root
  
    // Retrieve a pointer to the current document
    CATILinkableObject *piLinkableOnRoot = NULL;
    rc = QueryInterface(IID_CATILinkableObject, 
                        (void**) &piLinkableOnRoot);
...

    CATDocument *pDoc = piLinkableOnRoot -> GetDocument();
...
  
    // Retrieve the document's product root
    CATIDocRoots* piDocRootsOnDoc = NULL;
    rc = pDoc -> QueryInterface(IID_CATIDocRoots,
                                (void**) &piDocRootsOnDoc);
...
  
    // The document's root product is the first element of the list returned by GiveDocRoots
    CATListValCATBaseUnknown_var *pProductList = piDocRootsOnDoc -> GiveDocRoots();
    CATBaseUnknown *pRootProduct = NULL;
    CATIProduct *piRootProduct = NULL;
...
    if (pProductList->Size()) {  
        pRootProduct = (*pProductList)[1];
...
        rc = pRootProduct -> QueryInterface(IID_CATIProduct,
                                            (void**) &piRootProduct);
...
    }
...

    // Retrieve a CATIModelEvents pointer on the product root and connect the feature
    CATIModelEvents *piModelEventsOnProductRoot = NULL;
    rc = piRootProduct -> QueryInterface(IID_CATIModelEvents,
                                         (void**) &piModelEventsOnProductRoot);
...

    piModelEventsOnProductRoot -> ConnectTo(piFeature);
  
    // Send a notification of the creation to the view
    CATCreate ntfCreate(piFeature, piModelEventsOnProductRoot);
    piModelEventsOnProductRoot -> Dispatch(ntfCreate);
  
    piModelEventsOnProductRoot -> Release();
    piModelEventsOnProductRoot = NULL;

...
}

The visualization process must be notified of the creation through an event notification that must be sent at the Product level. This is because the real visualization root of our features is the Product root. The "CAAPstINFRoot" nodes serve only to better structure our features; they do not enter into the visualization process. 

Therefore, the first step in sending a creation notification is to retrieve the Product root. To do this, it is necessary to retrieve a CATDocument pointer to the current document using the GetDocument method of CATILinkableObject on the current aggregating "CAAPstINFRoot" feature. Then, from the CATDocument pointer, we can retrieve a CATIDocRoots interface pointer and execute the GiveDocRoots method. This method returns a list of the documents' products, the first of which is the Product root. Now, on the Product root, we can retrieve a CATIModelEvents interface pointer and execute the ConnectTo method for the new feature that has been created. Then, a new CATCreate object is instantiated for the new feature on the Product root and this CATCreate object is then dispatched through the Dispatch method of CATIModelEvents.

[Top]

1.2 GetChildren.

HRESULT CAAEPstINFRoot::GetChildren (CATListValCATBaseUnknown_var **pList)
{
    CATISpecAttrAccess *piAttrAccessOnRoot = NULL;
    HRESULT rc = this -> QueryInterface(IID_CATISpecAttrAccess,
                                        (void**) &piAttrAccessOnRoot);
...
  
    CATISpecAttrKey *piListComponentKey = NULL;
    piListComponentKey = piAttrAccessOnRoot -> GetAttrKey ("ListOfComponents");
...
    CATISpecObject *piComponent = NULL;
    piAttrAccessOnRoot -> Beginning(piListComponentKey);
    while (piAttrAccessOnRoot -> Next(piListComponentKey)) {
        piComponent = piAttrAccessOnRoot -> GetSpecObject(piListComponentKey);	            
...
        (*pList) -> Append(piComponent);
...
    }

...
}

This method retrieves a list of the features aggregated by this "CAAPstINFRoot" node. To do this, it first retrieves a CATISpecAttrAccess interface pointer on the current "CAAPstINFRoot". Then, using the GetAttrKey method, it retrieves the CATISpecAttrKey corresponding to the "ListOfComponents" attribute. Using this key, it then loops through the list of components using the Beginning and Next methods of CATISpecAttrAccess and executes the GetSpecObject on each list element in order to retrieve the CATISpecObject pointer corresponding to the aggregated feature. It appends this object to the list that is to be returned using the Append method of the CATListVarCATBaseUnknown collection.

2. Valuating "CAAPstINFRoot" attributes.

Valuating the "CAAPstINFRoot" feature's attributes is done in the CAAPstINFMainCreateDocument.cpp file, after the instantiation of all of the features that are to be aggregated to it. This operation is simply performed by calling the AddChild method defined in the CAAIPstINFRoot interface, whose implementation we just saw in the above section.

...
CAAIPstINFRoot *piPstINFRoot = NULL;
rc = piRootInst1 -> QueryInterface (IID_CAAIPstINFRoot,
                                    (void**) &piPstINFRoot);
...
   
rc = piPstINFRoot -> AddChild(piPointInst1);
...
   
rc = piPstINFRoot -> AddChild(piPointInst2);
...

rc = piPstINFRoot -> AddChild(piPointInst3);
...

rc = piPstINFRoot -> AddChild(piPointInst4);
...

rc = piPstINFRoot -> AddChild(piPointInst5);
...
 
rc = piPstINFRoot -> AddChild(piLineInst1);
...
rc = piPstINFRoot -> AddChild(piWireInst1);
...

Use the CAAIPstINFRoot::AddChild method to aggregate a new feature to a "CAAPstINFRoot". This method performs the necessary data modifications to aggregate the new feature to the "CAAPstINFRoot", performs a refresh of the navigation tree in order for the new feature to be taken into account and finally, sends a creation notification event to the product root in order for the new feature to be visualized.

[Top]

Saving the New Product Document

...
rc = CATDocumentServices::SaveAs (*pDoc, argv[2]);
...

Use the SaveAs static method of CATDocumentServices to save the new document. The storage pathname of the new document is passed as an argument to the use case.

[Top]


In Short

The CAAPstINFCreateDocument use case has shown you how to create new features "from scratch" in an applicative container of a Product document. 

[Top]


References

[1] Integrating New Features in a Product Document
[2] Feature Modeler Overview
[3] The Product Structure Model
[4] Creating a New StartUp Catalog
[5] Creating Features in an Applicative Container
[Top]

History

Version: 1.2 [Aug 2004] Document revised
Version: 2 [May 2003] Add reference to "Creating Features in an Applicative Container"
Version: 1 [May 2002] Document created
[Top]

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