Difference between revisions of "User:Arielch/Internship/Current Context Menu Implementation"

From Apache OpenOffice Wiki
Jump to: navigation, search
m (Context menu and shells)
Line 295: Line 295:
  
 
=== Context menu and shells ===
 
=== Context menu and shells ===
Every feature provided by a context menu (and by all the other UI elements) is represented in the application framework by a '''command URL''' (cf. [http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/OfficeDev/Command_URL OpenOffice.org Developer's Guide - Office ][http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/OfficeDev/Command_URL Development - OpenOffice.org Application Environment - Using the Dispatch Framework - Command URL]). In the older SFX framework features are represented by '''''slots''''' organized into '''''shells'''''. A shell can be seen as a '''context''' that groups related functionality, and is internally represented by an object derived from the [http://svn.services.openoffice.org/opengrok/xref/DEV300_m85/sfx2/inc/sfx2/shell.hxx#SfxShell SfxShell] base class.
+
Every feature provided by a context menu (and by all the other UI elements) is represented in the application framework by a '''command URL''' (cf. [http://wiki.services.openoffice.org/wiki/Documentation/DevGuide/OfficeDev/Command_URL OpenOffice.org Developer's Guide - Office Development - OpenOffice.org Application Environment - Using the Dispatch Framework - Command URL]). In the older SFX framework features are represented by '''''slots''''' organized into '''''shells'''''. A shell can be seen as a '''context''' that groups related functionality, and is internally represented by an object derived from the [http://svn.services.openoffice.org/opengrok/xref/DEV300_m85/sfx2/inc/sfx2/shell.hxx#SfxShell SfxShell] base class.
  
 
For our purpose it is important to know that the functionality of a shell is defined in its “interface”, represented by a [http://svn.services.openoffice.org/opengrok/xref/DEV300_m85/sfx2/inc/sfx2/objface.hxx#SfxInterface SfxInterface].</tt> This object contains an array of slots, where each slot represents a command supported in this context (that is, by this shell object). More important, a '''context menu''' is registered at the shell's interface using the macro [http://svn.services.openoffice.org/opengrok/xref/DEV300_m85/sfx2/inc/sfx2/shell.hxx#SFX_POPUPMENU_REGISTRATION SFX_POPUPMENU_REGISTRATION]<nowiki>; for example, the first context menu defined above (</nowiki><tt>RID_POPUP_CELLS</tt>) is registered at the [http://svn.services.openoffice.org/opengrok/xref/DEV300_m85/sc/source/ui/view/cellsh.cxx#SFX_IMPL_INTERFACE ScCellShell]'s interface:
 
For our purpose it is important to know that the functionality of a shell is defined in its “interface”, represented by a [http://svn.services.openoffice.org/opengrok/xref/DEV300_m85/sfx2/inc/sfx2/objface.hxx#SfxInterface SfxInterface].</tt> This object contains an array of slots, where each slot represents a command supported in this context (that is, by this shell object). More important, a '''context menu''' is registered at the shell's interface using the macro [http://svn.services.openoffice.org/opengrok/xref/DEV300_m85/sfx2/inc/sfx2/shell.hxx#SFX_POPUPMENU_REGISTRATION SFX_POPUPMENU_REGISTRATION]<nowiki>; for example, the first context menu defined above (</nowiki><tt>RID_POPUP_CELLS</tt>) is registered at the [http://svn.services.openoffice.org/opengrok/xref/DEV300_m85/sc/source/ui/view/cellsh.cxx#SFX_IMPL_INTERFACE ScCellShell]'s interface:

Revision as of 23:51, 10 August 2010


A prerequisite for developing a New Context Menu Implementation is to get a clear understanding about how context menus currently work. This page summarizes the research done during the first week; it is just an outline that will guide in a further, deeper research that should be undertaken to adapt the code in the application modules to use the new context menu implementation.

It begins with an introduction about how context menus work in OpenOffice.org, followed by a (rather abstract/technical) explanation of the general mechanism based on the sfx2 code, together with a short description of the current state in both sfx2 and non-sfx2-based modules.

Introduction

A context menu is a menu that is displayed upon user interaction, such as a mouse click or a keyboard stroke, exposing to the user the functionality that is available in the current context.

Internally, a context menu is called a pop-up menu, though we will avoid this term because pop-up menus are also the menu bar's sub-menus, and the menus displayed when some toolbar item or a certain kind of button are pressed.

The following gives an overview of what takes place internally when a context menu is created, displayed, and the respective selected action – if any – executed.

Context menu events

VCL (Visual Control Layer) is the core module responsible for OpenOffice.org Graphical User Interface at the lower level. By “lower level” we mean that VCL code handles the main event loop, that waits for events and dispatches them, and controls all graphical output on the display.

We will not enter on the lower, system-dependent part of VCL (the System Abstraction Layer – SAL), for now it is enough to understand that events such as the key and mouse events that trigger the context menu execution are processed at system-level and then translated and posted to VCL's system-independent layer (in a function named ImplWindowFrameProc) that processes the event (see for example the mouse event case) and then calls the code responsible for handling it, the so called “event handler” (see ImplCallCommand), which receives a CommandEvent (in our case, CommandEvent::GetCommand() reports a COMMAND_CONTEXTMENU, and CommandEvent::IsMouseEvent() is TRUE in case the event was fired by a mouse user action, FALSE if it was triggered by keyboard – this is important to determine the position where the context menu is displayed: it depends on the mouse coordinates – in case of mouse event, or it is calculated relative to the Window that received the key event).

The context menu event handling takes us to the modules level. Usually the event is triggered on the window that displays the document content (a class derived from VCL's Window, owned by the document's currently active view), and handled in the respective Command method overridden by the derived class, for example:

Of course, not every context menu is activated on the window that displays the document content (the component window); in a Writer document, for example, the user can trigger the context menu over a toolbar to customize it, or over the status bar control that displays the current page style in order to change it, or over the ruler to change the measure unit, etc. We will come back to this later.

The code handling the context menu event is rather module specific, but in general, once the context menu to be displayed is determined according to the context where the event was triggered, the context menu structure is created.

Menu structure and resource files

A context menu is an instance of a VCL PopupMenu, a class responsible for both the menu structure – in form of a List container, and its visual representation (here again with a system-dependent and a system-independent layer).

This class has a constructor to instantiate an empty PopupMenu, and methods to insert items into this container, one by one (much like the com.sun.star.awt.PopupMenu API, which is a UNO wrapper of this VCL functionality). As you can imagine, hard-coding the menu structure in the source code is not much reliable, so in most parts of the application code PopupMenus are usually initialized from a resource that holds (usually almost) the whole menu structure. This is done with the PopupMenu's constructor that takes a ResId, which is a class that encapsulates (among other things) a numeric identifier that unequivocally identifies a resource and an object to handle this kind of data (a so called resource manager).

The menu structure is described in a text file (*.src) that is then compiled into a binary file (*.res) by a resource compiler. The following example shows the menu definition for the context menu activated for a cell or cell range in OpenOffice.org Calc (sc/source/ui/src/popup.src):

 Menu RID_POPUP_CELLS
 {
     ItemList =
     {
         MenuItem
         {
             Identifier = SID_CELL_FORMAT_RESET ;
             HelpId = SID_CELL_FORMAT_RESET ;
             Text [ en-US ] = "~Default Formatting" ;
         };
          //------------------------------
         MenuItem { Separator = TRUE ; };
          //------------------------------
         MenuItem
         {
             Identifier = FID_CELL_FORMAT ;
             HelpId = FID_CELL_FORMAT ;
             Text [ en-US ] = "~Format Cells..." ;
         };
          //------------------------------
         MenuItem { Separator = TRUE ; };
          //------------------------------
         MenuItem
         {
             Identifier = FID_INS_CELL ;
             HelpId = FID_INS_CELL ;
             Text [ en-US ] = "~Insert..." ;
         };
         MenuItem
         {
             Identifier = FID_DELETE_CELL ;
             HelpId = FID_DELETE_CELL ;
             Text [ en-US ] = "De~lete..." ;
         };
         MenuItem
         {
             Identifier = SID_DELETE ;
             HelpId = SID_DELETE ;
             Text [ en-US ] = "Delete C~ontents..." ;
         };
          //------------------------------
         MenuItem { Separator = TRUE ; };
          //------------------------------
         MenuItem
         {
             Identifier = SID_INSERT_POSTIT ;
             HelpId = SID_INSERT_POSTIT ;
             Text [ en-US ] = "Insert Co~mment" ;
         };
         MenuItem
         {
             Identifier = SID_DELETE_NOTE ;
             HelpId = SID_DELETE_NOTE ;
             Text [ en-US ] = "D~elete Comment" ;
         };
         MenuItem
         {
             Identifier = FID_NOTE_VISIBLE ;
             HelpId = FID_NOTE_VISIBLE ;
             Text [ en-US ] = "Sho~w Comment" ;
         };
          //------------------------------
         MenuItem { Separator = TRUE ; };
          //------------------------------
 
         MenuItem
         {
             Identifier = SID_CUT ;
             HelpId = SID_CUT ;
             Text [ en-US ] = "Cu~t" ;
         };
         MenuItem
         {
             Identifier = SID_COPY ;
             HelpId = SID_COPY ;
             Text [ en-US ] = "~Copy" ;
         };
 
         MenuItem
         {
             Identifier = SID_PASTE ;
             HelpID = SID_PASTE ;
             Text [ en-US ] = "~Paste" ;
         };
 
         MenuItem
         {
             Identifier = SID_PASTE_SPECIAL ;
             HelpId = SID_PASTE_SPECIAL ;
             Text [ en-US ] = "P~aste Special..." ;
         };
          //------------------------------
         MenuItem { Separator = TRUE ; };
          //------------------------------
         MenuItem
         {
             Identifier = SID_DATA_SELECT ;
             HelpId = SID_DATA_SELECT ;
             Text [ en-US ] = "~Selection List..." ;
         };
     };
 };

The following is a short description of the Menu resource definition (mainly taken from rsc/doku/feinkonz.43/rsc.doc):

in the first line

Menu RID_POPUP_CELLS

the keyword Menu defines the type of this resource: a Menu defines the data for the VCL classes PopupMenu and MenuBar (this last one is now obsolete, because the MenuBar definition is stored in an XML file).

RID_POPUP_CELLS is the numeric resource identifier.

A Menu is a list of menu items, so inside the outermost brackets ItemList contains a list of MenuItems that will be inserted in the VCL Menu in the order they were written.

Inside a MenuItem, when the keyword Separator is followed by TRUE it indicates that the item will not be displayed to the user with a text describing a function, it will be just a medium to visually separate one MenuItem from another (thus allowing to group together MenuItems).

The keyword Text specifies the text of the menu item (the text locale is given inside square brackets, usually only for en-US – other locales are added at build time by transex3 from a localize.sdf file).

The keyword HelpId specifies a numeric identifier that references a string in the Help system with a descriptive help text. There is also a HelpText keyword that specifies the localized help text directly (but this rarely used for PopupMenus inside the src file).

The keyword Identifier specifies a number which is used to identify the menu item (on the sfx2-based modules, it usually corresponds to a slot ID, and will be used to execute the respective functionality).

The keyword Command specifies the Command URL (in the form of “.uno:XXX”), notably missing in the example above (this has the drawback for extensions intercepting context menus that the Command URL is generated in the form of “[slot:Identifier slot:Identifier]”, making it really hard to detect the menu item functionality).

Inside a MemuItem it is possible define a Menu, that will work as a SubMenu: a new PopupMenu that will be activated when the MenuItem is highlighted.

There are other keywords that are now hardly used (Check, Disable,), refer to document quoted above for a description.

The following example shows the menu definition for the context menu activated when editing a cell in OpenOffice.org Calc (sc/source/ui/src/popup.src):

 Menu RID_POPUP_EDIT
 {
     ItemList =
     {
         MenuItem
         {
             Identifier = SID_CELL_FORMAT_RESET ;
             HelpId = SID_CELL_FORMAT_RESET ;
             Text [ en-US ] = "~Default" ;
         };
          //------------------------------
         MenuItem { Separator = TRUE ; };
          //------------------------------
         MenuItem // Menu-Controller
         {
             ITEM_FORMAT_ATTR_CHAR_FONT
         };
         MenuItem // Menu-Controller
         {
             ITEM_FORMAT_ATTR_CHAR_FONTHEIGHT
         };
         MenuItem
         {
             Text [ en-US ] = "Style" ;
             Identifier = RID_MN_FORMAT_STYLE ;
             HelpID = RID_MN_FORMAT_STYLE ;
             SubMenu = Menu
             {
                 ItemList =
                 {
                     MenuItem
                     {
                         ITEM_FORMAT_ATTR_CHAR_WEIGHT
                     };
                     MenuItem
                     {
                         ITEM_FORMAT_ATTR_CHAR_POSTURE
                     };
                     MenuItem
                     {
                         ITEM_FORMAT_ATTR_CHAR_OVERLINE
                     };
                     MenuItem
                     {
                         ITEM_FORMAT_ATTR_CHAR_UNDERLINE
                     };
                     MenuItem
                     {
                         Identifier = SID_ULINE_VAL_DOUBLE ;
                         HelpID = SID_ULINE_VAL_DOUBLE ;
                         Text [ en-US ] = "Do~uble Underline" ;
                     };
                     MenuItem
                     {
                         ITEM_FORMAT_ATTR_CHAR_STRIKEOUT
                     };
                     MenuItem
                     {
                         ITEM_FORMAT_ATTR_CHAR_SHADOWED
                     };
                     MenuItem
                     {
                         ITEM_FORMAT_ATTR_CHAR_CONTOUR
                     };
                     MenuItem
                     {
                         Separator = TRUE ;
                     };
                     MenuItem
                     {
                         Identifier = SID_SET_SUPER_SCRIPT ;
                         HelpID = SID_SET_SUPER_SCRIPT ;
                         Text [ en-US ] = "Su~perscript" ;
                     };
                     MenuItem
                     {
                         Identifier = SID_SET_SUB_SCRIPT ;
                         HelpID = SID_SET_SUB_SCRIPT ;
                         Text [ en-US ] = "Su~bscript" ;
                     };
                 };
             };
             Text [ en-US ] = "St~yle";
         };
          //------------------------------
         MenuItem { Separator = TRUE ; };
          //------------------------------
         MenuItem
         {
             ITEM_FORMAT_CHAR_DLG
         };
          //------------------------------
         MenuItem { Separator = TRUE ; };
          //------------------------------
         MenuItem
         {
             ITEM_OPEN_HYPERLINK
         };
     };
 };

This example shows the use of macro definitions and include directives inside the src file: ITEM_FORMAT_ATTR_CHAR_FONT (“Font” in the UI) and ITEM_FORMAT_ATTR_CHAR_FONTHEIGHT ("Size" in the UI), for example, are defined in another file, from another module, included in this file (svx/inc/globlmn_tmpl.hrc) with an include directive at the top of the src file.

Context binding

Although the code handling the context menu event chooses the right resource ID for the VCL PopupMenu according to the current context (the current selection in the document view), this context menu, at the moment of its creation, lacks still of full context sensitiveness: each menu item must be bound to the dynamic state of the application module, reflecting the current state of the feature it represents.

In the first code snippet, for example, a comment/note can be deleted or shown only if it has been inserted, so that if there is no comment in the cell for which the context menu was activated, the menu items that represent the functionality to delete and to show comments must be disable (and removed from the context menu that is finally displayed to the user – this is different from the MenuBar's PopupMenus, where disabled menu items are not removed).

This means that the context menu structure defined in the resource text file includes all supported features for this context, but not all of them are available/enabled all the time, and this has to be determined at runtime for each menu item.

The second code snippet shows another important fact: “Font”, “Size” and “Style” have all submenus, but only the “Style” submenu is defined in the resource text file. The reason is that the whole content of these submenus must be filled at runtime.

Command execution

Once the context menu is bound to the dynamic state of the office document, and disabled menu entries are removed, the menu is ready to be displayed to the user. This is done by the application module code, by simply calling PopupMenu::Execute (usually after linking some callbacks to handle specific Menu events).

Finally, the function represented by the selected menu item is executed: the menu item ID (or – more rarely – its Command URL) is dispatched.

SFX2 modules

SFX2 Context menu internals

This generic process flow described in the sections above is handled in concrete by the code in the different application modules in a not very unified way, so that it is quite hard to talk about “a current implementation”. Nevertheless, in the sfx2-based modules we can find a “generic” approach that will be described next. We will not go into further SFX2 internals, refer to the framework article for a more detail explanation.

Context menu and shells

Every feature provided by a context menu (and by all the other UI elements) is represented in the application framework by a command URL (cf. OpenOffice.org Developer's Guide - Office Development - OpenOffice.org Application Environment - Using the Dispatch Framework - Command URL). In the older SFX framework features are represented by slots organized into shells. A shell can be seen as a context that groups related functionality, and is internally represented by an object derived from the SfxShell base class.

For our purpose it is important to know that the functionality of a shell is defined in its “interface”, represented by a SfxInterface.</tt> This object contains an array of slots, where each slot represents a command supported in this context (that is, by this shell object). More important, a context menu is registered at the shell's interface using the macro SFX_POPUPMENU_REGISTRATION; for example, the first context menu defined above (RID_POPUP_CELLS) is registered at the ScCellShell's interface:

 SFX_IMPL_INTERFACE(ScCellShell, ScFormatShell , ScResId(SCSTR_CELLSHELL) )
 {
     SFX_OBJECTBAR_REGISTRATION( SFX_OBJECTBAR_OBJECT | SFX_VISIBILITY_STANDARD |
                                 SFX_VISIBILITY_SERVER,
                                 ScResId(RID_OBJECTBAR_FORMAT));
     SFX_POPUPMENU_REGISTRATION(ScResId(RID_POPUP_CELLS));
 }

while the second one (RID_POPUP_EDIT) is registered at the ScEditShell's interface:

 SFX_IMPL_INTERFACE(ScEditShell, SfxShell, ScResId(SCSTR_EDITSHELL))
 {
     SFX_POPUPMENU_REGISTRATION( ScResId(RID_POPUP_EDIT) );
 }


This registration simply stores the context menu resource ID in the shell interface's pointer implementation (aPopupRes member of SfxInterface_Impl) so that later it can be retrieved calling SfxInterface::GetPopupMenuResId().</tt>

Context menus registered in this way at a shell's interface are executed by a SfxDispatcher, an object owned by the SfxViewFrame. The SfxDispatcher maintains internally a stack of shell objects, the complete stack of contexts represents the whole functionality available in the current context at the document view in a particular situation (in the current selection, the current cursor position). As the context changes, shell objects are pushed and popped to and from the stack.

As an example, the following table represents how the stack looks when the context menu is activated for a cell or cell range in OpenOffice.org Calc:


Shell level
Shell name
Shell class
Registered PopupMenu resource ID
0 Cell ScCellShell (cell) RID_POPUP_CELLS (25003)
1 Form FmFormShell (form) 0
2 View SfxViewShell (view) 0
3 <Document title> SfxObjectShell (document) 0
4 <Doc. title>:<view frame Nr.> SfxViewFrame (frame) 0
5 StarCalc SfxModule (module) 0
6 StarOffice SfxApplication (application) 0

The shell name is the one retrieved by calling SfxShell::GetName(), the PopuMenu ResId is retrieved by calling GetPopupMenuResId() at the shell's SfxInterface (the unsigned 32 bits integer value is retrieved by ResId::GetId() ). The last four shells are usually pushed to the SfxDispatcher right after it is instantiated (see SfxViewFrame::Construct_Impl).

The table above can be compared with the next one, that represents the stack when the context menu is activated while editing a cell:


Shell level
Shell name
Shell class
Registered PopupMenu ResID
0 EditCell ScEditShell RID_POPUP_EDIT (25033)
1 Cell ScCellShell (cell) RID_POPUP_CELLS (25003)
2 Form FmFormShell (form) 0
3 View SfxViewShell (view) 0
4 <Document title> SfxObjectShell (document) 0
5 <Doc. title>:<view frame Nr.> SfxViewFrame (frame) 0
6 StarCalc SfxModule (module) 0
7 StarOffice SfxApplication (application) 0

This shows that the ScEditShell is pushed to the stack when the cell editing mode is entered, though the ScCellShell is not popped: both contexts are merged, because editing a cell includes also cell functionality. Both shells register a PopupMenu, but the SfxDispatcher will choose the one with higher priority (the one at the top of the stack of shells).


The following example pictures another aspect; it shows the stack of shells when a context menu is activated for a Fontwork shape in OpenOffice.org Writer:


Shell level
Shell name
Shell class
Registered PopupMenu ResID
0 Fontwork svx::FontworkBar 0
1 Draw SwDrawShell (drawing functionality in Writer) MN_DRAW_POPUPMENU (23153)
2 Form FmFormShell (form) 0
3 View SfxViewShell (view) 0
4 <Document title> SfxObjectShell (document) 0
5 <Doc. title>:<view frame Nr.> SfxViewFrame (frame) 0
6 StarCalc SfxModule (module) 0
7 StarOffice SfxApplication (application) 0

The shell on the top of the stack did not register a PopupMenu at the shell's interface, so the SfxDispatcher executes the next shell's PopupMenu. The logic behind this is explained next.

A very illustrative example of the SfxDispatcher stack in action can be seen in SwView::SelectShell.

Context menu processing

The following classes play a main role in the context menu handling at the SFX2 level:

  • SfxDispatcher is the point of contact between the application module code handling the context menu event and the SFX2 code manipulating the context menu. The application code calls SfxDispatcher::ExecutePopup(), which in turns calls SfxPopupMenuManager::ExecutePopup() with the resource ID for the context menu.
  • SfxPopupMenuManager and its base class SfxMenuManager are responsible for creating the VCL PopupMenu from the resource ID, and also a SfxVirtualMenu for the root PopupMenu.
  • SfxVirtualMenu is a kid of wrapper of the VCL PopupMenu, every submenu with a static nature (that is, whose structure is defined in a resource file and not completely defined at runtime) will be wrapped in a SfxVirtualMenu.
  • SfxMenuControl: for every menu item there is a SfxMenuControl responsible for its context-sensitiveness, all menu items are by default controlled by a SfxMenuControl instance, except for those commands URLs/IDs for which has been registered an specific derived class at module level (these SfxMenuControls are usually responsible of filling a whole submenu at runtime, and setting the state of the respective item in the parent menu)

SfxDispatcher

The application module code usually calls one of the following SfxDispatcher methods:

 // caller has to clean up the Manager on his own
 static SfxPopupMenuManager* Popup( sal_uInt16 nConfigId,Window *pWin, const Point *pPos );
 
 void         ExecutePopup( const ResId &rId,
                            Window *pWin = 0, const Point *pPosPixel = 0 );
 static void  ExecutePopup( USHORT nConfigId = 0,
                            Window *pWin = 0, const Point *pPosPixel = 0 );

The parameter pWin is a VCL Window, and is the parent of the PopupMenu's window (a MenuFloatingWindow). If no Window was given, it is assumed to be the component's window.

The parameter pPosPixel is a Point that represents the coordinates of the left upper corner of the PopupMenu's window. If no Point was given, it is assumed to be the mouse pointer position.

When the SfxDispatcher is called with a ResId, it simply calls SfxPopupMenuManager::ExecutePopup. When the numeric resource ID is given, the SfxDispatcher stack of shell is searched for a suitable ResId (usually nConfigId is 0, so the first ResId whose numeric ID is different from 0 is chosen; if nConfigId is not 0, the first ResId whose numeric ID is identical with nConfigId will be chosen).

SfxPopupMenuManager

The static method SfxPopupMenuManager::ExecutePopup deserves a step-by-step, description.

It first instantiates a VCL PopupMenu for the ResId passed as argument, and loops the root container until finding the first clipboard function (Cut, Copy, Paste):

     PopupMenu *pSVMenu = new PopupMenu( rResId );
     USHORT n, nCount = pSVMenu->GetItemCount();
     for ( n=0; n<nCount; n++ )
     {
         USHORT nId = pSVMenu->GetItemId( n );
         if ( nId == SID_COPY || nId == SID_CUT || nId == SID_PASTE )
             break;
     }

the Thesaurus submenu is inserted right before them:

     PopupMenu* pThesSubMenu = InsertThesaurusSubmenu_Impl( &pFrame->GetBindings(), pSVMenu );

If no clipboard functions where found, they are insert right here, after the Thesaurus submenu;

     if ( n == nCount )
     {
         PopupMenu aPop( SfxResId( MN_CLIPBOARDFUNCS ) );
         nCount = aPop.GetItemCount();
         pSVMenu->InsertSeparator();
         for ( n=0; n<nCount; n++ )
         {
             USHORT nId = aPop.GetItemId( n );
             pSVMenu->InsertItem( nId, aPop.GetItemText( nId ), aPop.GetItemBits( nId ) );
             pSVMenu->SetHelpId( nId, aPop.GetHelpId( nId ));
         }
     }

The verbs of the embedded object are inserted right after the clipboard functions:

     InsertVerbs_Impl( &pFrame->GetBindings(), pFrame->GetViewShell()->GetVerbs(), pSVMenu );

Some information must be set for letting the context menu be intercepted:

     Menu* pMenu = NULL;
     ::com::sun::star::ui::ContextMenuExecuteEvent aEvent;
     aEvent.SourceWindow = VCLUnoHelper::GetInterface( pWindow );
     aEvent.ExecutePosition.X = rPoint.X();
     aEvent.ExecutePosition.Y = rPoint.Y();
     ::rtl::OUString sDummyMenuName;

If any interceptor did not cancel the context menu execution, then it must be executed, not directly by calling PopupMenu::Execute(), but through the SfxPopupMenuManager:

     if ( pFrame->GetViewShell()->TryContextMenuInterception( *pSVMenu, sDummyMenuName, pMenu, aEvent ) )
     {
         if ( pMenu )
         {
             delete pSVMenu;
             pSVMenu = (PopupMenu*) pMenu;
         }
 
                 SfxPopupMenuManager aPop( pSVMenu, pFrame->GetBindings() );
                 aPop.RemoveDisabledEntries();
                 aPop.Execute( rPoint, pWindow );
     }
 
     delete pThesSubMenu;

The following points are of special interest, considering the new implementation design:

  • clipboard functions should be added to the XML structure of every context menu that uses them (every shell that supports them), and not handled as a special case in the generic context menu implementation
  • the same is valid for the Thesaurus submenu: a menu item must be added in the menu structure, and filled at runtime by a UNO PopupMenu controller implementation
  • the embedded objects verbs should be filled by a UNO PopupMenu controller, and so they should not be added in the root context menu: a PopupMenu controller should only have access to the PopupMenu it is filling, not its parent, nor the root menu.

SfxVirtualMenu

The SfxVirtualMenu wraps the VCL PopupMenu functionality, providing the context binding the VCL menu lacks of. This is done by instantiating a menu item controller for every menu item.

The root SfxVirtualMenu for the root PopupMenu is instantiated in the SfxMenuManger constructor. A new SfxVirtualMenu is created when a menu item has a submenu of its own, that is not dynamically filled, but defined in the resource file. For the other menu items, a default menu controller is created, or a special one, registered at the module level (this last is the case when the menu item has a dynamically generated submenu).

SfxMenuControl

The main role of a SfxMenuControl is to listen for status updates and reflect this in the menu item it controls, this implies that the menu item is enabled or disabled, checked or unchecked, etc. depending of the state and type of notification (the SfxItemState and the type of SfxPoolItem passed to SfxMenuControl::StateChanged).

Most menu items are controlled by a generic menu item controller, an instance of SfxMenuControl, some menu item require a special menu item controller which is responsible for a whole PopupMenu.

SFX2 Menu Controllers

Special menu item controllers are derived from SfxMenuControl. They provide special functionality, which usually consist in filling up a whole submenu. For example, when the SfxPoolItem is a SfxStringItem, the generic controller simply updates the menu item text with the new string transported in the pool item; the controller in charge of the Thesaurus menu item also receives a SfxStringItem, but it contains a string that must be processed (in the form of “text#locale”) so that synonyms are looked up and inserted in a submenu.

The next table contains these special SFX2-based menu item controllers:


Menu Controller
Command URL
UNO PopupMenuController replacement
ControlConversionMenuController .uno:ChangeControlType framework::ControlMenuController[1]
SfxObjectVerbsControl .uno:ObjectMenue framework::ObjectMenuController[2]
SfxThesSubMenuControl .uno:ThesaurusFromContext Not ported yet
SvxFontMenuControl .uno:CharFontName framework::FontMenuController
SvxFontSizeMenuControl .uno:FontHeight framework::FontSizeMenuController[3]
SvxSmartTagsControl [none?] Not ported yet

Except for SfxThesSubMenuControl and SvxSmartTagsControl, the other SFX PopupMenu Controllers are already ported to the new PopupMenuController API, see UI Controllers – UNO PopupMenu Controllers.

Notice that the SfxObjectVerbsControl is not even used, OLE verbs are inserted directly in SfxPopupMenuManager::ExecutePopup, calling InsertVerbs_Impl.

SFX2 Modules analysis

As explained above, in general, SFX2 context menus are registered at the shell's interface using the macro SFX_POPUPMENU_REGISTRATION; unfortunately, searching for this macro's use cases in all the modules will not give the complete list of all context menus that we should migrate from the resource file to a XML format. With this in mind, the menus registered in each sfx2-based module listed in following sections do not represent the whole set of context menu actually in use.

sw

The following table list PopupMenus registered at Writer's shells:


PopupMenu Resource ID
ID Numeric Value
SW Shells
Shell Name
Menu String [en-US]
MN_DRAW_POPUPMENU 23153 SwDrawShell

SwBezierShell

Draw

Bezier

Graphic
MN_DRAWFORM_POPUPMENU 23159 SwDrawFormShell

SwWebDrawFormShell

DrawForm Control
MN_DRWTXT_POPUPMENU 23154 SwDrawTextShell ObjectText Draw Object text
MN_FRM_POPUPMENU 23152 SwFrameShell

SwWebFrameShell

Frame Frame
MN_GRF_POPUPMENU 23155 SwGrfShell

SwWebGrfShell

Graphic Graphic
MN_MEDIA_POPUPMENU 23160 SwMediaShell Media Playback Media object
MN_OLE_POPUPMENU 23156 SwOleShell

SwWebOleShell

Object Object
MN_PPREVIEW_POPUPMENU 23157 SwPagePreView PageView Draw Object text
MN_SRCVIEW_POPUPMENU 23158 SwSrcView Source HTML source
MN_TAB_POPUPMENU 23151 SwTableShell

SwWebTableShell

Table Table
MN_TEXT_POPUPMENU 23150 SwTextShell Text Text
MN_WEB_TEXT_POPUPMENU 20446 SwWebTextShell Text NO STRING
MN_ANNOTATION_POPUPMENU 23164 SwAnnotationShell  ??? (NONE)

sc

The following table list PopupMenus registered at Calc's shells:


PopupMenu Resource ID
ID Numeric Value
SC Shell
Shell Name
Menu String [en-US]
RID_POPUP_CELLS 25003 ScCellShell Cell "Cell pop-up menu"
RID_POPUP_TAB 26345 ScTabPopShell "Sheet bar pop-up menu"
RID_POPUP_PAGEBREAK 25046 ScPageBreakShell PageBreak "Page Break Preview pop-up menu"
RID_POPUP_AUDIT 25034 ScAuditingShell Auditing "Detective Fill Mode pop-up menu"
RID_POPUP_PIVOT 25021 ScPivotShell Pivot "DataPilot pop-up menu"
RID_POPUP_EDIT 25033 ScEditShell EditCell "Text Input pop-up menu"
RID_POPUP_PREVIEW 25007 ScPreviewShell Preview "Page Preview pop-up menu"
RID_POPUP_CHART 25009 ScChartShell ChartObject [NO STRING]
RID_POPUP_DRAWFORM 25048 ScDrawFormShell DrawForm "Popup menu for form objects"
RID_POPUP_OLE 25008 ScOleObjectShell OleObject [NO STRING]
RID_POPUP_MEDIA 25061 ScMediaShell "Media Playback"[1] [NO STRING]
RID_POPUP_DRAW 25004 ScDrawShell Drawing "Pop-up menu for drawing objects"
RID_POPUP_GRAPHIC 25024 ScGraphicShell GraphicObject [NO STRING]
RID_POPUP_DRAWTEXT 25029 ScDrawTextObjectBar DrawText "Pop-up menu for text objects"

sd

The following table lists PopupMenus registered at Draw/Impress's shells, the y all are executed using the SFX2 framework:


PopupMenu Resource ID
sd Shell
RID_TASKPANE_LAYOUTMENU_POPUP sd::toolpanel::LayoutMenu
RID_TASKPANE_MASTERPAGESSELECTOR_POPUP sd::toolpanel::controls::MasterPagesSelector
RID_DRAW_TEXTOBJ_INSIDE_POPUP sd::DrawViewShell

sd::GraphicViewShell

RID_OUTLINE_POPUP sd::OutlineViewShell

In sd most PopupMenus are not registered at a shell.

The following menus are defined in sd/source/ui/app/popup.src, they all use the SFX2 framework but are not registered:

  • Draw only:
    • RID_SLIDE_SORTER_DRAW_SEL_POPUP
    • RID_SLIDE_SORTER_DRAW_NOSEL_POPUP
    • RID_LAYERTAB_POPUP
  • Impress only:
    • RID_SLIDE_SORTER_IMPRESS_SEL_POPUP
    • RID_SLIDE_SORTER_IMPRESS_NOSEL_POPUP
    • RID_SLIDE_SORTER_MASTER_SEL_POPUP
    • RID_SLIDE_SORTER_MASTER_NOSEL_POPUP
  • both Draw and Impress:
    • RID_DRAW_TABLEOBJ_INSIDE_POPUP
    • RID_FORM_CONTROL_POPUP
    • RID_DRAW_GLUEPOINT_POPUP
    • RID_BEZIER_POPUP

The resource file sd/source/ui/app/popup2_tmpl.src contains menus defined using conditional compilation to indicate the resource compiler when a menu is meant for Draw or Impress; the menu structure is basically the same for both applications, except that Impress menus in general add two items, one for the “Custom Animation” and other for the “Interaction”. The menu ID naming follows the following scheme: RID_SHELL_NAME_POPUP, where SHELL is DRAW (for Impress menus) or GRAPHIC (for Draw menus), for example RID_DRAW_TEXTOBJ_POPUP and RID_GRAPHIC_TEXTOBJ_POPUP. All this context menus are handled in sd::DrawViewShell::Command, using the generic SFX2 framework:


Impress
Draw
RID_DRAW_TEXTOBJ_POPUP RID_GRAPHIC_TEXTOBJ_POPUP
RID_DRAW_GEOMOBJ_POPUP RID_GRAPHIC_GEOMOBJ_POPUP
RID_DRAW_CUSTOMSHAPE_POPUP RID_GRAPHIC_CUSTOMSHAPE_POPUP
RID_DRAW_3DSCENE_POPUP RID_GRAPHIC_3DSCENE_POPUP
RID_DRAW_3DSCENE2_POPUP RID_GRAPHIC_3DSCENE2_POPUP
RID_DRAW_3DOBJ_POPUP RID_GRAPHIC_3DOBJ_POPUP
RID_DRAW_GROUPOBJ_POPUP RID_GRAPHIC_GROUPOBJ_POPUP
RID_DRAW_LINEOBJ_POPUP RID_GRAPHIC_LINEOBJ_POPUP
RID_DRAW_EDGEOBJ_POPUP RID_GRAPHIC_EDGEOBJ_POPUP
RID_DRAW_MEASUREOBJ_POPUP RID_GRAPHIC_MEASUREOBJ_POPUP
RID_DRAW_POLYLINEOBJ_POPUP RID_GRAPHIC_POLYLINEOBJ_POPUP
RID_DRAW_NOSEL_POPUP RID_GRAPHIC_NOSEL_POPUP
RID_DRAW_MULTISELECTION_POPUP RID_GRAPHIC_MULTISELECTION_POPUP
RID_DRAW_GRAPHIC_POPUP RID_GRAPHIC_GRAPHIC_POPUP
RID_DRAW_OLE2_POPUP RID_GRAPHIC_OLE2_POPUP
RID_DRAW_PAGETAB_POPUP RID_GRAPHIC_PAGETAB_POPUP
RID_DRAW_MEDIA_POPUP RID_GRAPHIC_MEDIA_POPUP
RID_DRAW_TABLE_POPUP RID_GRAPHIC_TABLE_POPUP

The following menus do not use the generic SFX2 framework, the use VCL directly:

Non SFX modules

ToDo

Context menu implementation

ToDo: describe how context menu interception is currently implemented in both sfx2-based and non-sfx2-based modules.




  1. http://hg.services.openoffice.org/DEV300/file/DEV300_m85/sc/source/ui/drawfunc/mediash.cxx#l63 http://hg.services.openoffice.org/DEV300/file/DEV300_m85/sc/source/ui/src/scstring.src#l726
Personal tools