3D PLM Enterprise Architecture

User Interface - Frame

Creating a Most Recent Used Command Header

How to create a command header class whose the representation is a dynamic list of items in a menu
Use Case

Abstract

This use case explains how to create a specialized command header. This command header has a customized graphic representation. In place of a push item into a menu, the graphic representation is a dynamic list of push items. 


What You Will Learn With This Use Case

This use case illustrates the creation of a customized command header. In a menu, its graphic representation is a dynamic list of push items in place of a push item, the default representation. You will learn how to create a command header such as those which displays the most recent used document in the File menu. There are three steps:

It is a component which must derive from the CATAfrDialogCommandHeader class. 

It is a component which must derive from the CATAfrCommandHeaderRep class and which instantiates one or more CATDlgPushItem class instances. 

The data is a list of strings. This list is independent of an instance of a V5 document. It means that whatever the current document, or even if any document is opened, the list of strings is the same. 

You can also read the CAAAfrComboColorHeader use case [1] which presents another customized command header. In this case, the graphic representation is a combo in a toolbar. Contrarily to the current use case, the data (the current color) is dependent of the document. 

To take full advantage of this article, you can first read "The Command Headers" technical article [2], and precisely the "Creating Customized Command Headers" section.  

[Top]

The CAAAfrMRUHeader Use Case

CAAAfrMRUHeader is a use case of the CAAApplicationFrame.edu framework that illustrates ApplicationFrame framework capabilities

[Top]

What Does CAAAfrMRUHeader Do

CAAAfrMRUHeader creates a command header whose the graphic representation is a list of push items in the File menu. Before to explain the construction of such a command header, see the following scenario which shows the end user view. 

  1. Launch CNEXT
  2. Select File menu 
  3. Above Exit, you have a separator, and just above it the "standard" most recent used documents.
  4. Launch Add Item in MRU in the General toolbar
  5. This toolbar comes from an Add-in of the General workshop. Refer to the referenced use case to display this toolbar [3].

    The Add Item in MRU command is a CATDlgDialog command. 

  6. The following Dialog box appears
  7. In the editor, enter Item 1, then click OK
  8. Select File menu 
  9. Now, after Exit, you have a new push item, Item 1
  10. Launch Add Item in MRU () in the General toolbar
  11. In the editor, enter Item 2, then click OK
  12. Select File menu 
  13. Now, after Exit, you have two push items:
    • In first position Item 2: the last created (used) item, 
    • In second position Item 1: the oldest created (used) item
  14. Select Item 1 in File menu
  15. The Selected item dialog box appears. It displays the selected item (Item 1). Close the dialog box.
  16. Select File menu 
  17. Now, after Exit, you always have two push items, but observe the new order:
    • In first position Item 1: the last used item, 
    • In second position Item 2: the oldest used item
  18. On the File menu click New 
  19. New Dialog box click any kind document type and click OK
  20. Select File menu, you have the same list of items.

In this scenario, you can see that there is a list of strings (or item). About this list :

This list (named MRU list) is kept by a component called CAAAfrMRUManager. It controls data (list of strings) which are displayed in the push items of a menu through the CAAIAfrMRUManagement interface. Since, the MRU list is unique, this component is unique during the session. 

Fig.1 Manager of the MRU List 

The MRU header is an instance of a class deriving from the CATAfrDialogCommandHeader class, like any command header whose the graphic representation is customized. The following UML diagram describes in detail the schema of classes:

Fig.2 MRU Header UML Diagram

CAAAfrMRUHeader is a component which must implement the CATIAfrCommandHeaderRep interface to provide the customized graphic representation. This interface contains three methods:

The MRU header is instantiated in an Add-in of the General workshop [3]. The last step of the Step by Step section explains this instantiation.

[Top]

How to Launch CAAAfrMRUHeader

To launch CAAAfrMRUHeader, you will need to set up the build time environment, then compile CAAAfrMRUHeader and CAAAfrGeneralWksAddin[3] along with their prerequisites, set up the run time environment, and then execute the use case [5].

But just before launching the execution, edit the CAAApplicationFrame.edu.dico interface dictionary file located in the dictionary directory of the CAAApplicationFrame.edu framework:

