Intercepting Context Menus
A context menu is displayed when an object is right clicked. Typically, a context menu has context dependent functions to manipulate the selected object, such as cut, copy and paste. Developers can intercept context menus before they are displayed to cancel the execution of a context menu, add, delete, or modify the menu by replacing context menu entries or complete sub menus. It is possible to provide new customized context menus.
Context menu interception is implemented by the observer pattern. This pattern defines a one-to-many dependency between objects, so that when an object changes state, all its dependents are notified. The implementation supports more than one interceptor. The root access point for intercepting context menus is a com.sun.star.frame.Controller object. The controller implements the interface com.sun.star.ui.XContextMenuInterception to support context menu interception.
Register and Remove an Interceptor
The com.sun.star.ui.XContextMenuInterception interface enables the developer to register and remove the interceptor code. When an interceptor is registered, it is notified whenever a context menu is about to be executed. Registering an interceptor adds it to the front of the interceptor chain, so that it is called first. The order of removals is arbitrary. It is not necessary to remove the interceptor that registered last.
Writing an Interceptor
Notification
A context menu interceptor implements the com.sun.star.ui.XContextMenuInterceptor interface. This interface has one function that is called by the responsible controller whenever a context menu is about to be executed.
ContextMenuInterceptorAction notifyContextMenuExecute ( [in] ContextMenuExecuteEvent aEvent)
The com.sun.star.ui.ContextMenuExecuteEvent is a struct that holds all the important information for an interceptor.
Members of com.sun.star.ui.ContextMenuExecuteEvent | |
---|---|
ExecutePosition | com.sun.star.awt.Point. Contains the position the context menu will be executed. |
SourceWindow | com.sun.star.awt.XWindow. Contains the window where the context menu has been requested. |
ActionTriggerContainer | com.sun.star.container.XIndexContainer. The structure of the intercepted context menu. The member implements the com.sun.star.ui.ActionTriggerContainer service. |
Selection | com.sun.star.view.XSelectionSupplier. Provides the current selection inside the source window. |
Querying a Menu Structure
The ActionTriggerContainer member is an indexed container of context menu entries, where each menu entry is a property set. It implements the com.sun.star.ui.ActionTriggerContainer service. The interface com.sun.star.container.XIndexContainer directly accesses the intercepted context menu structure through methods to access, insert, remove and replace menu entries.
All elements in an ActionTriggerContainer
member support the com.sun.star.beans.XPropertySet interface to get and set property values. There are two different types of menu entries with different sets of properties:
Type of Menu Entry | Service Name |
---|---|
Menu entry | "com.sun.star.ui.ActionTrigger "
|
Separator | "com.sun.star.ui.ActionTriggerSeparator "
|
It is essential to determine the type of each menu entry be querying it for the interface com.sun.star.lang.XServiceInfo and calling
boolean supportsService ( [in] string ServiceName )
The following example shows a small helper class to determine the correct menu entry type.
// A helper class to determine the menu element type
public class MenuElement
{
static public boolean IsMenuEntry( com.sun.star.beans.XPropertySet xMenuElement ) {
com.sun.star.lang.XServiceInfo xServiceInfo =
(com.sun.star.lang.XServiceInfo)UnoRuntime.queryInterface(
com.sun.star.lang.XServiceInfo.class, xMenuElement );
return xServiceInfo.supportsService( "com.sun.star.ui.ActionTrigger" );
}
static public boolean IsMenuSeparator( com.sun.star.beans.XPropertySet xMenuElement ) { com.sun.star.lang.XServiceInfo xServiceInfo =
(com.sun.star.lang.XServiceInfo)UnoRuntime.queryInterface(
com.sun.star.lang.XServiceInfo.class, xMenuElement );
return xServiceInfo.supportsService( "com.sun.star.ui.ActionTriggerSeparator" );
}
}
Figure 4.1: Determine the menu element type
The com.sun.star.ui.ActionTrigger service supported by selectable menu entries has the following properties:
Properties of com.sun.star.ui.ActionTrigger | |
---|---|
Text | string. Contains the text of the label of the menu entry. |
CommandURL | string. Contains the command URL that defines which function will be executed if the menu entry is selected by the user. |
HelpURL | string. This optional property contains a help URL that points to the help text. |
Image | com.sun.star.awt.XBitmap. This property contains an image that is shown left of the menu label. The use is optional so that no image is used if this member is not initialized. |
SubContainer | com.sun.star.container.XIndexContainer. This property contains an optional sub menu. |
The com.sun.star.ui.ActionTriggerSeparator service defines only one optional property:
Property of com.sun.star.ui.ActionTriggerSeparator | |
---|---|
SeparatorType | com.sun.star.ui.ActionTriggerSeparatorType. Specifies a certain type of a separator. Currently the following types are possible:
|
Changing a Menu
It is possible to accomplish certain tasks without implementing code in a context menu interceptor, such as preventing a context menu from being activated. Normally, a context menu is changed to provide additional functions to the user.
As previously discussed, the context menu structure is queried through the ActionTriggerContainer member that is part of the com.sun.star.ui.ContextMenuExecuteEvent structure. The com.sun.star.ui.ActionTriggerContainer service has an additional interface com.sun.star.lang.XMultiServiceFactory that creates [IDL:com.sun.star.ui.ActionTriggerContainer], ActionTriggerContainer and com.sun.star.ui.ActionTriggerSeparator objects. These objects are used to extend a context menu.
The com.sun.star.lang.XMultiServiceFactory implementation of the ActionTriggerContainer implementation supports the following strings:
String | Object |
---|---|
"com.sun.star.ui.ActionTrigger" | Creates a normal menu entry. |
"com.sun.star.ui.ActionTriggerContainer" | Creates an empty sub menu1 . |
"com.sun.star.ui.ActionTriggerSeparator" | Creates an unspecified separator2 . |
1 A sub menu cannot exist by itself. It has to be inserted into a com.sun.star.ui.ActionTrigger !
2 The separator has no special type. It is the responsibility of the concrete implementation to render an unspecified separator.
Finishing Interception
Every interceptor that is called directs the controller how it continues after the call returns. The enumeration com.sun.star.ui.ContextMenuInterceptorAction defines the possible return values.
Values of com.sun.star.ui.ContextMenuInterceptorAction | |
---|---|
IGNORED
|
Called object has ignored the call. The next registered com.sun.star.ui.XContextMenuInterceptor should be notified. |
CANCELLED
|
The context menu must not be executed. No remaining interceptor will be called. |
EXECUTE_MODIFIED
|
The context menu has been modified and should be executed without notifying the next registered com.sun.star.ui.XContextMenuInterceptor. |
CONTINUE_MODIFIED
|
The context menu was modified by the called object. The next registered com.sun.star.ui.XContextMenuInterceptor should be notified. |
The following example shows a context menu interceptor that adds a a sub menu to a menu that has been intercepted at a controller, where this com.sun.star.ui.XContextMenuInterceptor has been registered. This sub menu is inserted into the context menu at the topmost position. It provides help functions to the user that are reachable through the menu Help.
import com.sun.star.ui.*;
import com.sun.star.lang.XMultiServiceFactory;
import com.sun.star.beans.XPropertySet;
import com.sun.star.container.XIndexContainer;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.uno.Exception;
import com.sun.star.beans.UnknownPropertyException;
import com.sun.star.lang.IllegalArgumentException;
public class ContextMenuInterceptor implements XContextMenuInterceptor {
public ContextMenuInterceptorAction notifyContextMenuExecute(
com.sun.star.ui.ContextMenuExecuteEvent aEvent ) throws RuntimeException {
try {
// Retrieve context menu container and query for service factory to
// create sub menus, menu entries and separators
com.sun.star.container.XIndexContainer xContextMenu = aEvent.ActionTriggerContainer;
com.sun.star.lang.XMultiServiceFactory xMenuElementFactory =
(com.sun.star.lang.XMultiServiceFactory)UnoRuntime.queryInterface(
com.sun.star.lang.XMultiServiceFactory.class, xContextMenu );
if ( xMenuElementFactory != null ) {
// create root menu entry for sub menu and sub menu
com.sun.star.beans.XPropertySet xRootMenuEntry =
(XPropertySet)UnoRuntime.queryInterface(
com.sun.star.beans.XPropertySet.class,
xMenuElementFactory.createInstance ( "com.sun.star.ui.ActionTrigger" ));
// create a line separator for our new help sub menu
com.sun.star.beans.XPropertySet xSeparator =
(com.sun.star.beans.XPropertySet)UnoRuntime.queryInterface(
com.sun.star.beans.XPropertySet.class,
xMenuElementFactory.createInstance( "com.sun.star.ui.ActionTriggerSeparator" ) );
Short aSeparatorType = new Short( ActionTriggerSeparatorType.LINE );
xSeparator.setPropertyValue( "SeparatorType", (Object)aSeparatorType );
// query sub menu for index container to get access
com.sun.star.container.XIndexContainer xSubMenuContainer =
(com.sun.star.container.XIndexContainer)UnoRuntime.queryInterface(
com.sun.star.container.XIndexContainer.class,
xMenuElementFactory.createInstance(
"com.sun.star.ui.ActionTriggerContainer" ));
// intialize root menu entry "Help"
xRootMenuEntry.setPropertyValue( "Text", new String( "Help" ));
xRootMenuEntry.setPropertyValue( "CommandURL", new String( "slot:5410" ));
xRootMenuEntry.setPropertyValue( "HelpURL", new String( "5410" ));
xRootMenuEntry.setPropertyValue( "SubContainer", (Object)xSubMenuContainer );
// create menu entries for the new sub menu
// intialize help/content menu entry
// entry "Content"
XPropertySet xMenuEntry = (XPropertySet)UnoRuntime.queryInterface(
XPropertySet.class, xMenuElementFactory.createInstance (
"com.sun.star.ui.ActionTrigger" ));
xMenuEntry.setPropertyValue( "Text", new String( "Content" ));
xMenuEntry.setPropertyValue( "CommandURL", new String( "slot:5401" ));
xMenuEntry.setPropertyValue( "HelpURL", new String( "5401" ));
// insert menu entry to sub menu
xSubMenuContainer.insertByIndex ( 0, (Object)xMenuEntry );
// intialize help/help agent
// entry "Help Agent"
xMenuEntry = (com.sun.star.beans.XPropertySet)UnoRuntime.queryInterface(
com.sun.star.beans.XPropertySet.class,
xMenuElementFactory.createInstance (
"com.sun.star.ui.ActionTrigger" ));
xMenuEntry.setPropertyValue( "Text", new String( "Help Agent" ));
xMenuEntry.setPropertyValue( "CommandURL", new String( "slot:5962" ));
xMenuEntry.setPropertyValue( "HelpURL", new String( "5962" ));
// insert menu entry to sub menu
xSubMenuContainer.insertByIndex( 1, (Object)xMenuEntry );
// intialize help/tips
// entry "Tips"
xMenuEntry = (com.sun.star.beans.XPropertySet)UnoRuntime.queryInterface(
com.sun.star.beans.XPropertySet.class,
xMenuElementFactory.createInstance(
"com.sun.star.ui.ActionTrigger" ));
xMenuEntry.setPropertyValue( "Text", new String( "Tips" ));
xMenuEntry.setPropertyValue( "CommandURL", new String( "slot:5404" ));
xMenuEntry.setPropertyValue( "HelpURL", new String( "5404" ));
// insert menu entry to sub menu
xSubMenuContainer.insertByIndex ( 2, (Object)xMenuEntry );
// add separator into the given context menu
xContextMenu.insertByIndex ( 0, (Object)xSeparator );
// add new sub menu into the given context menu
xContextMenu.insertByIndex ( 0, (Object)xRootMenuEntry );
// The controller should execute the modified context menu and stop notifying other
// interceptors.
return com.sun.star.ui.ContextMenuInterceptorAction.EXECUTE_MODIFIED ;
}
}
catch ( com.sun.star.beans.UnknownPropertyException ex ) {
// do something useful
// we used a unknown property
}
catch ( com.sun.star.lang.IndexOutOfBoundsException ex ) {
// do something useful
// we used an invalid index for accessing a container
}
catch ( com.sun.star.uno.Exception ex ) {
// something strange has happend!
}
catch ( java.lang.Throwable ex ) {
// catch java exceptions - do something useful
}
return com.sun.star.ui.ContextMenuInterceptorAction.IGNORED;
}
}
Content on this page is licensed under the Public Documentation License (PDL). |