Notice: This Wiki is now read only and edits are no longer possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.
Difference between revisions of "Menu Contributions"
(→Example Matrix) |
(→Add ProblemView menus) |
||
Line 45: | Line 45: | ||
= Add ProblemView menus = | = Add ProblemView menus = | ||
− | Add the Problems view menus. | + | Add the Problems view menus. The problems view has one toolbar command and in the view menu, 3 actions and 2 dynamic submenus. |
− | + | ||
= File->Exit = | = File->Exit = |
Revision as of 19:39, 18 October 2006
Placement examples that try to descript the old to new way.
Contents
- 1 Example Matrix
- 2 Add ProblemView menus
- 3 File->Exit
- 4 Edit->Copy
- 5 Global toolbar->Save
- 6 Global toolbar->Open Type
- 7 Global toolbar->Toggle Mark Occurrences
- 8 Search->Registry Search
- 9 Widget in the main toolbar
- 10 Edit->Undo relabel action
- 11 Search->Registry Search editor action
- 12 Search->Registry Search programmatic editor action
- 13 Add View submenu and item
- 14 Text editor popup action
- 15 IFile object contribution
- 16 Product removes Search Registry
- 17 Dynamic Previous Searches submenu
- 18 Dynamic Previous Searches editors group
- 19 Added For Paul
Example Matrix
Example | Location | visible when | enabled when | defined by | placed by | handled by | comments |
---|---|---|---|---|---|---|---|
Add ProblemView menus | view menu | always | always | ViewPart & IActionBars | ViewPart & IActionBars | SampleViewAction | |
File->Exit | global menu | always | always | ActionFactory | WorkbenchActionBuilder | QuitAction | |
Edit->Copy | global menu | always | there is an enabled handler | Workbench | IDEApplication | active part (what about Trim??) | enablement determined by handler |
Global toolbar->Save | global toolbar | always | the active part needs saving | Workbench | IDEApplication | Workbench | |
Global toolbar->Open Type | global toolbar | Java Navigation action set is enabled | Java Navigation action set is enabled | JDT UI | JDT UI | JDT UI | |
Global toolbar->Toggle Mark Occurrences | global (editor) toolbar | any Java editor is active | any Java editor is active | all Java Editors | all Java Editors | active Java Editor | push button state is updated based on active editor |
Search->Registry Search | global menu | Registry Search action set is enabled | Registry Search action set is enabled | plugin | actionSet | RegistrySearchAction | |
Widget in the main toolbar | global toolbar | Registry Search action set is enabled | Registry Search action set is enabled | plugin | actionSet | RegistrySearchAction | |
Edit->Undo relabel action | global menu | always | always | ActionFactory | WorkbenchActionBuilder | LabelRetargetAction | |
Search->Registry Search editor action | global (editor) menu | any registry editor is active | any registry editor is active | org.eclipse.ui.editorActions | org.eclipse.ui.editorActions | RegistrySearchAction | |
Search->Registry Search programmatic editor action | global (editor) menu | any registry editor is active | any registry editor is active | registry editor action bar contributor | registry editor action bar contributor | RegistrySearchAction | |
Add View submenu and item | view menu | always | always | org.eclipse.ui.viewActions | org.eclipse.ui.viewActions | SampleViewAction | |
Text editor popup action | text editor context menu | always | always | org.eclipse.ui.popupMenus | org.eclipse.ui.popupMenus | SampleContributionAction | |
IFile object contribution | all context menus | selection is an IFile | always | org.eclipse.ui.popupMenus | org.eclipse.ui.popupMenus | SampleContributionAction | |
Product removes Search Registry | global menu | never | always | ApplicationWorkbenchWindowAdvisor | N/A | menu service | this cannot easily be done |
Dynamic Previous Searches submenu | global menu | always | always | org.eclipse.ui.actionSets | org.eclipse.ui.actionSets | IMenuCreator | |
Dynamic Previous Searches editors group | global menu | always | always | N/A | N/A | IDynamicMenu |
Add the Problems view menus. The problems view has one toolbar command and in the view menu, 3 actions and 2 dynamic submenus.
File->Exit
Current RCP using ActionBarAdvisor
The ApplicationActionBarAdvisor should add the exit menu. The QuitAction is already coded and the exit command is already defined.
// create the file menu MenuManager menu = new MenuManager(IDEWorkbenchMessages.Workbench_file, IWorkbenchActionConstants.M_FILE); // ... quitAction = ActionFactory.QUIT.create(window); register(quitAction); ActionContributionItem quitItem = new ActionContributionItem(quitAction); quitItem.setVisible(!"carbon".equals(SWT.getPlatform())); //$NON-NLS-1$ menu.add(quitItem);
Current RCP or Eclipse plugin using an actionSet
Using an actionSet, you can also place the action in the main menu.
<extension point="org.eclipse.ui.actionSets"> <actionSet id="org.eclipse.ui.file.exitActions" label="Exit Actions" visible="true"> <action class="org.eclipse.ui.internal.QuitAction" id="quit" definitionId="org.eclipse.ui.file.exit" label="E&xit" menubarPath="file/fileEnd" tooltip="Exit Eclipse"> </action> </actionSet> </extension>
With the new structure, you would have to turn the action into a handler.
<extension point="org.eclipse.ui.handlers"> <handler commandId="org.eclipse.ui.file.exit" class="org.eclipse.ui.internal.QuitHandler"/> </extension>
Then you can place it in the menu:
<extension point="org.eclipse.ui.menus"> <item commandId="org.eclipse.ui.file.exit" mnemonic="x" id="org.eclipse.ui.file.exit.menu"> <location type="menu"> <menu id="file"/> <order after="fileEnd"/> </location> </item> </extension>
You can globally place your exit menu in the file menu, or tie it to an actionSet using the <visibleWhen/> clause.
Edit->Copy
Some Copy Stuff.
Global toolbar->Save
save
Global toolbar->Open Type
open type
Global toolbar->Toggle Mark Occurrences
toggle
Search->Registry Search
Provide a basic action set. You have 2 actions, Registry Find and Registry Replace, and you want to add them to the "dialog" section of the Search menu.
Assume you have 2 commands defined, com.example.registry.search.find
(Registry Find) and com.example.registry.search.replace
(Registry Replace), and you want to add them to the main Search menu at org.eclipse.search.menu/dialogGroup
. Your commands already have their images defined in the org.eclipse.ui.commandImages
extension point.
Define the action set:
<context description="The collection of registry search actions" id="com.example.registry.search.actionSet" name="Registry Search Action Set" parentId="org.eclipse.ui.contexts.actionSet"> </context>
And here is a possible view of the menus extension point:
<extension point="org.eclipse.ui.menus"> <item commandId="com.example.registry.search.find" mnemonic="d" id="com.example.registry.search.find.menu"> <location type="menu"> <menu id="org.eclipse.search.menu"/> <order after="dialogGroup"/> </location> <visibleWhen> <with variable="activeContexts"> <iterator operator="or"> <equals value="com.example.registry.search.actionSet"/> </iterator> </with> </visibleWhen> </item> <item commandId="com.example.registry.search.replace" mnemonic="p" id="com.example.registry.search.replace.menu"> <location type="menu"> <menu id="org.eclipse.search.menu"/> <order after="com.example.registry.search.find.menu"/> </location> <visibleWhen> <with variable="activeContexts"> <iterator operator="or"> <equals value="com.example.registry.search.actionSet"/> </iterator> </with> </visibleWhen> </item> </extension>
Hmmmm, so to programmatically do this, you would have to go through the IMenuService.
ICommandService commandServ = (ICommandService) getSite().getWindow().getService(ICommandService.class); IMenuService menuServ = (IMenuService) getSite().getWindow().getService(IMenuService.class); Command findCmd = commandServ.getCommand("com.example.registry.search.find"); SLocation findLocation = new SLocation(SBar.MENU, "org.eclipse.search.menu"); findLocation.setOrder(new SOrder(SOrder.AFTER, "dialogGroup")); SItem findItem = menuServ.getItem(new SLocation(SBar.MENU, "org.eclipse.search.menu/com.example.registry.search.find.menu")); findItem.define(findCmd, findLocation, "d"); menuServ.contribute(findItem, new ActionSetExpression("com.example.registry.search.actionSet")); Command replaceCmd = commandServ.getCommand("com.example.registry.search.replace"); SLocation replaceLocation = new SLocation(SBar.MENU, "org.eclipse.search.menu"); replaceLocation.setOrder(new SOrder(SOrder.AFTER, "com.example.registry.search.find.menu")); SItem replaceItem = menuServ.getItem(new SLocation(SBar.MENU, "org.eclipse.search.menu/com.example.registry.search.replace.menu")); replaceItem.define(replaceCmd, replaceLocation, "p"); menuServ.contribute(replaceItem, new ActionSetExpression("com.example.registry.search.actionSet"));
Widget in the main toolbar
You can use the extension point to contribute a control to the toolbar. You use the <widget/> element instead of the <item/> element.
<extension point="org.eclipse.ui.menus"> <widget class="com.example.registry.search.SearchBar" id="com.example.registry.search.find.searchbar"> <location type="toolbar"> <menu id="org.eclipse.search.toolbar"/> </location> <visibleWhen> <with variable="activeContexts"> <iterator operator="or"> <equals value="com.example.registry.search.actionSet"/> </iterator> </with> </visibleWhen> </widget> </extension>
The widget class must implement org.eclipse.ui.menus.IWorkbenchWidget, and provide fill(Composite parent)
for a toolbar.
I'm not sure how far to go with IWorkbenchWidget. We already use this interface for adding controls to the trim, and there are open bug requests about adding arbitrary controls to the toolbars.
Will menus take arbitrary controls?
Edit->Undo relabel action
Like the Undo action, sometimes menu items would want to allow their label to be updated. This is currently handled through the Command objects and the handlers. IMenuStateIds and INamedHandleStateIds define some states that we currently support.
This can be used to update the menu item label:
<extension point="org.eclipse.ui.commands"> <command description="Targetted Undo Command" id="org.eclipse.ui.commands.targettedUndo" name="Undo"> <state class="org.eclipse.jface.menus.TextState" id="NAME"/> </command> </extension>
It's placed in the menus just like any other command:
<extension point="org.eclipse.ui.menus"> <item commandId="org.eclipse.ui.commands.targettedUndo" mnemonic="u" id="org.eclipse.ui.commands.undo"> <location type="menu"> <menu id="edit"/> <order after="edit.ext"/> </location> </item> </extension>
As a handler becomes active and implement IObjectWithState (for example, derives from AbstractHandlerWithState) it is notified about any states that the handler's command contains. The states can be updated at that time.
class FileDeleteUndoHandler extends AbstractHandlerWithState { public final void handleStateChange(final State state, final Object oldValue) { if (INamedHandleStateIds.NAME.equals(state.getId()) && oldValue==null) { state.setValue("Undo File Delete"); } } public final Object execute(final ExecutionEvent event) { // undo a file delete using EFS ... very cool return null; } }
Search->Registry Search editor action
This should basically be the same as Search->Registry Search with a different visible when clause.
<visibleWhen> <with variable="activeEditorId"> <equals value="com.example.registry.RegistryEditor"/> </with> </visibleWhen>
So programmatically, that just translates into a different visible when expression:
menuServ.contribute(editorFindItem, new ActiveEditorIdExpression("com.example.registry.RegistryEditor"));
The menu items must be uniquely identified by their id. Since they only have one location, they can only have one activation in the service at a time.
Search->Registry Search programmatic editor action
Programmatically we have to take the editor action handlers into account.
One of the advantages of EditorActionBars is the lifecycle of the actions that are added. They're created when the first editor of that type is loaded and exist until the last editor of that type is closed.
Our service hierarchy has 2 levels, IWorkbenchWindow and IPartSite. Handlers registered with IWorkbenchWindow are active as long as the window is active, and are disposed when the window is disposed. Handlers registered with IPartSite are active and available as long as that specific part is active and available. When the part is closed, the handlers are disposed.
Two possibilities are:
1. Provide a service locator for the in-between case. Tied to a part type. The service locator expression makes the activation correct and the service locator disposes of them correctly. Basically, we would make IActionBars returned from each IPartSite a service locator as well.
2. Move these actions up to the IWorkbenchWindow level. With the correct expression the handler activation would be correct. But once created they would live as long as the workbench.
View actions have to specify their menus as they are self contained.
<command id="z.ex.editor.commands.SampleViewAction" name="Sample View Action" description="Sample View Action command"/>
<extension point="org.eclipse.ui.commandImages"> <image commandId="z.ex.editor.commands.SampleViewAction" icon="icons/sample.gif"/> </extension>
Placing the action (which is specifically a menu or button linked to a command) can be accomplished with the org.eclipse.ui.menus extension point.
<extension point="org.eclipse.ui.menus"> <menu id="z.ex.view.SampleViewMenu" mnemonic="M" label="Sample Menu"> <location type="viewMenu"> <part partId="z.ex.view.keybindings.views.SampleView"/> </location> </menu> <group groupId="z.ex.view.SampleViewGroup" separatorsVisible="false"> <location type="viewMenu"> <part partId="z.ex.view.keybindings.views.SampleView"> <menu id="z.ex.view.SampleViewMenu"/> </part> </location> </group> <item commandId="z.ex.editor.commands.SampleViewAction" mnemonic="V" id="z.ex.view.SampleViewAction"> <location type="viewMenu"> <part partId="z.ex.view.keybindings.views.SampleView"> <menu id="z.ex.view.SampleViewMenu"/> </part> <order after="z.ex.view.SampleViewGroup"/> </location> </item> </extension>
Hmmmm, so to programmatically do this, you would have to go through the IMenuService.
ICommandService commandServ = (ICommandService) getSite().getWindow().getService(ICommandService.class); IMenuService menuServ = (IMenuService) getSite().getWindow().getService(IMenuService.class); SMenu viewMenu = menuServ.getMenu(new SLocation(SBar.VIEW_MENU, "z.ex.view.keybindings.views.SampleView/z.ex.view.SampleViewMenu")); viewMenu.define("Sample Menu", new SLocation(SBar.VIEW_MENU, "z.ex.view.keybindings.views.SampleView"), "M"); SGroup viewGroup = menuServ.getGroup(new SLocation(SBar.VIEW_MENU, "z.ex.view.keybindings.views.SampleView/z.ex.view.SampleViewMenu/z.ex.view.SampleViewGroup")); viewGroup.define(new SLocation(SBar.VIEW_MENU, "z.ex.view.keybindings.views.SampleView/z.ex.view.SampleViewMenu", false); Command viewCmd = commandServ.getCommand("z.ex.editor.commands.SampleViewAction"); SLocation viewLocation = new SLocation(SBar.VIEW_MENU, "z.ex.view.keybindings.views.SampleView/z.ex.view.SampleViewMenu") viewLocation.setOrder(new SOrder(SOrder.AFTER, "z.ex.view.SampleViewGroup")); SItem viewItem = menuServ.getItem(new SLocation(SBar.VIEW_MENU, "z.ex.view.keybindings.views.SampleView/z.ex.view.SampleViewMenu/z.ex.view.SampleViewAction.menu")); viewItem.define(viewCmd, viewLocation, "V"); menuServ.contribute(viewItem);
Text editor popup action
Popups can be targetted at any registered context menu, or at all of them
<command id="z.ex.view.commands.SampleContributionAction" name="Sample Context Action" description="Sample Context Action command"/>
<extension point="org.eclipse.ui.commandImages"> <image commandId="z.ex.view.commands.SampleContributionAction" icon="icons/sample.gif"/> </extension>
Placing the action (which is specifically a menu or button linked to a command) can be accomplished with the org.eclipse.ui.menus extension point.
<extension point="org.eclipse.ui.menus"> <item commandId="z.ex.view.commands.SampleContributionAction" mnemonic="C" id="z.ex.objectContribution.menu"> <location type="contextMenu"> <menu id="#EditorContext"/> <order after="z.ex.editor.contextGroup"/> </location> </item> </extension>
Hmmmm, so to programmatically do this, you would have to go through the IMenuService.
Command contextCmd = commandServ.getCommand("z.ex.view.commands.SampleContributionAction"); SLocation contextLocation = new SLocation(SBar.CONTEXT_MENU, "#EditorContext"); contextLocation.setOrder(new SOrder(SOrder.AFTER, "z.ex.editor.contextGroup")); SItem contextItem = menuServ.getItem(new SLocation(SBar.CONTEXT_MENU, "#EditorContext/z.ex.objectContribution.menu")); contextItem.define(contextCmd, contextLocation, "C"); menuServ.contribute(contextItem);
IFile object contribution
There will be a reserved popup ID, "org.eclipse.ui.menus.context.any" that will allow contributions to any popup menu.
<extension point="org.eclipse.ui.menus"> <item commandId="z.ex.view.commands.SampleContributionAction" mnemonic="C" id="z.ex.objectContribution.menu"> <location type="contextMenu"> <menu id="org.eclipse.ui.menus.context.any"/> <order after="additions"/> </location> <visibleWhen> <with variable="selection"> <adapt type="org.eclipse.core.resources.IFile"/> </with> </visibleWhen> </item> </extension>
It's probably that the default variable for core expression evaluations would be selection, so you wouldn't need the <with/> clause. There would probably also be a short-hand to tie the visibility to an active handler. Maybe <visibleWhen handler="true"/>
It can be used programmatically.
Command contextCmd = commandServ.getCommand("z.ex.view.commands.SampleContributionAction"); SLocation contextLocation = new SLocation(SBar.CONTEXT_MENU, "org.eclipse.ui.menus.context.any"); contextLocation.setOrder(new SOrder(SOrder.AFTER, "additions")); SItem contextItem = menuServ.getItem(new SLocation(SBar.CONTEXT_MENU, "org.eclipse.ui.menus.context.any/z.ex.objectContribution.menu")); contextItem.define(contextCmd, contextLocation, "C"); menuServ.contribute(contextItem, new SelectionAdaptExpression("org.eclipse.core.resources.IFile"));
The contribution should look exactly the same as a normal contribution.
Product removes Search Registry
It should be possible to override the visibility of menu contributions.
IMenuService menuService = (IMenuService) PlatformUI.getWorkbench().getService(IMenuService.class); SItem findItem = menuServ.getItem(new SLocation(SBar.MENU, "org.eclipse.search.menu/com.example.registry.search.find.menu")); menuService.addOverride(findItem, new OverrideAdapter() { public Boolean isVisible() { return Boolean.FALSE; } });
The idea is to provide this ability at the product level. For example, an RCP app should be able to hide any menu items that it doesn't want but picked up through the inclusion of a plugin.
That implies that it might not be part of the general IMenuService interface. Or (taking a page from the IExtensionRegistry) it might use a token that's available from the WorkbenchWindowAdvisor so that products can use the interface, or even expose the ability to their users.
If it returns null
the next level of visibility is evaluated. The null
case is to keep it consistent with other overrides.
You want to add a dynamic "Previous Searches" submenu to the main Search menu.
<extension point="org.eclipse.ui.menus"> <menu label="Previous Searches" mnemonic="c" id="com.example.registry.search.recent.menu"> <dynamic class="com.example.registry.search.RecentMenu"/> <location type="menu"> <menu id="org.eclipse.search.menu"/> <order after="additions"/> </location> </item> </extension>
You can programmatically accomplish the same thing:
ICommandService commandServ = (ICommandService) getSite().getWindow().getService(ICommandService.class); IMenuService menuServ = (IMenuService) getSite().getWindow().getService(IMenuService.class); SMenu recentMenu = menuServ.getMenu(new SLocation(SBar.MENU, "org.eclipse.search.menu/com.example.registry.search.recent.menu")); SLocation menuLocation = new SLocation(SBar.MENU, "org.eclipse.search.menu"); menuLocation.setOrder(new SOrder(SOrder.AFTER, "additions")); recentMenu.define("Previous Searches", menuLocation, "c", new RecentMenu());
When your menu is about to show, you should get the callback:
public class RecentMenu implements IDynamicMenu { public void aboutToShow(IMenuCollection menu) { menu.clear(); String[] searchIds = getSearchVew().getPreviousSearches(); Command findCmd = commandServ.getCommand("com.example.registry.search.find"); SLocation findLocation = new SLocation(SBar.MENU, "org.eclipse.search.menu/com.example.registry.search.recent.menu"); for (int i=0; i<searchIds.length && i<4; i++) { SItem item = menuServ.getItem(new SLocation(SBar.MENU, "org.eclipse.search.menu/com.example.registry.search.recent.menu/recentItem" + i)); item.undefine(); ParameterizedCommand parmFindCmd = ....; // findCmd + the searchId parameter item.define(parmFindCmd, findLocation); menu.add(item); } } public SearchViewPart getSearchView() { return ....; } }
Dynamic Previous Searches editors group
You can have a group dynamically insert elements as a menu is shown.
<extension point="org.eclipse.ui.menus"> <group groupId="com.example.registry.search.editors.menu" separatorsVisible="true"> <dynamic class="com.example.registry.search.RecentSearchEditors"/> <location type="menu"> <menu id="file"/> <order after="mru"/> </location> </group> </extension>
When the File menu is about to show, you will be called with your group IMenuCollection (not the entire File menu). But basically, it looks the same as the dynamic menu case.
public class RecentSearchEditors implements IDynamicMenu { public void aboutToShow(IMenuCollection menu) { menu.clear(); String[] editorIds = getSearchVew().getPreviousOpenEditors(); Command openCmd = commandServ.getCommand("com.example.registry.search.openEditor"); SLocation fileLocation = new SLocation(SBar.MENU, "file"); for (int i=0; i<editorIds.length && i<4; i++) { SItem item = menuServ.getItem(new SLocation(SBar.MENU, "file/searchOpenEditor" + i)); item.undefine(); ParameterizedCommand parmOpenCmd = ....; // openCmd + the editorsId parameter item.define(parmOpenCmd, fileLocation); menu.add(item); } } public SearchViewPart getSearchView() { return ....; } }
Added For Paul
<menu name="Window" id="window"> <itemRef id="newWindow"> <itemRef id="newEditor"> <seperator id="seperator1"> <menu name="Open Perspective" id="openPerspective" class="generatePerspectivesMenu"/> <menu name="Show View" id="showView"/> <seperator id="seperator1"> <itemRef id="customizePerspective"> <itemRef id="savePerspective"> <itemRef id="closePerspective"> <itemRef id="closeAllPerspectives"> <seperator id="seperator3"> <menu name="Navigation" id="navigation"> <seperator id="seperator4"> </menu> </menu> <menu name="Working Sets" id="workingSets" after="window/navigation"> <dynamic class="windowworkingsets"/> <itemRef id="editWorkingSets"/> </menu> <toolbar id="workingSet"> <itemRef id="editWorkingSets"/> </toolbar> <itemRef id="hideToolbars" before="window/seperator1">