Windows InstallRootDirectory\CAAApplicationFrame.edu\CNext\code\dictionary\
UNIX InstallRootDirectory/CAAApplicationFrame.edu/CNext/code/dictionary/

In this file, remove the "#" character before the two following lines:

...
#CAAAfrGeneralWksAddin       CATIWorkbenchAddin          libCAAAfrGeneralWksAddin  
#CAAAfrGeneralWksAddin       CATIAfrGeneralWksAddin      libCAAAfrGeneralWksAddin
...

and then run mkCreateRuntimeView. 

[Top]

Where to Find the CAAAfrMRUHeader Code

The CAAAfrMRUHeader use case is made of several classes located in four modules of the CAAApplicationFrame.edu framework:

Windows InstallRootDirectory\CAAApplicationFrame.edu
Unix InstallRootDirectory/CAAApplicationFrame.edu

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

The CAAAfrCustCommandHdrModel.m module contains classes to define the CAAAfrMRUManager component and the notification sent by this component.

The notification sent when an element is added in the list, or when an element is selected (to become the first in the list)

Interface to add an element, select one, retrieve the list. 

The CAAAfrMRUManager component itself which implements the CAAIAfrMRUManagement interface.

The global function to retrieve the unique CAAAfrMRUManager component during the session.

The CAAAfrCustomizedCommandHeader.m module contains classes to define the MRU header:

The CAAfrGeoCommands.m module contains CATCommand classes 

It is a CATDlgDialog class (see image)  executed when the end user clicks the "Add Item in MRU" command in the General toolbar.

It is a CATDlgDialog class (see image) executed when the end user selects an item among the MRU list.

The CAAAfrGeneralWksAddin.m module contains an Add-in of the General workshop 

[Top]

Step-by-Step

There are four logical steps in CAAAfrMRUHeader:

  1. Creating the CAAAfrMRUManager Component
  2. Creating the Component Representing the MRU Command Header 
  3. Creating the Class Instantiating the Graphic Representation
  4. Instantiating the MRU Header Class

[Top]

Creating the CAAAfrMRUManager Component

The CAAAfrMRUManager component controls the MRU list to display in a menu. This list is managed through the CAAIAfrMRUManagement interface. The explanations about the creation of this interface are not given in this article, refer to the Creating Interfaces use case for more details [6].

... 
#define MRU_MAX_SIZE 5 

class  CAAAfrMRUManager : public CATBaseUnknown
{
   CATDeclareClass;

   public:
 
   CAAAfrMRUManager();
   virtual ~CAAAfrMRUManager(); 

   static HRESULT GetMRUManager(CAAAfrMRUManager ** oManager);

   virtual HRESULT AddElement(CATUnicodeString &iNewElement) ;
   virtual HRESULT GetElementList(CATListOfCATUnicodeString &ElementList) const  ;
   virtual HRESULT SelectElement(int iPosition) ;

 private:
   
   CAAAfrMRUManager(const CAAAfrMRUManager &iObjectToCopy);
   CAAAfrMRUManager & operator = (const CAAAfrMRUManager &iObjectToCopy);

 private:
   static CATIniCleanerSettingCtrl _Cleaner ;

   CATListOfCATUnicodeString       _NameList;
};

The source file of the CAAAfrMRUManager class is as follows:

... 
CATIniCleanerSettingCtrl CAAAfrMRUManager::_Cleaner ;

CATImplementClass(CAAAfrMRUManager, Implementation, CATBaseUnknown , CATNull);

#include <TIE_CAAIAfrMRUManagement.h>
TIE_CAAIAfrMRUManagement(CAAAfrMRUManager);


CAAAfrMRUManager::CAAAfrMRUManager() {}
CAAAfrMRUManager::~CAAAfrMRUManager(){}
...
... 
HRESULT CAAAfrMRUManager::GetMRUManager(CAAAfrMRUManager ** oManager)
{
 ...
      CATBaseUnknown * pManager = _Cleaner.GetController();
      if ( NULL == pManager )
      {
          CAAAfrMRUManager * Obj = NULL;
          Obj = new CAAAfrMRUManager();
          if ( NULL == Obj )
          {
             rc = E_OUTOFMEMORY ;
          }else
          {
            *oManager = Obj ; 
            _Cleaner.SetController(Obj);
          }
       }else  
       {
          *oManager = (CAAAfrMRUManager *) pManager ;
       }
...

The GetMRUManager method creates the only one instance of the CAAAfrMRUManager class or retrieves the existing one. _Cleaner is a static data member, a  CATIniCleanerSettingCtrl class instance. If the GetController method of the CATIniCleanerSettingCtrl class returns a null pointer, a CAAAfrMRUManager class instance is created, and kept by _Cleaner through the SetController method. Otherwise the GetMRUManager method returns the pointer kept by _Cleaner and retrieved thanks to the GetController method. 

Now, lets us see the three methods of the CAAIAfrMRUManagement interface. 

... 
HRESULT CAAAfrMRUManager::AddElement(CATUnicodeString &iNewElement) 
{
    if ( MRU_MAX_SIZE == _NameList.Size() )
    {
        // The list is full, the last element is removed
       _NameList.RemovePosition(MRU_MAX_SIZE);
    }
    // At the first position
    _NameList.InsertBefore(1,iNewElement);
    
    CATCallbackManager * pCBManager = ::GetDefaultCallbackManager(this) ;
    if ( NULL != pCBManager )
    {
         CAAAfrMRUManagerNotification * pNotification = new CAAAfrMRUManagerNotification();
         pCBManager->DispatchCallbacks(pNotification,this);
         pNotification->Release();
    }

    return S_OK ;
}
...

While there are less than MRU_MAX_SIZE elements in the list, represented by _NameList the data member, the AddElement method just adds the new element (iNewElement) at the first position (InsertBefore(1,...)). But when there are already MRU_MAX_SIZE elements in the list, before adding the new element at the first position, the last element of the list is removed. 

The second part of the AddElement method consists in to send a notification thanks to the callback manager [7]. So, all objects which will subscribe for this event, published by the MRU manager, will be informed and awaked. Refer to the callback use case [8], for explanations about the creation of a notification such as the CAAAfrMRUManagerNotification class, and how to send a notification using the default callback manager. 

... 
HRESULT CAAAfrMRUManager::GetElementList(CATListOfCATUnicodeString & oElementList) const  
{
    for ( int i = 1 ; i <= _NameList.Size() ; i++)
    {
       oElementList.Append(_NameList[i]);
    }

    return S_OK ;
}
...

The GetElementList method returns the contents of the list of item kept by _NameList the data member. This method will be called by the MRU header to build its graphic representation. See the Creating the Class Instantiating the Graphic Representation step.

... 
HRESULT CAAAfrMRUManager::SelectElement(int iPosition) 
{
    HRESULT rc = E_FAIL ;

    if ( (iPosition >= 1) && (iPosition <= MRU_MAX_SIZE) )
    {
        CATUnicodeString Sel = _NameList[iPosition] ;

       _NameList.RemovePosition(iPosition);

       _NameList.InsertBefore(1,Sel);

       CATCallbackManager * pCBManager = ::GetDefaultCallbackManager(this) ;
       ...
          CAAAfrMRUManagerNotification * pNotification = new CAAAfrMRUManagerNotification();
          
          pCBManager->DispatchCallbacks(pNotification,this);
          
          pNotification->Release();
          pNotification = NULL ;
...

The SelectElement method consists in to set at the first position the iPosition element of the list. So the element is first removed from the list (RemovePosition), and then reinserted at the first position (InsertBefore)

[Top]

Creating the Component Representing the MRU Command Header

The MRU header is a component which must Object Modeler and C++ derive from CATAfrDialogCommandHeader and must implement the CATIAfrCommandHeaderRep interface (Fig.2).

Component Creation

Here the CAAAfrMRUHeader header file:

//ApplicationFrame framework
#include "CATAfrDialogCommandHeader.h"

class ExportedByCAAAfrCustomizedCommandHeader CAAAfrMRUHeader: public CATAfrDialogCommandHeader
{
  CATDeclareClass ;

  public:
    CAAAfrMRUHeader(const CATString & iHeaderName);

    virtual ~CAAAfrMRUHeader();
    CATCommandHeader * Clone() ;
      
  private:
    CAAAfrMRUHeader(CATCommandHeader *iHeaderToCopy);
    CAAAfrMRUHeader(const CAAAfrMRUHeader & iObjectToCopy);
    CAAAfrMRUHeader& operator = (const CAAAfrMRUHeader & iObjectToCopy);

};

CAAAfrMRUHeader derives from CATAfrDialogCommandHeader. It is mandatory for a command header whose the graphic representation is customized. The CATDeclareClass macro declares that it belongs to a CAA component. The CATDeclareHeaderResources macro inserts the methods to manage the command header resources. 

About the mandatory public methods:

About the mandatory private methods:

Here the CAAAfrMRUHeader header file:

#include "CAAAfrMRUHeader.h"

CATImplementClass(CAAAfrMRUHeader, 
                  Implementation,
                  CATAfrDialogCommandHeader, 
                  CATNull);    

CAAAfrMRUHeader::CAAAfrMRUHeader(const CATString & iHeaderName) : 
    CATAfrDialogCommandHeader(iHeaderName){}

CAAAfrMRUHeader::CAAAfrMRUHeader(){}

CATCommandHeader * CAAAfrMRUHeader::Clone ()                                  
{ 
    return new CAAAfrMRUHeader(this); 
}   

CAAAfrMRUHeader::CAAAfrMRUHeader(CATCommandHeader * iHeaderToCopy):
                          CATAfrDialogCommandHeader(iHeaderToCopy)
{}	                  
Note: There is no CATDeclareHeaderResources macro in the header file, and neither CATImplementHeaderResources macro in the source file. There is no NLS resources for this header [10]. 

 

CATIAfrCommandHeaderRep implementation

This interface of the ApplicationFrame framework must be implemented by all command header whose the graphic representation is customized. On Fig.2, you see that the CAAEAfrCommandHeaderRepForMRU class is the implementation of this interface for the CAAAfrMRUHeader component. 

Here the CAAEAfrCommandHeaderRepForMRU header file

...
class CAAEAfrCommandHeaderRepForMRU : public CATBaseUnknown
{
  CATDeclareClass;
  
public:
  CAAEAfrCommandHeaderRepForMRU ();
  virtual ~CAAEAfrCommandHeaderRepForMRU();
  
  virtual HRESULT  CreateToolbarRep (const CATDialog * iParent,
                                            CATAfrCommandHeaderRep ** oHdrRep) ;
  virtual HRESULT  CreateMenuRep    (const CATDialog * iParent,
                                            CATAfrCommandHeaderRep ** oHdrRep) ;
  virtual HRESULT  CreateCtxMenuRep (const CATDialog * iParent,
                                            CATAfrCommandHeaderRep ** oHdrRep) ;
  
private:
  CAAEAfrCommandHeaderRepForMRU (const CAAEAfrCommandHeaderRepForMRU &iObjectToCopy);
  CAAEAfrCommandHeaderRepForMRU & operator = (const CAAEAfrCommandHeaderRepForMRU &iObjectToCopy);

};      

The CATDeclareClass macro declares that CAAEAfrCommandHeaderRepForMRU belongs to a component. CreateToolbarRep, CreateMenuRep, and CreateCtxMenuRep are methods of the CATIAfrCommandHeaderRep interface.

Here the CAAEAfrCommandHeaderRepForMRU source file

...
#include <TIE_CATIAfrCommandHeaderRep.h>
TIE_CATIAfrCommandHeaderRep(CAAEAfrCommandHeaderRepForMRU);

CATImplementClass(CAAEAfrCommandHeaderRepForMRU, 
                  DataExtension,
                  CATBaseUnknown, 
                  CAAAfrMRUHeader);
};
CAAEAfrCommandHeaderRepForMRU::
           CAAEAfrCommandHeaderRepForMRU():CATBaseUnknown(){}

CAAEAfrCommandHeaderRepForMRU::~CAAEAfrCommandHeaderRepForMRU){}
...      

The CAAEAfrCommandHeaderRepForMRU class states that it implements the CATIAfrCommandHeaderRep interface thanks to the TIE_CATIAfrCommandHeaderRep macro. The CATImplementClass macro declares that the CAAEAfrCommandHeaderRepForMRU class is a data extension, thanks to the DataExtension keyword, that extends CAAAfrMRUHeader. The third argument must always be set as CATBaseUnknown or CATNull for any kind of extension.  The class constructor and the class destructor are empty.

...
HRESULT CAAEAfrCommandHeaderRepForMRU::CreateMenuRep
         (const CATDialog * iParent,CATAfrCommandHeaderRep ** oHdrRep)
{
   HRESULT rc = E_FAIL ;

   if ( oHdrRep != NULL )
   {
      CATString Name = "CAAAfrMRURepId"  ;
      CAAAfrMRURep * pMRURep = new CAAAfrMRURep(iParent,Name);

      *oHdrRep = (CATAfrCommandHeaderRep *) pMRURep ;
      rc = S_OK ;
   }

   return rc ;
}
...      

The CreateMenuRep method provides the class instantiating the graphic representation of the MRU header. This method is called each time the header command must be represented in a menu.

The CAAAfrMRURep class is a CATCommand class [Fig.3], which instantiates the graphic representation of the MRU header (CATDlgPushItem instances). It is detailed in the Creating the Class Instantiating the Graphic Representation section, just below.  

iParent is a CATDialog component. It will be the dialog parent of all CATDlgPushItem instances. Name is the command name of the CAAAfrMRURep class instance. You can set the same identifier for all CAAAfrMRURep class instances. 

You do not have to take care of the CAAAfrMRURep class instance destruction, the returned value, oHdrRep is kept by the frame application, and the deletion of this pointer is automatically done.  

...
HRESULT CAAEAfrCommandHeaderRepForMRU::
             CreateToolbarRep(const CATDialog * iParent,CATAfrCommandHeaderRep ** oHdrRep)
{
  return  E_FAIL ;
}

HRESULT CAAEAfrCommandHeaderRepForMRU::
          CreateCtxMenuRep (const CATDialog * iParent,CATAfrCommandHeaderRep ** oHdrRep)
{
  return E_FAIL;
}

The MRU header has no representation in the menu bar or in a contextual menu, so CreateToolbarRep and CreateCtxMenuRep return E_FAIL.

[Top]

Creating the Class Instantiating the Graphic Representation

This class is the CAAAfrMRURep class. Its main roles are:

Here the CAAAfrMRURep header file:

...
#define MRU_MAX_SIZE 5
class CAAAfrMRURep : public CATAfrCommandHeaderRep
{
public:
  CAAAfrMRURep (const CATDialog * iParent, CATString & iCommandName);
  virtual ~CAAAfrMRURep();

  HRESULT Build();

private:
  void SelectCB(CATCommand * iPublishingCommand, 
                CATNotification * iNotification, 
                CATCommandClientData iData);

  void ModifiedCB(CATCallback       iEvent, 
                  void            *       , 
                  CATNotification * iNotification, 
                  CATCallbackEvent  iData,
	         CATSubscriberData iCallBack);
	         
  HRESULT ModifyListItem() ;

  CAAAfrMRURep (const CAAAfrMRURep &iObjectToCopy);
  CAAAfrMRURep & operator = (const CAAAfrMRURep &iObjectToCopy);

private:
     CATDlgPushItem         * _pItemList[MRU_MAX_SIZE];
     CAAIAfrMRUManagement   * _pIAfrMRUManagement ;
};

Here the CAAAfrMRURep source file:

[Top]

Instantiating the MRU Header Class

The MRU header is independent of the document, so this header is instantiated in an Add-in of the General workshop [3]. Here is an extract of the CAAAfrGeneralWksAdn class which is an implementation of the CATIAfrGeneralWksAddin interface. 

...
void CAAAfrGeneralWksAdn::CreateCommands()
{
  CATCommandHeader * pHdr = (CATCommandHeader*) new CAAAfrMRUHeader("CAAAfrMRUHdr");
  pHdr->SetVisibility(0);

...

The MRU command header is created using the constructor class. The most important thing in the usage of the SetVisibility method. This method of the CATCommandHeader class allows us to hide the command header instance in the Tools/Customize command. This command displays a dialog box containing tab pages. One of them, the Command tab page, displays by category, all the "visible" command header instances. The two following pictures explains the difference when the SetVisibility method is used or not.

This picture shows the Command tab page of the Tools/Customize command. In the All Commands category, you see that the CAAAfrMRUHdr appears. To do that we have set a comment before the SetVisibility  instruction. The MRU header is without NLS resources [10], so the displayed name is the internal name of the command header instance (the argument of the constructor class).
Now, using SetVisibility with 0 as argument, you can see that between Bulk Loading... and Capture,  CAAAfrMRUHdr is not there.

The advantage to hidde a command header, is that the end user cannot drag and drop the command in a toolbar, or it cannot launch it from the power input since it do not know its name. But caution, SetVisibility method do not prohibit to launch the command header in the power input, if you know the name of the command header. For the MRU header, there is no effect since there is no CATCommand associated with the MRU Header.

...
  pHdrMRU = (CATCommandHeader*) new CAAAfrGeneralWksAddinHeader("CAAAfrMRUSelElementHdr", 
                             "CAAAfrGeoCommands", 
                             "CAAAfrMRUSelElementCmd",
                             (void *) NULL);
  pHdrMRU->SetVisibility(0);
  
...

The next header instance name is CAAAfrMRUSelElementHdr. This header is a standard command header. So the CAAAfrGeneralWksAddinHeader command header class is used to create an instance [3]. This instance launches the CAAAfrMRUSelElementCmd command which is defined in the CAAAfrGeoCommands module of the CAAApplicationFrame.edu framework. This instance of command header is also hidden in Tools/Customize, because the use case want only to launch this command when the end user selects an item in the File Menu. But if you try to enter CAAAfrMRUSelElementHdr in the power input the Dialog command is lauched and the current item is displayed.

The last header about the MRU use case is the CAAAfrMRUAddElementHdr. It is a standard command header which launches the CAAAfrMRUAddElementCmd command which is defined in the CAAAfrGeoCommands module of the CAAApplicationFrame.edu framework. 

...
new CAAAfrGeneralWksAddinHeader("CAAAfrMRUAddElementHdr", 
                             "CAAAfrGeoCommands", 
                             "CAAAfrMRUAddElementCmd",
                             (void *) NULL);
...

In the CNext/resources/msgcatalog directory [10] you will find in the CAAAfrGeneralWksAddinHeader.CATNls file the following lines:

...
CAAAfrGeneralWksAddinHeader.CAAAfrMRUAddElementHdr.Category  = "File" ;
CAAAfrGeneralWksAddinHeader.CAAAfrMRUAddElementHdr.Title     = "Add Item in MRU" ;
CAAAfrGeneralWksAddinHeader.CAAAfrMRUAddElementHdr.ShortHelp = "Add Item in MRU" ;
CAAAfrGeneralWksAddinHeader.CAAAfrMRUAddElementHdr.Help      = "Add Item in MRU" ;
CAAAfrGeneralWksAddinHeader.CAAAfrMRUAddElementHdr.LongHelp  = "Add Item in MRU
This command adds a new item in the MRU list." ;
...

and in the CAAAfrGeneralWksAddinHeader.CATRsc file 

...
CAAAfrGeneralWksAddinHeader.CAAAfrMRUAddElementHdr.Icon.Normal = "I_CAAMRUAddItem" ;
...

where I_CAAMRUAddItem is the following icon: and that you retrieve in the CNext/resources/graphic/icons/normal directory.

[Top]


In Short

This use case has explained how to create a command header whose the graphic representation is customized:

The data model is kept by an unique instance during the session. 

[Top]


References

[1] Creating a Combo Command Header
[2] The Command Headers
[3] Making Your Document Independent Command Available in All Workbenches
[4] CATDlgPushItem
[5] Building and Launching a CAA V5 Use Case
[6] Creating Interfaces
[7] The Callback Mechanism (Technical Article)
[8] The Callback Mechanism (Use Case)
[9] The CAA Command Model
[10] Creating Resources for Command Headers
[11] Object Modeler Inheritances
[Top]

History

Version: 1 [Feb 2004] Document created
[Top]

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