Difference between revisions of "Menu Contributions"

From Eclipsepedia

Jump to: navigation, search
m (Menu Item Placement Examples moved to Menu Contributions)
m (Fixed a typo)
 
(48 intermediate revisions by 11 users not shown)
Line 5: Line 5:
 
The 4 extension points that deal with menus now org.eclipse.ui.actionSets, org.eclipse.ui.viewActions, org.eclipse.ui.editorActions, and org.eclipse.ui.popupMenus specify both menu placement and their visibility criteria.  In the new menu mechanism they are separate concepts, placement and visibility.
 
The 4 extension points that deal with menus now org.eclipse.ui.actionSets, org.eclipse.ui.viewActions, org.eclipse.ui.editorActions, and org.eclipse.ui.popupMenus specify both menu placement and their visibility criteria.  In the new menu mechanism they are separate concepts, placement and visibility.
  
= Work =
+
= Example Matrix =
  
This is a work list Eric and I threw together.
+
A (hopefully) growing list of menu contribution examples.
 
+
== Available in 3.3M4 ==
+
 
+
The basic menu API will be available in 3.3M4.  It includes both declarative '''org.eclipse.ui.menus''' extension point with core expression support for visibility, and a programmatic interface accessed through the <code>IMenuService</code>.
+
 
+
 
+
We support contributing to the main menu, and the view menu, view toolbar, and any IDed context menu.  We support contributing to existing toolbars in the main coolbar, and contributing trim widgets.
+
 
+
Programmatically we support the following types of contributions:
+
*MenuManager
+
*CommandContributionItem
+
*CompoundContributionItem
+
*ControlContribution (in 3.3M5)
+
*Separator
+
*GroupMarker
+
 
+
There are some specific mappings of elements and attributes on [[Menus Extension Mapping]].
+
 
+
== Available in 3.3M5 ==
+
 
+
There is an example of the RCP Mail application template updated for 3.3M5 and converted to use the org.eclipse.ui.menus extension point as much as possible at [http://dev.eclipse.org/viewcvs/index.cgi/platform-ui-home/R3_3/contributions-proposal/ Contribution Example].
+
 
+
 
+
* http://www.eclipse.org/eclipse/platform-core/images/small_check.gif changing the menu item or tool item state from a handler, like updating the label or tooltip or checked state.  Commands can contain <state/> elements, but that is not appropriate to use for providing feedback to the user.  This will be done by adapting a callback provided by the UI element.
+
* http://www.eclipse.org/eclipse/platform-core/images/small_check.gif the <separator/> element should have a '''name''' not an '''id'''
+
* http://www.eclipse.org/eclipse/platform-core/images/small_check.gif support creating radio button or checked menu items
+
* http://www.eclipse.org/eclipse/platform-core/images/small_check.gif creating new toolbars in the main coolbar/trim declaratively
+
* http://www.eclipse.org/eclipse/platform-core/images/small_check.gif creating new toolbars in the main coolbar/trim programmatically
+
* http://www.eclipse.org/eclipse/platform-core/images/small_check.gif org.eclipse.ui.popup.any as a context menu contribution
+
* http://www.eclipse.org/eclipse/platform-core/images/small_check.gif Drop down toolbar items
+
 
+
We also have action sets activating and de-activating contexts in '''3.3M5''', but we'll need to decide the proper action set story for '''3.3M6'''
+
 
+
We are still working on the EditorActionBarContributor story.  It seems like we might be able to deprecate it.  Editor instances can instantiate handlers upon creation for each command they support.
+
 
+
== Work still to be done ==
+
 
+
 
+
A list of behaviours not supported or shipped with the '''3.3M5''' API.
+
 
+
* http://www.eclipse.org/eclipse/platform-core/images/small_progress.gif the editor action bar contributor solution
+
* http://www.eclipse.org/eclipse/platform-core/images/small_progress.gif Attributes for <command/>: '''helpContextId''', '''style''' to support radio buttons and check boxes, '''state''' for checkboxes and radio buttons
+
* http://www.eclipse.org/eclipse/platform-core/images/small_progress.gif action sets as contexts
+
* http://www.eclipse.org/eclipse/platform-core/images/small_progress.gif validate and possibly optimize the context menu population story and lifecycle.  Many context menus set remove all when shown.
+
* migrate Marker views
+
* How do we give Trim widgets/toolbar widgets "focus" for command and handlers?
+
*
+
* http://www.eclipse.org/eclipse/platform-core/images/glass.gif migrate standard workbench actions
+
* Shortcuts to define reusable core expressions for <activeWhen/>, <enabledWhen/>, and <visibleWhen/>
+
* Check enabled visibleWhen support
+
* the mnemonic field for <command/> elements (decorating)
+
* display any keybinding for <command/> elements (decorating)
+
* Shortcuts placed on submenu items (like CTRL+N) (decorating)
+
* ensure full visibleWhen support in the MenuManagers - i.e. should empty menus display '''(empty)'''
+
* do we want to manage trim with a TrimContributionManager?  This removes the coolbar, but has RCP implications.
+
* the menu override capability - does this tie into the Customize Perspective dialog and action sets
+
* A set of default programmatic core expressions.  For example, ActionContextExpression or ActivePartExpression
+
* toolbar <visibleWhen/> expressions
+
* deprecate the 4 extension: actionSets, viewActions, editorActions, popupMenus
+
* read old extensions in terms of new extension
+
* convert platform UI extensions to new extension
+
* migration guide - what are the most common migration paths for Action and IActionDelegate to Command/IHandler.
+
* possibly provide an plugin.xml converter for actionSets to menus
+
* possibly provide an Action -> Handler converter
+
* ensure expressions can be reused
+
* http://www.eclipse.org/eclipse/platform-core/images/small_x.gif status manager contributions
+
 
+
 
+
Legend:
+
* nothing - TBD
+
* http://www.eclipse.org/eclipse/platform-core/images/glass.gif - investigating
+
* http://www.eclipse.org/eclipse/platform-core/images/small_progress.gif - in progress
+
* http://www.eclipse.org/eclipse/platform-core/images/small_check.gif - completed
+
* http://www.eclipse.org/eclipse/platform-core/images/small_x.gif - dropped
+
 
+
 
+
<!-- to be used when we complete information
+
list at http://dev.eclipse.org/viewcvs/index.cgi/platform-core-home/images/
+
 
+
complete      = http://www.eclipse.org/eclipse/platform-core/images/small_check.gif
+
dropped      = http://www.eclipse.org/eclipse/platform-core/images/small_x.gif
+
in progress  = http://www.eclipse.org/eclipse/platform-core/images/small_progress.gif
+
Investigating = http://www.eclipse.org/eclipse/platform-core/images/glass.gif
+
 
+
-->
+
 
+
= Add ProblemView menus =
+
 
+
Add the Problems view menus.  The Problems view has one toolbar action and in the view menu, 3 actions and 2 dynamic submenus.  It also has a dynamic menu and another bunch of actions in its context menu.
+
 
+
== Commands ==
+
 
+
First define commands that are specific to the view.  Since these are view commands, we can specify a default handler ... we're unlikely to replace it.
+
 
+
  <extension point="org.eclipse.ui.commands">
+
      <category id="org.eclipse.ui.views.problems"
+
                name="%ProblemView.category.name">
+
      </category>
+
      <command categoryId="org.eclipse.ui.views.problems"
+
              defaultHandler="org.eclipse.ui.views.markers.internal.TableSortHandler"
+
              description="%ProblemView.Sorting.description"
+
              id="org.eclipse.ui.views.problems.sorting"
+
              name="%ProblemView.Sorting.name">
+
      </command>
+
      &lt;!-- the view preference command would probably be defined once
+
      with the other preference contributions -->
+
      <command categoryId="org.eclipse.ui.views.problems"
+
              defaultHandler="org.eclipse.ui.preferences.ViewPreferencesHandler"
+
              description="%ViewPreferences.description"
+
              id="org.eclipse.ui.preferences.viewPreferences"
+
              name="%ViewPreferences.name">
+
        <commandParameter id="markerEnablementName"
+
                          name="%ViewPreferences.markerEnablementName.name"
+
                          optional="false" />
+
        <commandParameter id="markerLimitName"
+
                          name="%ViewPreferences.markerLimitName.name"
+
                          optional="false" />
+
      </command>
+
      <command categoryId="org.eclipse.ui.views.problems"
+
              defaultHandler="org.eclipse.ui.views.markers.internal.FiltersHandler"
+
              description="%ProblemView.ConfigureFilters.description"
+
              id="org.eclipse.ui.views.problems.configureFilters"
+
              name="%ProblemView.ConfigureFilters.name">
+
      </command>
+
      <command categoryId="org.eclipse.ui.views.problems"
+
              defaultHandler="org.eclipse.ui.views.markers.internal.OpenMarkerHandler"
+
              description="%ProblemView.GoTo.description"
+
              id="org.eclipse.ui.views.problems.goTo"
+
              name="%ProblemView.GoTo.name" />
+
  </extension>
+
 
+
== Handlers ==
+
 
+
We can also use a number of global commands, like copy, paste, delete, quick fix, and properties.  For these, we just need to define our handlers.  We need to add them with <activeWhen/> clauses to restrict them to being active when the view is active.
+
 
+
  <extension point="org.eclipse.ui.handlers">
+
      <handler commandId="org.eclipse.ui.edit.copy"
+
              class="org.eclipse.ui.views.markers.internal.CopyMarkerHandler">
+
        <enabledWhen>
+
            <not>
+
              <count value="0" />
+
            </not>
+
        </enabledWhen>
+
        <activeWhen>
+
            <with variable="activePartId">
+
              <equals value="org.eclipse.ui.views.ProblemView" />
+
            </with>
+
        </activeWhen>
+
      </handler>
+
      <handler commandId="org.eclipse.ui.edit.paste"
+
              class="org.eclipse.ui.views.markers.internal.PasteMarkerHandler">
+
        <enabledWhen>
+
            <not>
+
              <count value="0" />
+
            </not>
+
        </enabledWhen>
+
        <activeWhen>
+
            <with variable="activePartId">
+
              <equals value="org.eclipse.ui.views.ProblemView" />
+
            </with>
+
        </activeWhen>
+
      </handler>
+
      <handler commandId="org.eclipse.ui.edit.delete"
+
              class="org.eclipse.ui.views.markers.internal.RemoveMarkerHandler">
+
        <enabledWhen>
+
            <not>
+
              <count value="0" />
+
            </not>
+
        </enabledWhen>
+
        <activeWhen>
+
            <with variable="activePartId">
+
              <equals value="org.eclipse.ui.views.ProblemView" />
+
            </with>
+
        </activeWhen>
+
      </handler>
+
      <handler commandId="org.eclipse.ui.edit.selectAll"
+
              class="org.eclipse.ui.views.markers.internal.SelectAllMarkersHandler">
+
        <enabledWhen>
+
            <not>
+
              <count value="0" />
+
            </not>
+
        </enabledWhen>
+
        <activeWhen>
+
            <with variable="activePartId">
+
              <equals value="org.eclipse.ui.views.ProblemView" />
+
            </with>
+
        </activeWhen>
+
      </handler>
+
      <handler commandId="org.eclipse.jdt.ui.edit.text.java.correction.assist.proposals"
+
              class="org.eclipse.ui.views.markers.internal.ResolveMarkerHandler">
+
        <enabledWhen>
+
            <not>
+
              <count value="0" />
+
            </not>
+
        </enabledWhen>
+
        <activeWhen>
+
            <with variable="activePartId">
+
              <equals value="org.eclipse.ui.views.ProblemView" />
+
            </with>
+
        </activeWhen>
+
      </handler>
+
      <handler commandId="org.eclipse.ui.file.properties"
+
              class="org.eclipse.ui.views.markers.internal.ProblemPropertiesHandler">
+
        <enabledWhen>
+
            <not>
+
              <count value="0" />
+
            </not>
+
        </enabledWhen>
+
        <activeWhen>
+
            <with variable="activePartId">
+
              <equals value="org.eclipse.ui.views.ProblemView" />
+
            </with>
+
        </activeWhen>
+
      </handler>
+
  </extension>
+
 
+
 
+
Or we can programmatically activate them through the IHandlerService which we would retrieve from the ProblemView site.
+
 
+
IHandlerService handlerServ = (IHandlerService)getSite().getService(IHandlerService.class);
+
copy = new CopyMarkerHandler();
+
handlerServ.activateHandler("org.eclipse.ui.edit.copy", copy);
+
 
+
Using the ProblemView site to access the IHandlerService handles the <activeWhen/> clause for us, and our programmatic handler would manage its own enablement state.
+
 
+
=== Expression Sidebar  ===
+
 
+
You can see that the <activeWhen/>, <enabledWhen/>, and probably the <visibleWhen/> are likely to be replicated over and over again.  A possible option is some kind of expression template markup ... either in its own extension or supported by our UI extensions that can use core expressions.
+
 
+
Here's an example of using expression templates in its own extension point.
+
 
+
  <extension point="org.eclipse.core.expression.templates">
+
    <expression id="isPartActive">
+
      <parameter id="partId" />
+
      <with variable="activePartId">
+
        <equals value="$partId" />
+
      </with>
+
    </expression>
+
    <expression id="isActionSetActive">
+
      <parameter id="actionSetId" />
+
      <with variable="activeContexts">
+
        <iterator operator="or">
+
          <equals value="$actionSetId" />
+
        </iterator>
+
      </with>
+
    </expression>
+
    <expression id="isContextActive">
+
      <parameter id="contextId" />
+
      <with variable="activeContexts">
+
        <iterator operator="or">
+
          <equals value="$contextId" />
+
        </iterator>
+
      </with>
+
    </expression>
+
    <expression id="isSelectionAvailable">
+
      <not>
+
        <count value="0" />
+
      </not>
+
    </expression>
+
  </extension>
+
 
+
 
+
This could be used to simplify the handler definitions:
+
 
+
  <extension point="org.eclipse.ui.handlers">
+
    <handler commandId="org.eclipse.ui.edit.copy"
+
            class="org.eclipse.ui.views.markers.internal.CopyMarkerHandler">
+
      <enabledWhen>
+
        <evaluate ref="isSelectionAvailable" />
+
      </enabledWhen>
+
      <activeWhen>
+
        <evaluate ref="isPartActive">
+
          <parameter id="partId" value="org.eclipse.ui.views.ProblemView" />
+
        </evaluate>
+
      </activeWhen>
+
    </handler>
+
  </extension>
+
 
+
 
+
If we allow recursive template definitions, that would allow you to specify the concrete expression once and then reference it throughout your view.
+
 
+
  <extension point="org.eclipse.core.expression.templates">
+
    <expression id="isProblemViewActive">
+
      <evaluate ref="isPartActive">
+
        <parameter id="partId" value="org.eclipse.ui.views.ProblemView" />
+
      </evaluate>
+
    </expression>
+
  </extension>
+
  <extension point="org.eclipse.ui.handlers">
+
    <handler commandId="org.eclipse.ui.edit.copy"
+
            class="org.eclipse.ui.views.markers.internal.CopyMarkerHandler">
+
      <enabledWhen>
+
        <evaluate ref="isSelectionAvailable" />
+
      </enabledWhen>
+
      <activeWhen>
+
        <evaluate ref="isProblemViewActive" />
+
      </activeWhen>
+
    </handler>
+
  </extension>
+
 
+
 
+
This reduces the handler definition even more.
+
 
+
 
+
A similar option to reuse expressions as much as possible without turning them into their own procedural language would be to allow global definitions and then reuse them.  No parameters and no expression composition:
+
 
+
  <extension point="org.eclipse.core.expression.templates">
+
    <expression id="isProblemViewActive">
+
      <with variable="activePartId">
+
        <equals value="org.eclipse.ui.views.ProblemView" />
+
      </with>
+
    </expression>
+
    <expression id="isSelectionAvailable">
+
      <not>
+
        <count value="0" />
+
      </not>
+
    </expression>
+
  </extension>
+
  <extension point="org.eclipse.ui.handlers">
+
    <handler commandId="org.eclipse.ui.edit.copy"
+
            class="org.eclipse.ui.views.markers.internal.CopyMarkerHandler">
+
      <enabledWhen ref="isSelectionAvailable" />
+
      <activeWhen ref="isProblemViewActive" />
+
    </handler>
+
  </extension>
+
 
+
=== Another Alternative: Specify Context at Extension Level ===
+
 
+
 
+
Since <code>enabledWhen</code> and <code>activeWhen</code> specify context and the simple way to specify context in XML is enclosure, how about scoping context to the extension point rather than the handler:
+
 
+
  <extension point="org.eclipse.ui.handlers">
+
      <enabledWhen>  <!-- context of all  handlers in this extension -->
+
        <not>
+
          <count value="0" />
+
        </not>
+
      </enabledWhen>
+
      <activeWhen>
+
        <with variable="activePartId">
+
          <equals value="org.eclipse.ui.views.ProblemView" />
+
        </with>
+
      </activeWhen>
+
      <handler commandId="org.eclipse.ui.edit.copy"
+
            class="org.eclipse.ui.views.markers.internal.CopyMarkerHandler" />
+
      <handler commandId="org.eclipse.ui.edit.paste"
+
            class="org.eclipse.ui.views.markers.internal.PasteMarkerHandler" />
+
      <handler commandId="org.eclipse.ui.edit.delete"
+
            class="org.eclipse.ui.views.markers.internal.RemoveMarkerHandler" />
+
      <handler commandId="org.eclipse.jdt.ui.edit.text.java.correction.assist.proposals"
+
            class="org.eclipse.ui.views.markers.internal.ResolveMarkerHandler" />
+
      <handler commandId="org.eclipse.ui.edit.selectAll"
+
            class="org.eclipse.ui.views.markers.internal.SelectAllMarkersHandler" />
+
      <handler commandId="org.eclipse.ui.file.properties"
+
            class="org.eclipse.ui.views.markers.internal.ProblemPropertiesHandler" />
+
  </extension>
+
 
+
This gives compact markup without inventing a new language.  Elements nested in the handler element could override the extension-wide settings.
+
 
+
== Menus ==
+
  
 +
{| class="wikitable" border="1"
 +
|-
 +
! Example !! comments
 +
|-
 +
| [[Menu Contributions/Dropdown Command]] || Dropdown tool items can have their menus filled in using menu contributions
 +
|-
 +
| [[Menu Contributions/Problems View Example]] || An example showing how the Problems View might be converted
 +
|-
 +
| [[Menu Contributions/Populating a dynamic submenu]] || A menu contribution to populate a Problems View dynamic submenu
 +
|-
 +
| [[Menu Contributions/Toggle Mark Occurrences]] || Placing the toggle mark occurrences button
 +
|-
 +
| [[Menu Contributions/Toggle Button Command]] || Contribute a toggle state menu item thru commands
 +
|-
 +
| [[Menu Contributions/Radio Button Command]] || Similar to updating toggle state, you can create radio buttons using menu contributions
 +
|-
 +
| [[Menu Contributions/Update checked state]] || The active handler can update the checked state (and other attributes) of its button
 +
|-
 +
| [[Menu Contributions/Search Menu]] || Adding the Java Search options to the Search menu
 +
|-
 +
| [[Menu Contributions/IFile objectContribution]] || A menu contribution for context menus when the selection is an IFile
 +
|-
 +
| [[Menu Contributions/TextEditor viewerContribution]] || A menu contribution for the text editor context menu
 +
|-
 +
| [[Menu Contributions/Widget in a toolbar]] || A menu contribution adding a control into the main toolbar
 +
|-
 +
| [[Menu Contributions/RCP removes the Project menu]] || An RCP application removes the Project menu.  Note: this will probably not be in 3.3
 +
|-
 +
| [[Menu Contributions/Workbench wizard contribution]] || Contributing workbench wizards to Menu
 +
|-
 +
|}
  
Then we would define the ProblemView menu structures.  We are using 3 <b>roots</b>:  the view menu, the view toolbar, and the view context menu.  This is an example of an "in-place" menu definition.  The <menuContribution/> location attribute is a URI that defines the starting point for inserting the menu elements. The XML hierarchy mirrors the menu hierarchy, in that you can define items and menus within the body of other menus.
+
= Menu XML =
  
  <extension point="org.eclipse.ui.menus">
+
Declarative information ... this needs to be cleaned up.
      <menuContribution locationURI="menu:org.eclipse.ui.views.ProblemView">
+
        <command commandId="org.eclipse.ui.views.problems.sorting"
+
                  label="%ProblemView.Sorting.name"
+
                  mnemonic="%ProblemView.Sorting.mnemonic"
+
                  style="push"
+
                  tooltip="%ProblemView.Sorting.tooltip">
+
        </command>
+
        <menu id="org.eclipse.ui.views.problems.groupBy.menu"
+
              label="%ProblemView.GroupBy.label"
+
              mnemonic="%ProblemView.GroupBy.mnemonic">
+
            <dynamic class="org.eclipse.ui.views.markers.internal.GroupByItems"
+
                    id="org.eclipse.ui.views.problems.groupBy.items">
+
            </dynamic>
+
        </menu>
+
        <separator name="group.filter" visible="true" />
+
        <menu id="org.eclipse.ui.views.problems.filters.menu"
+
              label="%ProblemView.Filters.label"
+
              mnemonic="%ProblemView.Filters.mnemonic">
+
            <dynamic class="org.eclipse.ui.views.markers.internal.FilterItems"
+
                    id="org.eclipse.ui.views.problems.filters.items" />
+
        </menu>
+
        <command commandId="org.eclipse.ui.views.problems.configureFilters"
+
                  icon="$nl$/elcl16/filter_ps.gif"
+
                  label="%ProblemView.ConfigureFilters.name"
+
                  mnemonic="%ProblemView.ConfigureFilters.mnemonic"
+
                  tooltip="%ProblemView.ConfigureFilters.tooltip" />
+
        <command commandId="org.eclipse.ui.preferences.viewPreferences"
+
                  label="%ViewPreferences.name"
+
                  mnemonic="%ViewPreferences.mnemonic">
+
            <parameter name="markerEnablementName" value="LIMIT_PROBLEMS" />
+
            <parameter name="markerLimitName" value="PROBLEMS_LIMIT" />
+
        </command>
+
      </menuContribution>
+
      <menuContribution locationURI="toolbar:org.eclipse.ui.views.ProblemView">
+
        <command commandId="org.eclipse.ui.views.problems.configureFilters"
+
                  icon="$nl$/elcl16/filter_ps.gif"
+
                  tooltip="%ProblemView.ConfigureFilters.tooltip" />
+
      </menuContribution>
+
      <menuContribution locationURI="popup:org.eclipse.ui.views.ProblemView">
+
        <command commandId="org.eclipse.ui.views.problems.goTo"
+
                  mnemonic="%ProblemView.GoTo.mnemonic"
+
                  icon="$nl$/elcl16/gotoobj_tsk.gif"
+
                  disabledIcon="$nl$/dlcl16/gotoobj_tsk.gif"
+
                  tooltip="%ProblemView.GoTo.tooltip" />
+
        <separator name="group.showIn" visible="true" />
+
        <menu id="org.eclipse.ui.views.problems.showIn.menu"
+
              label="%ProblemView.ShowIn.label"
+
              mnemonic="%ProblemView.ShowIn.mnemonic">
+
            <dynamic class="org.eclipse.ui.actions.ShowInContributions"
+
                    id="org.eclipse.ui.views.problems.showIn.items" />
+
        </menu>
+
        <separator name="group.edit" visible="true" />
+
        <command commandId="org.eclipse.ui.edit.copy"
+
                  mnemonic="%ProblemView.copy.mnemonic"
+
                  icon="$nl$/icons/full/etool16/copy_edit.gif"
+
                  disabledIcon="$nl$/icons/full/dtool16/copy_edit.gif" />
+
        <command commandId="org.eclipse.ui.edit.paste"
+
                  mnemonic="%ProblemView.paste.mnemonic"
+
                  icon="$nl$/icons/full/etool16/paste_edit.gif"
+
                  disabledIcon="$nl$/icons/full/dtool16/paste_edit.gif" />
+
        <command commandId="org.eclipse.ui.edit.delete"
+
                  mnemonic="%ProblemView.delete.mnemonic"
+
                  icon="$nl$/icons/full/etool16/delete_edit.gif"
+
                  disabledIcon="$nl$/icons/full/dtool16/delete_edit.gif">
+
            <visibleWhen>
+
              <not>
+
                  <with variable="activePartId">
+
                    <equals value="org.eclipse.ui.views.ProblemView" />
+
                  </with>
+
              </not>
+
            </visibleWhen>
+
        </command>
+
        <command commandId="org.eclipse.ui.edit.selectAll"
+
                  mnemonic="%ProblemView.selectAll.mnemonic" />
+
        <separator name="group.resolve" visible="true" />
+
        <command commandId="org.eclipse.jdt.ui.edit.text.java.correction.assist.proposals"
+
                  mnemonic="%ProblemView.Resolve.mnemonic"
+
                  icon="$nl$/icons/full/elcl16/smartmode_co.gif"
+
                  disabledIcon="$nl$/icons/full/dlcl16/smartmode_co.gif" />
+
        <separator name="additions" visible="false" />
+
        <separator name="group.properties" visible="true" />
+
        <command commandId="org.eclipse.ui.file.properties"
+
                  mnemonic="%ProblemView.Properties.mnemonic" />
+
      </menuContribution>
+
  </extension>
+
  
 +
=== Declarative menus - some constraints ===
  
 
Some constraints on the system:
 
Some constraints on the system:
Line 465: Line 53:
 
# You can reference a <menu/> by id.
 
# You can reference a <menu/> by id.
 
# If you are just creating menu items for your commands, you can leave them with only a command id.  You don't have to specify an item id.
 
# If you are just creating menu items for your commands, you can leave them with only a command id.  You don't have to specify an item id.
# You can reference an <command/> for placement options (after, before, etc) by id.
+
# You can reference a <command/> for placement options (after, before, etc.) by id.
 
# <separator/> ids only have to be unique within that menu level.  This is changed to name instead of id in '''3.3M5'''.
 
# <separator/> ids only have to be unique within that menu level.  This is changed to name instead of id in '''3.3M5'''.
# You can provide an <command/> label attribute.  If none is provided, it will take the command name.
+
# You can provide a <command/> label attribute.  If none is provided, it will take the command name.
 
# In this design the item contains most of the same rendering information that <action/> did.
 
# In this design the item contains most of the same rendering information that <action/> did.
 
# <menu/> and <command/> can have <visibleWhen/> clauses.  If a menu's <visibleWhen/> evaluates to false, we will never ask the items contained in that menu.
 
# <menu/> and <command/> can have <visibleWhen/> clauses.  If a menu's <visibleWhen/> evaluates to false, we will never ask the items contained in that menu.
# All of the display-able attributes are translatable.
+
# All of the displayable attributes are translatable.
# The mnemonic is specified as you place your <command/> elements in their respective menus, since it is possible that the same command might need a different mnemonic depending on which menu it is placed.  Also, when defaulting to command names they don't contain any mnemonic information.
+
# The mnemonic is specified as you place your <command/> elements in their respective menus, since it is possible that the same command might need a different mnemonic depending on which menu it is placed.  Also, when defaulting to command names, they don't contain any mnemonic information.
 +
 
 +
Menus cannot be re-used, and so they have an intrinsic id value.  Separators are unique within one menu level, so they also contain their name.
  
 
=== Menu URIs ===
 
=== Menu URIs ===
Line 481: Line 71:
 
scheme is about how to interpret the URI path.  For example, <code>menu</code>, <code>toolbar</code>, <code>popup</code>, <code>status</code> (although status may be deprecated).
 
scheme is about how to interpret the URI path.  For example, <code>menu</code>, <code>toolbar</code>, <code>popup</code>, <code>status</code> (although status may be deprecated).
  
 +
==== menu: ====
  
 
For <code>menu:</code> valid root ids will be any viewId for that view's menu, and <b>org.eclipse.ui.main.menu</b> for the main menu.  Then specify the id of the menu this contribution applies to.  The placement modifier helps position the menu contribution.  ex: after=<id>, where <id> can be a separator name, menu id, or item id.  An example of a path: <code>menu:org.eclipse.search.menu?after=contextMenuActionsGroup</code>
 
For <code>menu:</code> valid root ids will be any viewId for that view's menu, and <b>org.eclipse.ui.main.menu</b> for the main menu.  Then specify the id of the menu this contribution applies to.  The placement modifier helps position the menu contribution.  ex: after=<id>, where <id> can be a separator name, menu id, or item id.  An example of a path: <code>menu:org.eclipse.search.menu?after=contextMenuActionsGroup</code>
  
 
Since menu ids must be unique, you can specify your menu location relative to an existing id: <code>menu:org.eclipse.search.menu?after=contextMenuActionsGroup</code>
 
Since menu ids must be unique, you can specify your menu location relative to an existing id: <code>menu:org.eclipse.search.menu?after=contextMenuActionsGroup</code>
 +
 +
==== toolbar: ====
  
 
For <code>toolbar:</code> valid root ids will be any viewId for that view's toolbar, <b>org.eclipse.ui.main.toolbar</b> for the main toolbar, and any toolbar id that is contained in the main toolbar.  Toolbars can support <b>invisible</b> separators.  Toolbars in the main toolbar (technically a coolbar) can have ids as well as separators, but only one level.  For example: <code>toolbar:org.eclipse.ui.edit.text.actionSet.presentation?after=Presentation</code>
 
For <code>toolbar:</code> valid root ids will be any viewId for that view's toolbar, <b>org.eclipse.ui.main.toolbar</b> for the main toolbar, and any toolbar id that is contained in the main toolbar.  Toolbars can support <b>invisible</b> separators.  Toolbars in the main toolbar (technically a coolbar) can have ids as well as separators, but only one level.  For example: <code>toolbar:org.eclipse.ui.edit.text.actionSet.presentation?after=Presentation</code>
Line 492: Line 85:
 
The use of <b>org.eclipse.ui.main.toolbar</b> might change if all "main" toolbars have ids anyway, so the only options for interpretting the toolbar root is 1) the view toolbar or 2) an IDed main toolbar.
 
The use of <b>org.eclipse.ui.main.toolbar</b> might change if all "main" toolbars have ids anyway, so the only options for interpretting the toolbar root is 1) the view toolbar or 2) an IDed main toolbar.
  
 +
==== popup: ====
  
 
For <code>popup:</code> valid root ids are any registered context id (which defaults to the part id if no context menu id was given at registration time) and <b>org.eclipse.ui.popup.any</b> for all registered context menus.  For example, to add to the default Text Editor context menu: <code>popup:#TextEditorContext?after=additions</code>
 
For <code>popup:</code> valid root ids are any registered context id (which defaults to the part id if no context menu id was given at registration time) and <b>org.eclipse.ui.popup.any</b> for all registered context menus.  For example, to add to the default Text Editor context menu: <code>popup:#TextEditorContext?after=additions</code>
Line 497: Line 91:
 
Popup submenus are treated like menu submenus, except the form continues to be <code>popup:submenuId</code>.
 
Popup submenus are treated like menu submenus, except the form continues to be <code>popup:submenuId</code>.
  
There will be constants defined for the ids that the eclipse workbench provides.
+
There will be constants defined for the ids that the eclipse workbench provides, probably in <code>org.eclipse.ui.menus.MenuUtil</code>.
  
=== Menu - JSR198 ===
+
=== Using Expressions in &lt;visibleWhen/&gt; ===
 +
 
 +
In '''3.3M6''' an org.eclipse.core.expressions.definitions extension point was added. Used to define a [[Platform Expression Framework|core expression]], the definition can then be referenced from other locations.
 +
 
 +
<source lang="xml">
 +
<extension point="org.eclipse.core.expressions.definitions">
 +
  <definition id="com.example.context">
 +
    <with variable="activeContexts">
 +
      <iterate operator="or">
 +
        <equals value="org.eclipse.ui.contexts.actionSet"/>
 +
      </iterate>
 +
    </with>
 +
  </definition>
 +
</extension>
 +
</source>
 +
 
 +
This can be called in a core expression like activeWhen, enabledWhen, visibleWhen, etc using the reference element:
 +
 
 +
<source lang="xml">
 +
<reference definitionId="com.example.context"/>
 +
</source>
 +
 
 +
=== Ideas that were considered but not implemented ===
 +
 
 +
These ideas were considered but not implemented.
 +
 
 +
==== Menu - JSR198 ====
  
 
'''Note:''' for novelty purposes only.
 
'''Note:''' for novelty purposes only.
Line 508: Line 128:
 
* org.eclipse.ui.views.problems.resolveMarker.item from popup:org.eclipse.ui.views.ProblemView
 
* org.eclipse.ui.views.problems.resolveMarker.item from popup:org.eclipse.ui.views.ProblemView
  
  <menu-hook>
+
<source lang="xml">
    <actions>
+
<menu-hook>
      <action id="org.eclipse.ui.views.problems.sorting.item">
+
  <actions>
        <label>Sorting...</label>
+
    <action id="org.eclipse.ui.views.problems.sorting.item">
        <mnemonic>S</mnemonic>
+
      <label>Sorting...</label>
        <tooltip>Change the Sort order</tooltip>
+
      <mnemonic>S</mnemonic>
        <invoke-class>org.eclipse.ui.views.problems.sorting</invoke-class>
+
      <tooltip>Change the Sort order</tooltip>
      </action>
+
      <invoke-class>org.eclipse.ui.views.problems.sorting</invoke-class>
      <action id="org.eclipse.ui.views.problems.resolveMarker.item">
+
    </action>
        <label>Quick Fix</label>
+
    <action id="org.eclipse.ui.views.problems.resolveMarker.item">
        <mnemonic>Q</mnemonic>
+
      <label>Quick Fix</label>
        <iconpath>$nl$/icons/full/elcl16/smartmode_co.gif</iconpath>
+
      <mnemonic>Q</mnemonic>
        <invoke-class>org.eclipse.jdt.ui.edit.text.java.correction.assist.proposals</invoke-class>
+
      <iconpath>$nl$/icons/full/elcl16/smartmode_co.gif</iconpath>
        <update-class>org.eclipse.jdt.ui.edit.text.java.correction.assist.proposals</update-class>
+
      <invoke-class>org.eclipse.jdt.ui.edit.text.java.correction.assist.proposals</invoke-class>
      </action>
+
      <update-class>org.eclipse.jdt.ui.edit.text.java.correction.assist.proposals</update-class>
    </actions>
+
    </action>
    <menus>
+
  </actions>
      <menubar id="org.eclipse.ui.views.ProblemView">
+
  <menus>
        <menu id="org.eclipse.ui.views.ProblemView">
+
    <menubar id="org.eclipse.ui.views.ProblemView">
          <section id="problem.view.section">
+
      <menu id="org.eclipse.ui.views.ProblemView">
            <command action-ref="org.eclipse.ui.views.problems.sorting.item" />
+
        <section id="problem.view.section">
            <menu id="org.eclipse.ui.views.problems.groupBy.menu">
+
          <command action-ref="org.eclipse.ui.views.problems.sorting.item" />
              <label>Group By</label>
+
          <menu id="org.eclipse.ui.views.problems.groupBy.menu">
              <mnemonic>G</mnemonic>
+
            <label>Group By</label>
            </menu>
+
            <mnemonic>G</mnemonic>
           </section>
+
           </menu>
        </menu>
+
      </menubar>
+
      <popup id="org.eclipse.ui.views.ProblemView">
+
        <section id="group.resolve">
+
          <command action-ref="org.eclipse.ui.views.problems.resolveMarker.item" />
+
 
         </section>
 
         </section>
       </popup>
+
       </menu>
     </menus>
+
    </menubar>
   </menu-hook>
+
    <popup id="org.eclipse.ui.views.ProblemView">
 +
      <section id="group.resolve">
 +
        <command action-ref="org.eclipse.ui.views.problems.resolveMarker.item" />
 +
      </section>
 +
     </popup>
 +
   </menus>
 +
</menu-hook>
 +
</source>
  
 
Some thoughts:
 
Some thoughts:
Line 550: Line 172:
 
* the menus can't specify dynamic submenus
 
* the menus can't specify dynamic submenus
  
=== Menu - XUL ===
+
==== Menu - XUL ====
  
 
'''Note:''' for novelty purposes only.
 
'''Note:''' for novelty purposes only.
Line 557: Line 179:
 
For comparison, with Mozilla everywhere there is the probability eclipse will include xulrunner.  Menu definitions that are consistent with XUL look like:
 
For comparison, with Mozilla everywhere there is the probability eclipse will include xulrunner.  Menu definitions that are consistent with XUL look like:
  
  <keyset>
+
<source lang="xml">
    <key id="paste-key" modifiers="accel" key="V" />
+
<keyset>
  </keyset>
+
  <key id="paste-key" modifiers="accel" key="V" />
  <menubar id="org.eclipse.ui.views.ProblemView">
+
</keyset>
    <menupopup id="org.eclipse.ui.views.ProblemView">
+
<menubar id="org.eclipse.ui.views.ProblemView">
      <menuitem id="org.eclipse.ui.views.problems.sorting.item"
+
  <menupopup id="org.eclipse.ui.views.ProblemView">
                accesskey="S"
+
    <menuitem id="org.eclipse.ui.views.problems.sorting.item"
                key="paste-key"
+
        accesskey="S"
                label="Sorting..."
+
        key="paste-key"
                oncommand="invokeCommand('org.eclipse.ui.views.problems.sorting')" />
+
        label="Sorting..."
      <menu id="org.eclipse.ui.views.problems.groupBy.menu"
+
        oncommand="invokeCommand('org.eclipse.ui.views.problems.sorting')" />
            label="Group By"
+
    <menu id="org.eclipse.ui.views.problems.groupBy.menu"
            accesskey="G">
+
        label="Group By"
        <menupopup id="groupby.popup">
+
        accesskey="G">
          <!-- this is where submenu items would go -->
+
      <menupopup id="groupby.popup">
        </menupopup>
+
        <!-- this is where submenu items would go -->
      </menu>
+
      </menupopup>
    </menupopup>
+
    </menu>
  </menubar>
+
  </menupopup>
 
+
</menubar>
 +
</source>
  
 
XUL supports everything as a flavour of a DOM, and javascripting can drive your buttons to perform commands.  I suspect the scripting would allow you to dynamically update menus (dynamic menus) on popup, depending on what events the DOM would report to you.
 
XUL supports everything as a flavour of a DOM, and javascripting can drive your buttons to perform commands.  I suspect the scripting would allow you to dynamically update menus (dynamic menus) on popup, depending on what events the DOM would report to you.
  
== Menus API ==
 
  
We can contribute menu definitions through the IMenuService API.
+
==== Expression Templates original suggestion  ====
  
The above example can be done for the view menus:
 
  
    public void addProblemsViewMenuContribution() {
+
You can see that the <activeWhen/>, <enabledWhen/>, and probably the <visibleWhen/> are likely to be replicated over and over againA possible option is some kind of expression template markup ... either in its own extension or supported by our UI extensions that can use core expressions.
        IMenuService menuService = (IMenuService) PlatformUI.getWorkbench()
+
                .getService(IMenuService.class);
+
+
        AbstractContributionFactory viewMenuAddition = new AbstractContributionFactory(
+
                "menu:org.eclipse.ui.views.ProblemView?after=additions") {
+
            public void createContributionItems(IMenuService menuService,
+
                    List additions) {
+
                CommandContributionItem item = new CommandContributionItem(
+
                        null, "org.eclipse.ui.views.problems.sorting", null,
+
                        null, null, null, "Sorting...", "S",
+
                        "Change the Sort order",
+
                        CommandContributionItem.STYLE_PUSH);
+
                additions.add(item);
+
+
                MenuManager submenu = new MenuManager("Group &By",
+
                        "org.eclipse.ui.views.problems.groupBy.menu");
+
                IContributionItem dynamicItem = new CompoundContributionItem(
+
                        "org.eclipse.ui.views.problems.groupBy.items") {
+
                    protected IContributionItem[] getContributionItems() {
+
                        // Here's where you would dynamically generate your list
+
                        IContributionItem[] list = new IContributionItem[2];
+
                        Map parms = new HashMap();
+
                        parms.put("groupBy", "Severity");
+
                        list[0] = new CommandContributionItem(null,
+
                                "org.eclipse.ui.views.problems.grouping",
+
                                parms, null, null, null, "Severity", null,
+
                                null, CommandContributionItem.STYLE_PUSH);
+
+
                        parms = new HashMap();
+
                        parms.put("groupBy", "None");
+
                        list[1] = new CommandContributionItem(null,
+
                                "org.eclipse.ui.views.problems.grouping",
+
                                parms, null, null, null, "None", null, null,
+
                                CommandContributionItem.STYLE_PUSH);
+
                        return list;
+
                    }
+
                };
+
                submenu.add(dynamicItem);
+
+
                additions.add(submenu);
+
                additions.add(new Separator("group.filter"));
+
+
                submenu = new MenuManager("&Filters",
+
                        "org.eclipse.ui.views.problems.filters.menu");
+
                dynamicItem = new CompoundContributionItem(
+
                        "org.eclipse.ui.views.problems.filters.items") {
+
                    protected IContributionItem[] getContributionItems() {
+
                        // Here's where you would dynamically generate your list
+
                        IContributionItem[] list = new IContributionItem[1];
+
                        Map parms = new HashMap();
+
                        parms.put("filter", "Default");
+
                        list[0] = new CommandContributionItem(null,
+
                                "org.eclipse.ui.views.problems.filters", parms,
+
                                null, null, null, "Default", null, null,
+
                                CommandContributionItem.STYLE_PUSH);
+
                        return list;
+
                    }
+
                };
+
                submenu.add(dynamicItem);
+
+
                additions.add(submenu);
+
+
                ImageDescriptor filterIcon = PlatformUI.getWorkbench()
+
                        .getSharedImages().getImageDescriptor(
+
                                "elcl16/filter_ps.gif");
+
                item = new CommandContributionItem(null,
+
                        "org.eclipse.ui.views.problems.configureFilters", null,
+
                        filterIcon, null, null, "Configure Filters...", "C",
+
                        "Configure the filters to be applied to this view",
+
                        CommandContributionItem.STYLE_PUSH);
+
                additions.add(item);
+
   
+
                Map parms = new HashMap();
+
                parms.put("markerEnablementName", "LIMIT_PROBLEMS");
+
                parms.put("markerLimitName", "PROBLEMS_LIMIT");
+
                item = new CommandContributionItem(null,
+
                        "org.eclipse.ui.preferences.viewPreferences", parms,
+
                        null, null, null, "Preference", "P",
+
                        "Open the preference dialog",
+
                        CommandContributionItem.STYLE_PUSH);
+
                additions.add(item);
+
            }
+
+
            public void releaseContributionItems(IMenuService menuService,
+
                    List items) {
+
                // for us this is a no-op
+
            }
+
        };
+
        menuService.addContributionFactory(viewMenuAddition);
+
    }
+
  
 +
Here's an example of using expression templates in its own extension point.
  
+
<source lang="xml">
 +
<extension point="org.eclipse.core.expression.templates">
 +
  <expression id="isPartActive">
 +
    <parameter id="partId" />
 +
    <with variable="activePartId">
 +
      <equals value="$partId" />
 +
    </with>
 +
  </expression>
 +
  <expression id="isActionSetActive">
 +
    <parameter id="actionSetId" />
 +
    <with variable="activeContexts">
 +
      <iterator operator="or">
 +
        <equals value="$actionSetId" />
 +
      </iterator>
 +
    </with>
 +
  </expression>
 +
  <expression id="isContextActive">
 +
    <parameter id="contextId" />
 +
    <with variable="activeContexts">
 +
      <iterator operator="or">
 +
        <equals value="$contextId" />
 +
      </iterator>
 +
    </with>
 +
  </expression>
 +
  <expression id="isSelectionAvailable">
 +
    <not>
 +
      <count value="0" />
 +
    </not>
 +
  </expression>
 +
</extension>
 +
</source>
  
The <code>AbstractContributionFactory</code> creates new contribution items every time <code>createContributionItems(List)</code> is called.  The factory location tells the framework where to insert the contributions when populating <code>ContributionManager</code>s.
+
This could be used to simplify the handler definitions:
  
You add your IContributionItems in the list. Supported contributions include:
+
<source lang="xml">
*MenuManagers
+
<extension point="org.eclipse.ui.handlers">
*Separators
+
  <handler commandId="org.eclipse.ui.edit.copy"
*GroupMarkers
+
      class="org.eclipse.ui.views.markers.internal.CopyMarkerHandler">
*CommandContributionItems
+
    <enabledWhen>
*CompoundContributionItems
+
      <evaluate ref="isSelectionAvailable" />
*ControlContributions
+
    </enabledWhen>
 +
    <activeWhen>
 +
      <evaluate ref="isPartActive">
 +
        <parameter id="partId" value="org.eclipse.ui.views.ProblemView" />
 +
      </evaluate>
 +
    </activeWhen>
 +
  </handler>
 +
</extension>
 +
</source>
  
If you need to reference an Item at some time you will need to create it with an id, which must be unique.
+
If we allow recursive template definitions, that would allow you to specify the concrete expression once and then reference it throughout your view.
  
Menus cannot be re-used, and so they have an intrinsic id value. Separators are unique within one menu level, so they also contain their name.
+
<source lang="xml">
 +
<extension point="org.eclipse.core.expression.templates">
 +
  <expression id="isProblemViewActive">
 +
    <evaluate ref="isPartActive">
 +
      <parameter id="partId" value="org.eclipse.ui.views.ProblemView" />
 +
    </evaluate>
 +
  </expression>
 +
</extension>
 +
<extension point="org.eclipse.ui.handlers">
 +
  <handler commandId="org.eclipse.ui.edit.copy"
 +
      class="org.eclipse.ui.views.markers.internal.CopyMarkerHandler">
 +
    <enabledWhen>
 +
      <evaluate ref="isSelectionAvailable" />
 +
    </enabledWhen>
 +
    <activeWhen>
 +
      <evaluate ref="isProblemViewActive" />
 +
    </activeWhen>
 +
  </handler>
 +
</extension>
 +
</source>
  
= Add Toggle Mark Occurrences to main toolbar =
+
This reduces the handler definition even more.
  
  
We can provide the Toggle Mark Occurrences toolbar buttonIt's normally contributed through an actionSet as a retargettable action, and the Java and Class File editors *EditorActionBarContributors provide the implementation ToggleMarkOccurrencesAction through IActionBars#setGlobalActionHandler(*).
+
A similar option to reuse expressions as much as possible without turning them into their own procedural language would be to allow global definitions and then reuse them.  No parameters and no expression composition:
 +
 
 +
<source lang="xml">
 +
<extension point="org.eclipse.core.expression.templates">
 +
  <expression id="isProblemViewActive">
 +
    <with variable="activePartId">
 +
      <equals value="org.eclipse.ui.views.ProblemView" />
 +
    </with>
 +
  </expression>
 +
  <expression id="isSelectionAvailable">
 +
    <not>
 +
      <count value="0" />
 +
    </not>
 +
  </expression>
 +
</extension>
 +
<extension point="org.eclipse.ui.handlers">
 +
  <handler commandId="org.eclipse.ui.edit.copy"
 +
      class="org.eclipse.ui.views.markers.internal.CopyMarkerHandler">
 +
    <enabledWhen ref="isSelectionAvailable" />
 +
    <activeWhen ref="isProblemViewActive" />
 +
  </handler>
 +
</extension>
 +
</source>
 +
 
 +
==== Another Expression Alternative: Specify Context at Extension Level ====
 +
 
 +
 
 +
Since <code>enabledWhen</code> and <code>activeWhen</code> specify context and the simple way to specify context in XML is enclosure, how about scoping context to the extension point rather than the handler:
 +
 
 +
<source lang="xml">
 +
<extension point="org.eclipse.ui.handlers">
 +
  <enabledWhen> <!-- context of all  handlers in this extension -->
 +
    <not>
 +
      <count value="0" />
 +
    </not>
 +
  </enabledWhen>
 +
  <activeWhen>
 +
    <with variable="activePartId">
 +
      <equals value="org.eclipse.ui.views.ProblemView" />
 +
    </with>
 +
  </activeWhen>
 +
  <handler commandId="org.eclipse.ui.edit.copy"
 +
      class="org.eclipse.ui.views.markers.internal.CopyMarkerHandler" />
 +
  <handler commandId="org.eclipse.ui.edit.paste"
 +
      class="org.eclipse.ui.views.markers.internal.PasteMarkerHandler" />
 +
  <handler commandId="org.eclipse.ui.edit.delete"
 +
      class="org.eclipse.ui.views.markers.internal.RemoveMarkerHandler" />
 +
  <handler commandId="org.eclipse.jdt.ui.edit.text.java.correction.assist.proposals"
 +
      class="org.eclipse.ui.views.markers.internal.ResolveMarkerHandler" />
 +
  <handler commandId="org.eclipse.ui.edit.selectAll"
 +
      class="org.eclipse.ui.views.markers.internal.SelectAllMarkersHandler" />
 +
  <handler commandId="org.eclipse.ui.file.properties"
 +
      class="org.eclipse.ui.views.markers.internal.ProblemPropertiesHandler" />
 +
</extension>
 +
</source>
 +
 
 +
This gives compact markup without inventing a new language.  Elements nested in the handler element could override the extension-wide settings.
 +
 
 +
= Updating the menu and toolbar appearance =
  
== Commands ==
 
  
 
It was suggested in 3.2 that state on the command could be used to implement the old contribution story behaviours:
 
It was suggested in 3.2 that state on the command could be used to implement the old contribution story behaviours:
Line 708: Line 354:
 
#setting the item state (like checked state)
 
#setting the item state (like checked state)
  
In 3.3 the enablement is tied to the command, and for the other behaviours we've decided to go with option 1.
+
In 3.3 the enablement is tied to the command, and for the other behaviours we've decided to go with UIElements approach.
  
Option 1:
+
== UIElements represent each UI visible instance of a command ==
  
The command service keeps a list of registered UI elements, which can be updated by the active handler.
+
The command service keeps a list of registered UI elements, which can be updated by the active handler. The checked state can be updated through <tt>UIElement#setChecked(boolean);</tt> (note that <tt>updateElement</tt> below is from <tt>IElementUpdater</tt>):
  
The checked state can be updated through UIElement#setChecked(boolean);
+
<source lang="java">
 
+
private boolean isChecked() {
private boolean isChecked() {
+
    return getStore().getBoolean(
return getStore().getBoolean(
+
            PreferenceConstants.EDITOR_MARK_OCCURRENCES);
PreferenceConstants.EDITOR_MARK_OCCURRENCES);
+
}
}
+
 
   
 
   
public void updateElement(UIElement element, Map parameters) {
+
public void updateElement(UIElement element, Map parameters) {
element.setChecked(isChecked());
+
    element.setChecked(isChecked());
}
+
}
 +
</source>
  
When the toggle handler runs, it can request that any UI elements have their appearance updated from its execute(*) method:
+
When the toggle handler runs, it can request that any UI elements have their appearance updated from its <tt>execute(*)</tt> method:
  
ICommandService service = (ICommandService) serviceLocator
+
<source lang="java">
.getService(ICommandService.class);
+
ICommandService service = (ICommandService) serviceLocator
service.refreshElements(
+
        .getService(ICommandService.class);
IJavaEditorActionDefinitionIds.TOGGLE_MARK_OCCURRENCES,
+
service.refreshElements(IJavaEditorActionDefinitionIds.TOGGLE_MARK_OCCURRENCES, null);
null);
+
</source>
  
 
+
== State associated with the command is propogated to UI visible elements ==
 
+
Option 2:
+
  
 
First define the toggle mark occurrences command.  Pretty straight forward,
 
First define the toggle mark occurrences command.  Pretty straight forward,
Line 741: Line 385:
 
update the label for the menu/toolbar items, we also add the "NAME" state.
 
update the label for the menu/toolbar items, we also add the "NAME" state.
  
  <extension point="org.eclipse.ui.commands">
+
<source lang="xml">
    <command categoryId="org.eclipse.jdt.ui.category.source"
+
<extension point="org.eclipse.ui.commands">
            description="%jdt.ui.ToggleMarkOccurrences.description"
+
  <command categoryId="org.eclipse.jdt.ui.category.source"
            id="org.eclipse.jdt.ui.edit.text.java.toggleMarkOccurrences"
+
      description="%jdt.ui.ToggleMarkOccurrences.description"
            name="%jdt.ui.ToggleMarkOccurrences.name">
+
      id="org.eclipse.jdt.ui.edit.text.java.toggleMarkOccurrences"
      <state id="NAME" class="org.eclipse.jface.menus.TextState" />
+
      name="%jdt.ui.ToggleMarkOccurrences.name">
      <state id="STYLE" class="org.eclipse.jface.commands.ToggleState:true" />
+
    <state id="NAME" class="org.eclipse.jface.menus.TextState" />
    </command>
+
    <state id="STYLE" class="org.eclipse.jface.commands.ToggleState:true" />
  </extension>
+
  </command>
 +
</extension>
 +
</source>
  
== Handlers ==
+
= Work =
  
This command doesn't have a default handler, as it only applies to specific
+
Progress in 3.3.
editors that are provided. So we would provide the handler for the java editor.
+
  
<extension
+
== Available in 3.3 ==
      point="org.eclipse.ui.handlers">
+
    <handler
+
          class="org.eclipse.jdt.internal.ui.javaeditor.ToggleMarkOccurrencesHandler"
+
          commandId="org.eclipse.jdt.ui.edit.text.java.toggleMarkOccurrences"
+
          helpContextId="org.eclipse.jdt.ui.toggle_mark_occurrences_action_context">
+
      <activeWhen>
+
          <with
+
                variable="activeEditorId">
+
            <or>
+
                <equals
+
                      value="org.eclipse.jdt.ui.CompilationUnitEditor">
+
                </equals>
+
                <equals
+
                      value="org.eclipse.jdt.ui.ClassFileEditor">
+
                </equals>
+
            </or>
+
          </with>
+
      </activeWhen>
+
    </handler>
+
</extension>
+
  
 +
* [[Image:Ok_green.gif]] the editor action bar contributor solution.  EditorActionBarContributor will not be deprecated, but is not used in the commands/handler story.  Menu Contributions have visibility tied to an active editor id, and editor specific handlers can be created in the editor init(*) or createPartControl(*) method using the handler service from getPartSite().getService(IHandlerService.class).
 +
* [[Image:Ok_green.gif]] Attributes for <command/>: '''helpContextId''', '''style''' to support radio buttons and check boxes
 +
* [[Image:Ok_green.gif]] action sets as contexts - action sets are still defined using org.eclipse.ui.actionSets, and each actionSet generates an equivalent context.  showing/hiding actionSets activates/deactivates the equivalent context.
 +
* [[Image:Ok_green.gif]] How do we give Trim widgets/toolbar widgets "focus" for command and handlers?  There was an IFocusService added in 3.3 that allows a trim control to register itself.  When that control has focus, the control and the ID it registered with are provided in the global application context to core expressions and handlers.  This is available, but might not be the optimal solution if you just want cut, copy, and paste to work.
 +
* [[Image:Ok_green.gif]] Shortcuts to define reusable core expressions for <activeWhen/>, <enabledWhen/>, and <visibleWhen/>. This has been added as the org.eclipse.core.expressions.definitions extension point and the core expression <reference/> element.
 +
* [[Image:Ok_green.gif]] the mnemonic field for <command/> elements (decorating)
 +
* [[Image:Ok_green.gif]] display any keybinding for <command/> elements (decorating)
 +
* [[Image:Ok_green.gif]] toolbar <visibleWhen/> expressions
  
We're active for both the Java editor and the Class File editor.  There is also the option to programmatically install the handler.
+
== Available in 3.3M5 ==
  
AndExpression expr = new AndExperssion();
+
There is an example of the RCP Mail application template updated for 3.3M5 and converted to use the org.eclipse.ui.menus extension point as much as possible at [http://dev.eclipse.org/viewcvs/index.cgi/platform-ui-home/R3_3/contributions-proposal/ Contribution Example].
expr.add(new ActivePartIdExpression("org.eclipse.jdt.ui.CompilationUnitEditor"));
+
expr.add(new ActivePartIdExpression("org.eclipse.jdt.ui.ClassFileEditor"));
+
IHandlerService handlerServ = (IHandlerService)getSite().getWorkbenchWindow().getService(IHandlerService.class);
+
toggleOccurrencesHandler = new ToggleMarkOccurrencesHandler();
+
handlerServ.activateHandler("org.eclipse.jdt.ui.edit.text.java.toggleMarkOccurrences", toggleOccurrencesHandler, expr);
+
  
Since the same handler is valid for both editors, we install it with a specific expression and <b>don't</b> tie the activation to the part siteBut as written, the <code>toggleOccurrencesHandler</code> will exist as long as the workbench window exists.
+
* [[Image:Ok_green.gif]]  changing the menu item or tool item state from a handler, like updating the label or tooltip or checked state.  Commands can contain <state/> elements, but that is not appropriate to use for providing feedback to the userThis will be done by adapting a callback provided by the UI element.
 +
* [[Image:Ok_green.gif]] the <separator/> element should have a '''name''' not an '''id'''
 +
* [[Image:Ok_green.gif]] support creating radio button or checked menu items
 +
* [[Image:Ok_green.gif]] creating new toolbars in the main coolbar/trim declaratively
 +
* [[Image:Ok_green.gif]] creating new toolbars in the main coolbar/trim programmatically
 +
* [[Image:Ok_green.gif]] org.eclipse.ui.popup.any as a context menu contribution
 +
* [[Image:Ok_green.gif]] Drop down toolbar items
  
== Menus ==
+
We also have action sets activating and de-activating contexts in '''3.3M5''', but we'll need to decide the proper action set story for '''3.3M6'''
  
In '''3.3M5''' ActionSets generate and update active contexts.
+
We are still working on the EditorActionBarContributor story. It seems like we might be able to deprecate it.  Editor instances can instantiate handlers upon creation for each command they support.
  
 +
== Available in 3.3M4 ==
  
  <extension
+
The basic menu API will be available in 3.3M4. It includes both declarative '''org.eclipse.ui.menus''' extension point with core expression support for visibility, and a programmatic interface accessed through the <code>IMenuService</code>.
        point="org.eclipse.ui.menus">
+
      <menuContribution
+
            locationURI="toolbar:org.eclipse.ui.main.toolbar?after=additions">
+
        <toolbar
+
              id="org.eclipse.ui.edit.text.actionSet.presentation">
+
            <command
+
                  commandId="org.eclipse.jdt.ui.edit.text.java.toggleMarkOccurrences"
+
                  disabledIcon="$nl$/icons/full/dtool16/mark_occurrences.gif"
+
                  helpContextId="toggle_mark_occurrences_action_context"
+
                  icon="$nl$/icons/full/etool16/mark_occurrences.gif"
+
                  id="org.eclipse.jdt.ui.edit.text.java.toggleMarkOccurrences"
+
                  label="%toggleMarkOccurrences.label"
+
                  style="toggle"
+
                  tooltip="%toggleMarkOccurrences.tooltip">
+
              <visibleWhen
+
                    checkEnabled="false">
+
                  <with
+
                        variable="activeContexts">
+
                    <iterate
+
                          operator="or">
+
                        <equals
+
                              value="org.eclipse.jdt.ui.text.java.actionSet.presentation">
+
                        </equals>
+
                    </iterate>
+
                  </with>
+
              </visibleWhen>
+
            </command>
+
        </toolbar>
+
      </menuContribution>
+
  </extension>
+
  
  
This item is also tied to an actionSet.
+
We support contributing to the main menu, and the view menu, view toolbar, and any IDed context menu.  We support contributing to existing toolbars in the main coolbar, and contributing trim widgets.
  
== Menus API ==
+
Programmatically we support the following types of contributions:
 +
*MenuManager
 +
*CommandContributionItem
 +
*CompoundContributionItem
 +
*ControlContribution (in 3.3M5)
 +
*Separator
 +
*GroupMarker
  
The above XML can be done using the menus API:
+
There are some specific mappings of elements and attributes on [[Menus Extension Mapping]].
  
public static void createToggleMarkOccurrences() {
 
    final IMenuService menuService = (IMenuService) PlatformUI
 
            .getWorkbench().getService(IMenuService.class);
 
    final ImageDescriptor markOccurDesc = AbstractUIPlugin
 
            .imageDescriptorFromPlugin("org.eclise.ui.tests",
 
                    "icons/full/etool16/mark_occurrences.gif");
 
    final ImageDescriptor disabledMarkOccurDesc = AbstractUIPlugin
 
            .imageDescriptorFromPlugin("org.eclise.ui.tests",
 
                    "icons/full/dtool16/mark_occurrences.gif");
 
 
    AbstractContributionFactory contribution = new AbstractContributionFactory(
 
            "toolbar:org.eclipse.ui.edit.text.actionSet.presentation?after=Presentation") {
 
        public void createContributionItems(IMenuService menuService,
 
                List additions) {
 
            IContributionItem item = new CommandContributionItem(
 
                    null,
 
                    "org.eclipse.jdt.ui.edit.text.java.toggleMarkOccurrences",
 
                    null, markOccurDesc, disabledMarkOccurDesc, null, null,
 
                    null, "Toggle Mark Occurrences", CommandContributionItem.STYLE_CHECK);
 
            menuService
 
                    .registerVisibleWhen(
 
                            item,
 
                            new ActiveActionSetExpression(
 
                                    "org.eclipse.jdt.ui.text.java.actionSet.presentation"));
 
            additions.add(item);
 
        }
 
 
        public void releaseContributionItems(IMenuService menuService,
 
                List items) {
 
        }
 
    };
 
    menuService.addContributionFactory(contribution);
 
}
 
  
 +
== Work still to be done ==
  
This asks for a toolbar root in the org.eclipse.ui.edit.text.actionSet.presentation toolbar after the Presentation id.
 
  
It's contributed with a visibleWhen clause <code>ActiveActionSetExpression("org.eclipse.jdt.ui.text.java.actionSet.presentation")</code>, so it will be visible when the actionSet is active.
+
A list of behaviours not supported or shipped with '''3.3'''.
  
= Possible Java Search Menu Example =
+
* validate and possibly optimize the context menu population story and lifecycle.  Many context menus set remove all when shown.
 +
* migrate Marker views
 +
* migrate standard workbench actions - a few were done
 +
* Check enabled visibleWhen support
 +
* Shortcuts placed on submenu items (like CTRL+N) (decorating)
 +
* ensure full visibleWhen support in the MenuManagers - i.e. should empty menus display '''(empty)'''
 +
* do we want to manage trim with a TrimContributionManager?  This removes the coolbar, but has RCP implications.
 +
* the menu override capability - does this tie into the Customize Perspective dialog and action sets
 +
* A set of default programmatic core expressions.  For example, ActionContextExpression or ActivePartExpression
 +
* deprecate the 4 extension: actionSets, viewActions, editorActions, popupMenus
 +
* read old extensions in terms of new extension
 +
* convert platform UI extensions to new extension
 +
* migration guide - what are the most common migration paths for Action and IActionDelegate to Command/IHandler.
 +
* Attributes for <command/>:  '''state''' for checkboxes and radio buttons
 +
* possibly provide an plugin.xml converter for actionSets to menus
 +
* possibly provide an Action -> Handler converter
 +
* [[Image:Error.gif]] status manager contributions
  
The java search menu items are added through a Java Search action set.  They have code that enables/disables the action set depending on the active editor.
 
  
== ActionSet context ==
+
Legend:
 +
* nothing - TBD
 +
* [[Image:Glass.gif]] - investigating
 +
* [[Image:Progress.gif]] - in progress
 +
* [[Image:Ok_green.gif]] - completed
 +
* [[Image:Error.gif]] - dropped
  
 
+
[[Category:Eclipse Project]]
For something to go in an actionSet, then we would define the actionSet context.  This hasn't be worked out for '''3.3M5''', we still define an actionSet using org.eclipse.ui.actionSets.
+
 
+
  <extension point="org.eclipse.ui.contexts">
+
    <context description="%JavaSearchActionSet.description"
+
            id="org.eclipse.jdt.ui.SearchActionSet"
+
            name="%JavaSearchActionSet.label"
+
            parentId="org.eclipse.ui.contexts.actionSet">
+
    </context>
+
  </extension>
+
 
+
== Commands ==
+
 
+
Also, a number of the items were retargetable actions that allow label updates.  The active handler can update their appearance with an ICommandService@refreshElements(*) call.
+
 
+
  <extension point="org.eclipse.ui.commands">
+
    <command name="%ActionDefinition.readAccessInworkspace.name"
+
            description="%ActionDefinition.readAccessInWorkspace.description"
+
            categoryId="org.eclipse.search.ui.category.search"
+
            id="org.eclipse.jdt.ui.edit.text.java.search.read.access.in.workspace">
+
    </command>
+
    <command name="%ActionDefinition.readAccessInProject.name"
+
            description="%ActionDefinition.readAccessInProject.description"
+
            categoryId="org.eclipse.search.ui.category.search"
+
            id="org.eclipse.jdt.ui.edit.text.java.search.read.access.in.project">
+
    </command>
+
    <command name="%ActionDefinition.readAccessInHierarchy.name"
+
            description="%ActionDefinition.readAccessInHierarchy.description"
+
            categoryId="org.eclipse.search.ui.category.search"
+
            id="org.eclipse.jdt.ui.edit.text.java.search.read.access.in.hierarchy">
+
    </command>
+
    <command name="%ActionDefinition.readAccessInWorkingSet.name"
+
            description="%ActionDefinition.readAccessInWorkingSet.description"
+
            categoryId="org.eclipse.search.ui.category.search"
+
            id="org.eclipse.jdt.ui.edit.text.java.search.read.access.in.working.set">
+
    </command>
+
    <command name="%ActionDefinition.writeAccessInWorkspace.name"
+
            description="%ActionDefinition.writeAccessInWorkspace.description"
+
            categoryId="org.eclipse.search.ui.category.search"
+
            id="org.eclipse.jdt.ui.edit.text.java.search.write.access.in.workspace">
+
    </command>
+
    <command name="%ActionDefinition.writeAccessInProject.name"
+
            description="%ActionDefinition.writeAccessInProject.description"
+
            categoryId="org.eclipse.search.ui.category.search"
+
            id="org.eclipse.jdt.ui.edit.text.java.search.write.access.in.project">
+
    </command>
+
    <command name="%ActionDefinition.writeAccessInHierarchy.name"
+
            description="%ActionDefinition.writeAccessInHierarchy.description"
+
            categoryId="org.eclipse.search.ui.category.search"
+
            id="org.eclipse.jdt.ui.edit.text.java.search.write.access.in.hierarchy">
+
    </command>
+
    <command name="%ActionDefinition.writeAccessInWorkingSet.name"
+
            description="%ActionDefinition.writeAccessInWorkingSet.description"
+
            categoryId="org.eclipse.search.ui.category.search"
+
            id="org.eclipse.jdt.ui.edit.text.java.search.write.access.in.working.set">
+
    </command>
+
  </extension>
+
 
+
== Menus ==
+
 
+
 
+
We'll assume that the Search menu is globally defined elsewhere by the org.eclipse.search plugin.
+
 
+
  <extension point="org.eclipse.ui.menus">
+
      <menuContribution locationURI="menu:org.eclipse.ui.main.menu?after=navigate">
+
        <menu label="%searchMenu.label"
+
              mnemonic="%searchMenu.mnemonic"
+
              id="org.eclipse.search.menu">
+
            <!-- not to be used by clients  -->
+
            <separator name="internalDialogGroup" visible="false" />
+
            <!-- to be used by clients -->
+
            <separator name="dialogGroup" visible="false" />
+
            <!-- to be used by clients      -->
+
            <separator name="fileSearchContextMenuActionsGroup"
+
                      visible="true" />
+
            <!-- to be used by clients      -->
+
            <separator name="contextMenuActionsGroup" visible="true" />
+
            <!-- to be used by clients -->
+
            <separator name="occurencesActionsGroup" visible="true" />
+
            <!-- to be used by clients -->
+
            <separator name="extraSearchGroup" visible="true" />
+
        </menu>
+
      </menuContribution>
+
  </extension>
+
 
+
Then the JDT plugin would contribute the menu items to search, where the menuContribution location specifies the starting point for adding the menus.  For groups of actions like the Write Access or Read Access shown here, they can just be specified in order.  The <visibleWhen/> clauses must be specified on the items contributed if they want to belong to the actionSet, but if the contribute items are contain in a contributed menu, it can just be specified on the <menu/> element.
+
 
+
 
+
  <extension point="org.eclipse.ui.menus">
+
      <menuContribution locationURI="menu:org.eclipse.search.menu?after=dialogGroup">
+
        <command commandId="org.eclipse.jdt.internal.ui.search.openJavaSearchPage"
+
                  label="%openJavaSearchPageAction.label"
+
                  mnemonic="%openJavaSearchPageAction.mnemonic"
+
                  icon="$nl$/icons/full/obj16/jsearch_obj.gif"
+
                  helpContextId="java_search_action_context">
+
            <visibleWhen>
+
              <with variable="activeContexts">
+
                  <iterate operator="or">
+
                    <equals value="org.eclipse.jdt.ui.SearchActionSet">
+
                    </equals>
+
                  </iterate>
+
              </with>
+
            </visibleWhen>
+
        </command>
+
      </menuContribution>
+
      <menuContribution locationURI="menu:org.eclipse.search.menu?after=contextMenuActionsGroup">
+
        <menu id="readAccessSubMenu"
+
              label="%readAccessSubMenu.label"
+
              mnemonic="%readAccessSubMenu.mnemonic">
+
            <separator name="group1" visible="false" />
+
            <command commandId="org.eclipse.jdt.ui.edit.text.java.search.read.access.in.workspace"
+
                    label="%InWorkspace.label"
+
                    mnemonic="%InWorkspace.mnemonic">
+
            </command>
+
            <command commandId="org.eclipse.jdt.ui.edit.text.java.search.read.access.in.project"
+
                    label="%InProject.label"
+
                    mnemonic="%InProject.mnemonic">
+
            </command>
+
            <command commandId="org.eclipse.jdt.ui.edit.text.java.search.read.access.in.hierarchy"
+
                    label="%InHierarchy.label"
+
                    mnemonic="%InHierarchy.mnemonic">
+
            </command>
+
            <command commandId="org.eclipse.jdt.ui.edit.text.java.search.read.access.in.working.set"
+
                    label="%InWorkingSet.label"
+
                    mnemonic="%InWorkingSet.mnemonic">
+
            </command>
+
            <visibleWhen>
+
              <with variable="activeContexts">
+
                  <iterate operator="or">
+
                    <equals value="org.eclipse.jdt.ui.SearchActionSet">
+
                    </equals>
+
                  </iterate>
+
              </with>
+
            </visibleWhen>
+
        </menu>
+
        <menu id="writeAccessSubMenu"
+
              label="%writeAccessSubMenu.label"
+
              mnemonic="%writeAccessSubMenu.mnemonic">
+
            <separator name="group1" visible="false" />
+
            <command commandId="org.eclipse.jdt.ui.edit.text.java.search.write.access.in.workspace"
+
                    label="%InWorkspace.label"
+
                    mnemonic="%InWorkspace.mnemonic">
+
            </command>
+
            <command commandId="org.eclipse.jdt.ui.edit.text.java.search.write.access.in.project"
+
                    label="%InProject.label"
+
                    mnemonic="%InProject.mnemonic">
+
            </command>
+
            <command commandId="org.eclipse.jdt.ui.edit.text.java.search.write.access.in.hierarchy"
+
                    label="%InHierarchy.label"
+
                    mnemonic="%InHierarchy.mnemonic">
+
            </command>
+
            <command commandId="org.eclipse.jdt.ui.edit.text.java.search.write.access.in.working.set"
+
                    label="%InWorkingSet.label"
+
                    mnemonic="%InWorkingSet.mnemonic">
+
            </command>
+
            <visibleWhen>
+
              <with variable="activeContexts">
+
                  <iterate operator="or">
+
                    <equals value="org.eclipse.jdt.ui.SearchActionSet">
+
                    </equals>
+
                  </iterate>
+
              </with>
+
            </visibleWhen>
+
        </menu>
+
      </menuContribution>
+
      <menuContribution locationURI="menu:org.eclipse.search.menu?after=occurencesActionsGroup">
+
        <command commandId="org.eclipse.jdt.ui.edit.text.java.search.occurrences.in.file.quickMenu"
+
                  label="%occurrencesSubMenu.label">
+
            <visibleWhen>
+
              <with variable="activeContexts">
+
                  <iterate operator="or">
+
                    <equals value="org.eclipse.jdt.ui.SearchActionSet">
+
                    </equals>
+
                  </iterate>
+
              </with>
+
            </visibleWhen>
+
        </command>
+
      </menuContribution>
+
  </extension>
+
 
+
 
+
Currently, the java search menus are in the Java Search actionSet, that is dynamically enabled/disabled.  This could also be done by specifying a visibleWhen like:
+
 
+
<visibleWhen>
+
  <with variable="activeEditorId">
+
    <or>
+
      <equals value="org.eclipse.jdt.ui.CompilationUnitEditor" />
+
      <equals value="org.eclipse.jdt.ui.ClassFileEditor" />
+
    </or>
+
  </with>
+
</visibleWhen>
+
 
+
This would make the visible if either the Java or Class File editor was the active editor, and they would disappear otherwise.
+
 
+
== Menus API ==
+
 
+
The API can be used to contribute to the main menu bar:
+
 
+
    public static void addSearchMenu() {
+
        IMenuService menuService = (IMenuService) PlatformUI.getWorkbench()
+
                .getService(IMenuService.class);
+
+
        AbstractContributionFactory searchContribution = new AbstractContributionFactory(
+
                "menu:org.eclipse.ui.main.menu?after=navigate") {
+
            public void createContributionItems(IMenuService menuService,
+
                    List additions) {
+
                MenuManager search = new MenuManager("Se&arch",
+
                        "org.eclipse.search.menu");
+
+
                search.add(new GroupMarker("internalDialogGroup"));
+
                search.add(new GroupMarker("dialogGroup"));
+
                search.add(new Separator("fileSearchContextMenuActionsGroup"));
+
                search.add(new Separator("contextMenuActionsGroup"));
+
                search.add(new Separator("occurencesActionsGroup"));
+
                search.add(new Separator("extraSearchGroup"));
+
+
                additions.add(search);
+
            }
+
+
            public void releaseContributionItems(IMenuService menuService,
+
                    List items) {
+
                // nothing to do here
+
            }
+
        };
+
+
        menuService.addContributionFactory(searchContribution);
+
    }
+
 
+
 
+
It's just a menu inserted at the menu root location.
+
 
+
 
+
Then another plugin can contribute to the search menu:
+
 
+
    public static void addToSearchMenu() {
+
        final IMenuService menuService = (IMenuService) PlatformUI
+
                .getWorkbench().getService(IMenuService.class);
+
        final ActiveActionSetExpression activeSearchActionSet = new ActiveActionSetExpression(
+
                "org.eclipse.jdt.ui.SearchActionSet");
+
+
        final ImageDescriptor searchIcon = AbstractUIPlugin
+
                .imageDescriptorFromPlugin("org.eclise.ui.tests",
+
                        "icons/full/obj16/jsearch_obj.gif");
+
        AbstractContributionFactory factory = new AbstractContributionFactory(
+
                "menu:org.eclipse.search.menu?after=dialogGroup") {
+
            public void createContributionItems(IMenuService menuService,
+
                    List additions) {
+
                CommandContributionItem item = new CommandContributionItem(
+
                        "org.eclipse.jdt.internal.ui.search.openJavaSearchPage",
+
                        "org.eclipse.jdt.internal.ui.search.openJavaSearchPage",
+
                        null, searchIcon, null, null, null, null, null,
+
                        CommandContributionItem.STYLE_PUSH);
+
                menuService.registerVisibleWhen(item, activeSearchActionSet);
+
                additions.add(item);
+
            }
+
+
            public void releaseContributionItems(IMenuService menuService,
+
                    List items) {
+
            }
+
        };
+
        menuService.addContributionFactory(factory);
+
+
        factory = new AbstractContributionFactory(
+
                "menu:org.eclipse.search.menu?after=contextMenuActionsGroup") {
+
            public void createContributionItems(IMenuService menuService,
+
                    List additions) {
+
                MenuManager readMenu = new MenuManager("&Read Access",
+
                        "readAccessSubMenu");
+
                menuService
+
                        .registerVisibleWhen(readMenu, activeSearchActionSet);
+
                additions.add(readMenu);
+
+
                readMenu.add(new GroupMarker("group1"));
+
+
                CommandContributionItem item = new CommandContributionItem(
+
                        "org.eclipse.jdt.ui.edit.text.java.search.read.access.in.workspace",
+
                        "org.eclipse.jdt.ui.edit.text.java.search.read.access.in.workspace",
+
                        null, null, null, null, null, "W", null,
+
                        CommandContributionItem.STYLE_PUSH);
+
                readMenu.add(item);
+
                item = new CommandContributionItem(
+
                        "org.eclipse.jdt.ui.edit.text.java.search.read.access.in.project",
+
                        "org.eclipse.jdt.ui.edit.text.java.search.read.access.in.project",
+
                        null, null, null, null, null, "P", null,
+
                        CommandContributionItem.STYLE_PUSH);
+
                readMenu.add(item);
+
                item = new CommandContributionItem(
+
                        "org.eclipse.jdt.ui.edit.text.java.search.read.access.in.hierarchy",
+
                        "org.eclipse.jdt.ui.edit.text.java.search.read.access.in.hierarchy",
+
                        null, null, null, null, null, "H", null,
+
                        CommandContributionItem.STYLE_PUSH);
+
                readMenu.add(item);
+
                item = new CommandContributionItem(
+
                        "org.eclipse.jdt.ui.edit.text.java.search.read.access.in.working.set",
+
                        "org.eclipse.jdt.ui.edit.text.java.search.read.access.in.working.set",
+
                        null, null, null, null, null, "S", null,
+
                        CommandContributionItem.STYLE_PUSH);
+
                readMenu.add(item);
+
+
                MenuManager writeMenu = new MenuManager("&Write Access",
+
                        "writeAccessSubMenu");
+
                menuService.registerVisibleWhen(writeMenu,
+
                        activeSearchActionSet);
+
                additions.add(writeMenu);
+
+
                writeMenu.add(new GroupMarker("group1"));
+
+
                item = new CommandContributionItem(
+
                        "org.eclipse.jdt.ui.edit.text.java.search.write.access.in.workspace",
+
                        "org.eclipse.jdt.ui.edit.text.java.search.write.access.in.workspace",
+
                        null, null, null, null, null, "W", null,
+
                        CommandContributionItem.STYLE_PUSH);
+
                writeMenu.add(item);
+
                item = new CommandContributionItem(
+
                        "org.eclipse.jdt.ui.edit.text.java.search.write.access.in.project",
+
                        "org.eclipse.jdt.ui.edit.text.java.search.write.access.in.project",
+
                        null, null, null, null, null, "P", null,
+
                        CommandContributionItem.STYLE_PUSH);
+
                writeMenu.add(item);
+
                item = new CommandContributionItem(
+
                        "org.eclipse.jdt.ui.edit.text.java.search.write.access.in.hierarchy",
+
                        "org.eclipse.jdt.ui.edit.text.java.search.write.access.in.hierarchy",
+
                        null, null, null, null, null, "H", null,
+
                        CommandContributionItem.STYLE_PUSH);
+
                writeMenu.add(item);
+
                item = new CommandContributionItem(
+
                        "org.eclipse.jdt.ui.edit.text.java.search.write.access.in.working.set",
+
                        "org.eclipse.jdt.ui.edit.text.java.search.write.access.in.working.set",
+
                        null, null, null, null, null, "S", null,
+
                        CommandContributionItem.STYLE_PUSH);
+
                writeMenu.add(item);
+
            }
+
+
            public void releaseContributionItems(IMenuService menuService,
+
                    List items) {
+
            }
+
        };
+
        menuService.addContributionFactory(factory);
+
    }
+
 
+
 
+
 
+
When the main menu is populated, these contribution factories will be called.
+
 
+
= IFile object contribution =
+
 
+
We also have to provide object contributions (which in the past were scoped by objectClass).
+
 
+
== Menus ==
+
 
+
There will be a reserved popup ID, "org.eclipse.ui.popup.any" that will allow contributions to any popup menu.
+
 
+
  <extension point="org.eclipse.ui.menus">
+
    <menuContribution locationURI="popup:org.eclipse.ui.popup.any?after=additions">
+
      <command commandId="org.eclipse.ui.examples.wiki.post"
+
            mnemonic="%WikiExample.post.mnemonic"
+
            icon="$nl$/icons/full/elcl16/post_wiki.gif">
+
        <visibleWhen>
+
          <with variable="selection">
+
            &lt;!-- do something with an ISelection --&gt;
+
          </with>
+
        </visibleWhen>
+
      </command>
+
      <command commandId="org.eclipse.ui.examples.wiki.load"
+
            mnemonic="%WikiExample.load.mnemonic"
+
            icon="$nl$/icons/full/elcl16/load_wiki.gif">
+
        <visibleWhen
+
              checkEnabled="false">
+
            &lt;!-- the default variable is a Collection holding the ISelection,
+
                    or the objects from an IStructuredSelection --&gt;
+
            <iterate>
+
              <adapt
+
                    type="org.eclipse.core.resources.IResource">
+
              </adapt>
+
            </iterate>
+
        </visibleWhen>
+
      </command>
+
    </menuContribution>
+
  </extension>
+
 
+
 
+
 
+
It's probably that the default variable for core expression evaluations would be <b>selection</b>, so you wouldn't need the <with/> clause like in the second item above.
+
 
+
There would probably also be a short-hand to tie the visibility to an active handler.  Maybe <visibleWhen handler="true"/>  This is still conjecture.
+
 
+
== Menus API ==
+
 
+
So programmatically it is similar to all other menu contributions.
+
 
+
public static void addFileContribution() {
+
    final IMenuService menuService = (IMenuService) PlatformUI
+
            .getWorkbench().getService(IMenuService.class);
+
    // an expression that walks the selection looking for objectclasses
+
    final ObjectClassExpression ifileExpression = new ObjectClassExpression(
+
            "org.eclipse.core.resources.IFile");
+
+
    final ImageDescriptor postIcon = AbstractUIPlugin
+
            .imageDescriptorFromPlugin("org.eclise.ui.tests",
+
                    "icons/full/elcl16/post_wiki.gif");
+
    final ImageDescriptor loadIcon = AbstractUIPlugin
+
            .imageDescriptorFromPlugin("org.eclise.ui.tests",
+
                    "icons/full/elcl16/load_wiki.gif");
+
    AbstractContributionFactory factory = new AbstractContributionFactory(
+
            "popup:org.eclipse.ui.popup.any?after=additions") {
+
        public void createContributionItems(IMenuService menuService,
+
                List additions) {
+
            CommandContributionItem item = new CommandContributionItem(
+
                    "org.eclipse.ui.examples.wiki.post",
+
                    "org.eclipse.ui.examples.wiki.post", null, postIcon,
+
                    null, null, null, "P", null,
+
                    CommandContributionItem.STYLE_PUSH);
+
            menuService.registerVisibleWhen(item, ifileExpression);
+
            additions.add(item);
+
+
            item = new CommandContributionItem(
+
                    "org.eclipse.ui.examples.wiki.load",
+
                    "org.eclipse.ui.examples.wiki.load", null, loadIcon,
+
                    null, null, null, "L", null,
+
                    CommandContributionItem.STYLE_PUSH);
+
            menuService.registerVisibleWhen(item, ifileExpression);
+
            additions.add(item);
+
        }
+
+
        public void releaseContributionItems(IMenuService menuService,
+
                List items) {
+
        }
+
    };
+
    menuService.addContributionFactory(factory);
+
}
+
 
+
 
+
 
+
The location of org.eclipse.ui.popup.any specifies any context menu, and the expression ties it to a specific objectClass.  Using the new expression syntax you can make your conditions more complex.
+
 
+
You can set your visibleWhen expression on each item as you create it.
+
 
+
= Text editor popup action =
+
 
+
Popups can be targetted at any registered context menu, or at all of them.  This is the Scramble Text command to be added the the standard text editor.
+
 
+
== Commands ==
+
 
+
First define the command and its handler.
+
 
+
  <extension point="org.eclipse.ui.commands">
+
    <command id="org.eclipse.ui.examples.menus.scramble.text"
+
            defaultHandler="org.eclipse.ui.examples.menus.internal.ScrambleTextHandler"
+
            name="%ScrambleText.name"
+
            description="%ScrambleText.description" />
+
  </extension>
+
 
+
== Menus ==
+
 
+
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">
+
    <menuContribution locationURI="popup:#TextEditorContext?after=additions">
+
      <command commandId="org.eclipse.ui.examples.menus.scramble.text"
+
            mnemonic="%ScrambleText.mnemonic"
+
            icon="$nl$/icons/full/eobj16/scramble.gif" />
+
    </menuContribution>
+
  </extension>
+
 
+
== Menus API ==
+
 
+
Programmatically do this, you would have to go through the IMenuService.
+
 
+
 
+
public static void addTextMenuContribition() {
+
    final IMenuService menuService = (IMenuService) PlatformUI
+
            .getWorkbench().getService(IMenuService.class);
+
+
    final ImageDescriptor scrambleIcon = AbstractUIPlugin
+
            .imageDescriptorFromPlugin("org.eclise.ui.tests",
+
                    "icons/full/eobj16/scramble.gif");
+
    AbstractContributionFactory factory = new AbstractContributionFactory(
+
            "popup:#TextEditorContext?after=additions") {
+
        public void createContributionItems(IMenuService menuService,
+
                List additions) {
+
            CommandContributionItem item = new CommandContributionItem(
+
                    "org.eclipse.ui.examples.menus.scramble.text",
+
                    "org.eclipse.ui.examples.menus.scramble.text",
+
                    null, scrambleIcon, null, null, null, "c", null,
+
                    CommandContributionItem.STYLE_PUSH);
+
            additions.add(item);
+
        }
+
+
        public void releaseContributionItems(IMenuService menuService,
+
                List items) {
+
        }
+
    };
+
    menuService.addContributionFactory(factory);
+
}
+
 
+
= Product removes the Project menu =
+
 
+
'''Note:''' this might not make it into 3.3
+
 
+
An RCP product wishes to remove the Project menu.  It should be possible to override the visibility of menu contributions.
+
 
+
    public void addOverride() {
+
        // the RCP app would already have its product key
+
        Object productKey = null;
+
+
        IMenuService menuServ = (IMenuService) PlatformUI.getWorkbench()
+
                .getActiveWorkbenchWindow().getService(IMenuService.class);
+
        menuServ.addOverride(productKey, "menu:project", new OverrideAdapter() {
+
            public Boolean getVisible() {
+
                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 <code>null</code> the next level of visibility is evaluated.  The <code>null</code> case is to keep it consistent with other overrides.
+
 
+
The override service is ID based.  For items which haven't specified their ID, the override will be applied to the commandId (which is required on every item).
+
 
+
 
+
 
+
= Widget in the main toolbar =
+
 
+
You can use the extension point to contribute a control to the toolbar.  You use the <control/> element instead of the <command/> element.
+
 
+
  <extension point="org.eclipse.ui.menus">
+
    <menuContribution locationURI="toolbar:org.eclipse.search.toolbar">
+
      <control id="org.eclipse.ui.examples.menus.searchBar"
+
              class="org.eclipse.ui.examples.menus.internal.SearchBar">
+
        <visibleWhen>
+
          <with variable="activeContexts">
+
            <iterator operator="or">
+
              <equals value="org.eclipse.jdt.ui.SearchActionSet" />
+
            </iterator>
+
          </with>
+
        </visibleWhen>
+
      </control>
+
    </menuContribution>
+
  </extension>
+
 
+
 
+
The control class must implement WorkbenchWindowControlContribution as of '''3.3M5'''.
+
 
+
 
+
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.  It looks like we'll deprecate it in favour of WorkbenchWindowControlContribution.
+
 
+
Also, there are risks associated with this like eager plugin activation.  Maybe we allow widget activation but restrict it to programmatic API only (after the plugin has been instantiated) or still allow declarative contributions but only with certain types of <visibleWhen/> clauses.
+
 
+
--[[User:Hudsonr.us.ibm.com|Hudsonr.us.ibm.com]] 09:02, 13 February 2007 (EST)
+
There are two separate reasons to use an extension point to contribute to the toolbar. One reason is to defer plug-in activation. But the other, is to allow a plug-in to contribute to another plug-in even though it depends on that plug-in, or it ships as additional, add-on function.  In either case, the plug-in owning the toolbar can not depend on the contributing plug-in. While in general, one wants plug-in activation to occur as late as possible, there are cases where you just don't care. It's great to see that I can now contribute anything I want to another plug-in's toolbar.
+
 
+
I think this flexibility needs to be supported. Isn't it possible for a bundle to specify exceptions that would prevent the bundle from being started even though the contribution's classes are loaded to create the Control?
+
 
+
:While we're still looking at this in '''3.3M6''' the preliminary implementation will probably be our standard proxy pattern.  That means that contributing a control to the main toolbar will just start the contributing plugin (so we'll just ask people to be careful :-).  But as an aside, I'm pretty sure that an exception that prevents a bundle from being started will also prevent us from getting the plugin control contribution from IConfigurationElement#createExecutableExtension(*)
+
:--[[User:Pwebster.ca.ibm.com|Pwebster.ca.ibm.com]] 10:34, 13 February 2007 (EST)
+
 
+
= Edit-&gt;Undo relabel action =
+
 
+
The active handler can update any UI elements registered against the its command.  It does this by requesting the ICommandService to refresh any registered UIElements.
+
 
+
Like the Undo action, sometimes menu items would want to allow their label to be updated.  The active handler can update the menu item.
+
 
+
<extension
+
      point="org.eclipse.ui.commands">
+
  <extension point="org.eclipse.ui.menus">
+
    <menuContribution locationURI="menu:edit?after=undo.ext">
+
      <command commandId="org.eclipse.ui.examples.menus.targettedUndo"
+
            mnemonic="%TargettedUndo.mnemonic" />
+
    </menuContribution>
+
  </extension>
+
 
+
As a handler becomes active and implement IElementUpdater like org.eclipse.ui.tests.menus.ToggleContextHandler, the command service calls <code>public void updateElement(UIElement element, Map parameters)</code> for every UIElement registered against the command.
+
 
+
public class ToggleContextHandler extends AbstractHandler implements
+
IElementUpdater {
+
private static final String TOGGLE_ID = "toggleContext.contextId";
+
// ...
+
public void updateElement(UIElement element, Map parameters) {
+
// the checked state depends on if we have an activation for that
+
// context ID or not
+
String contextId = (String) parameters.get(TOGGLE_ID);
+
element.setChecked(contextActivations.get(contextId) != null);
+
}
+
}
+
 
+
 
+
 
+
= Adding programmatic menus and handlers tied to an editor =
+
 
+
In '''3.3M6''' we'll be investigating deprecating EditorActionBarContributors.  The command and menu contributions are declared (and the handler can be as well).
+
 
+
But each editor could instantiate handlers with specific editor instance knowledge and activate them through the part site handler service.  This would take care of activating them and cleaning them up when the part goes away.
+
 
+
 
+
= Add a dynamic submenu to the ProblemView menu =
+
 
+
In [[#Add ProblemView menus|Add ProblemView menus]] we added 2 dynamic menus.  You then have to implement CompoundContributionItem in your provided class.
+
 
+
      <menu id="org.eclipse.ui.views.problems.groupBy.menu"
+
            label="%ProblemView.GroupBy.label"
+
            mnemonic="%ProblemView.GroupBy.mnemonic">
+
        <dynamic class="org.eclipse.ui.views.markers.internal.GroupByItems"
+
                id="org.eclipse.ui.views.problems.groupBy.items"/>
+
      </menu>
+
 
+
 
+
When your menu is populated, you'll have your getContributionItems() method called:
+
 
+
 
+
protected IContributionItem[] getContributionItems() {
+
      IContributionItem[] list = new IContributionItem[2];
+
      Map parms = new HashMap();
+
      parms.put("groupBy", "Severity");
+
      list[0] = new CommandContributionItem(null,
+
              "org.eclipse.ui.views.problems.grouping",
+
              parms, null, null, null, "Severity", null,
+
              null, CommandContributionItem.STYLE_PUSH);
+
+
      parms = new HashMap();
+
      parms.put("groupBy", "None");
+
      list[1] = new CommandContributionItem(null,
+
              "org.eclipse.ui.views.problems.grouping",
+
              parms, null, null, null, "None", null, null,
+
              CommandContributionItem.STYLE_PUSH);
+
      return list;
+
}
+
 
+
 
+
= Dynamic item replacement =
+
 
+
See [[#Add_a_dynamic_submenu_to_the_ProblemView_menu|Add_a_dynamic_submenu_to_the_ProblemView_menu]]
+
 
+
A dynamic contribution item is expanded in place.  It disposes the provided IContributionItems and requests new ones on every show.
+
 
+
= Example Matrix =
+
 
+
This will be updated later.
+
 
+
{| class="wikitable" border="1"
+
|-
+
! Example !! Location !! visible when !! enabled when !! defined by !! placed by !! handled by !! comments
+
|-
+
| [[#Add ProblemView menus|Add ProblemView menus]] || view menu || always || always || ViewPart & IActionBars || ViewPart & IActionBars || SampleViewAction
+
|-
+
|}
+

Latest revision as of 15:48, 24 December 2012

Placement examples that describe the proposed new way of placing menu items for 3.3. Please contribute comments and suggestions in the discussion area or on Bug 154130 -KeyBindings- Finish re-work of commands and key bindings.

Contents

[edit] Placement and visibility

The 4 extension points that deal with menus now org.eclipse.ui.actionSets, org.eclipse.ui.viewActions, org.eclipse.ui.editorActions, and org.eclipse.ui.popupMenus specify both menu placement and their visibility criteria. In the new menu mechanism they are separate concepts, placement and visibility.

[edit] Example Matrix

A (hopefully) growing list of menu contribution examples.

Example comments
Menu Contributions/Dropdown Command Dropdown tool items can have their menus filled in using menu contributions
Menu Contributions/Problems View Example An example showing how the Problems View might be converted
Menu Contributions/Populating a dynamic submenu A menu contribution to populate a Problems View dynamic submenu
Menu Contributions/Toggle Mark Occurrences Placing the toggle mark occurrences button
Menu Contributions/Toggle Button Command Contribute a toggle state menu item thru commands
Menu Contributions/Radio Button Command Similar to updating toggle state, you can create radio buttons using menu contributions
Menu Contributions/Update checked state The active handler can update the checked state (and other attributes) of its button
Menu Contributions/Search Menu Adding the Java Search options to the Search menu
Menu Contributions/IFile objectContribution A menu contribution for context menus when the selection is an IFile
Menu Contributions/TextEditor viewerContribution A menu contribution for the text editor context menu
Menu Contributions/Widget in a toolbar A menu contribution adding a control into the main toolbar
Menu Contributions/RCP removes the Project menu An RCP application removes the Project menu. Note: this will probably not be in 3.3
Menu Contributions/Workbench wizard contribution Contributing workbench wizards to Menu

[edit] Menu XML

Declarative information ... this needs to be cleaned up.

[edit] Declarative menus - some constraints

Some constraints on the system:

  1. Identifiers (id) for <menu/> elements must be globally unique.
  2. Identifiers (id) for <command/> elements must be globally unique if they are specified.
  3. You can reference a <menu/> by id.
  4. If you are just creating menu items for your commands, you can leave them with only a command id. You don't have to specify an item id.
  5. You can reference a <command/> for placement options (after, before, etc.) by id.
  6. <separator/> ids only have to be unique within that menu level. This is changed to name instead of id in 3.3M5.
  7. You can provide a <command/> label attribute. If none is provided, it will take the command name.
  8. In this design the item contains most of the same rendering information that <action/> did.
  9. <menu/> and <command/> can have <visibleWhen/> clauses. If a menu's <visibleWhen/> evaluates to false, we will never ask the items contained in that menu.
  10. All of the displayable attributes are translatable.
  11. The mnemonic is specified as you place your <command/> elements in their respective menus, since it is possible that the same command might need a different mnemonic depending on which menu it is placed. Also, when defaulting to command names, they don't contain any mnemonic information.

Menus cannot be re-used, and so they have an intrinsic id value. Separators are unique within one menu level, so they also contain their name.

[edit] Menu URIs

For location placement we need a path and placement modifier, and to specify how the paths are built. First pass we are going to look at URIs.

  • <scheme>:<menu-id>[?<placement-modifier>]

scheme is about how to interpret the URI path. For example, menu, toolbar, popup, status (although status may be deprecated).

[edit] menu:

For menu: valid root ids will be any viewId for that view's menu, and org.eclipse.ui.main.menu for the main menu. Then specify the id of the menu this contribution applies to. The placement modifier helps position the menu contribution. ex: after=<id>, where <id> can be a separator name, menu id, or item id. An example of a path: menu:org.eclipse.search.menu?after=contextMenuActionsGroup

Since menu ids must be unique, you can specify your menu location relative to an existing id: menu:org.eclipse.search.menu?after=contextMenuActionsGroup

[edit] toolbar:

For toolbar: valid root ids will be any viewId for that view's toolbar, org.eclipse.ui.main.toolbar for the main toolbar, and any toolbar id that is contained in the main toolbar. Toolbars can support invisible separators. Toolbars in the main toolbar (technically a coolbar) can have ids as well as separators, but only one level. For example: toolbar:org.eclipse.ui.edit.text.actionSet.presentation?after=Presentation

In this example, Presentation is an invisible separator in the org.eclipse.ui.edit.text.actionSet.presentation toolbar.

The use of org.eclipse.ui.main.toolbar might change if all "main" toolbars have ids anyway, so the only options for interpretting the toolbar root is 1) the view toolbar or 2) an IDed main toolbar.

[edit] popup:

For popup: valid root ids are any registered context id (which defaults to the part id if no context menu id was given at registration time) and org.eclipse.ui.popup.any for all registered context menus. For example, to add to the default Text Editor context menu: popup:#TextEditorContext?after=additions

Popup submenus are treated like menu submenus, except the form continues to be popup:submenuId.

There will be constants defined for the ids that the eclipse workbench provides, probably in org.eclipse.ui.menus.MenuUtil.

[edit] Using Expressions in <visibleWhen/>

In 3.3M6 an org.eclipse.core.expressions.definitions extension point was added. Used to define a core expression, the definition can then be referenced from other locations.

<extension point="org.eclipse.core.expressions.definitions">
  <definition id="com.example.context">
    <with variable="activeContexts">
       <iterate operator="or">
         <equals value="org.eclipse.ui.contexts.actionSet"/>
       </iterate>
    </with>
  </definition>
</extension>

This can be called in a core expression like activeWhen, enabledWhen, visibleWhen, etc using the reference element:

<reference definitionId="com.example.context"/>

[edit] Ideas that were considered but not implemented

These ideas were considered but not implemented.

[edit] Menu - JSR198

Note: for novelty purposes only.

For comparison, there is a JSR describing how IDEs can contribute menus. Below is a sample for 2 items:

  • org.eclipse.ui.views.problems.sorting.item from menu:org.eclipse.ui.views.ProblemView
  • org.eclipse.ui.views.problems.resolveMarker.item from popup:org.eclipse.ui.views.ProblemView
<menu-hook>
  <actions>
    <action id="org.eclipse.ui.views.problems.sorting.item">
      <label>Sorting...</label>
      <mnemonic>S</mnemonic>
      <tooltip>Change the Sort order</tooltip>
      <invoke-class>org.eclipse.ui.views.problems.sorting</invoke-class>
    </action>
    <action id="org.eclipse.ui.views.problems.resolveMarker.item">
      <label>Quick Fix</label>
      <mnemonic>Q</mnemonic>
      <iconpath>$nl$/icons/full/elcl16/smartmode_co.gif</iconpath>
      <invoke-class>org.eclipse.jdt.ui.edit.text.java.correction.assist.proposals</invoke-class>
      <update-class>org.eclipse.jdt.ui.edit.text.java.correction.assist.proposals</update-class>
    </action>
  </actions>
  <menus>
    <menubar id="org.eclipse.ui.views.ProblemView">
      <menu id="org.eclipse.ui.views.ProblemView">
        <section id="problem.view.section">
          <command action-ref="org.eclipse.ui.views.problems.sorting.item" />
          <menu id="org.eclipse.ui.views.problems.groupBy.menu">
            <label>Group By</label>
            <mnemonic>G</mnemonic>
          </menu>
        </section>
      </menu>
    </menubar>
    <popup id="org.eclipse.ui.views.ProblemView">
      <section id="group.resolve">
        <command action-ref="org.eclipse.ui.views.problems.resolveMarker.item" />
      </section>
    </popup>
  </menus>
</menu-hook>

Some thoughts:

  • the actions can only specify one icon
  • the actions can't *quite* link to our commands
  • the menus can't specify dynamic submenus

[edit] Menu - XUL

Note: for novelty purposes only.


For comparison, with Mozilla everywhere there is the probability eclipse will include xulrunner. Menu definitions that are consistent with XUL look like:

<keyset>
  <key id="paste-key" modifiers="accel" key="V" />
</keyset>
<menubar id="org.eclipse.ui.views.ProblemView">
  <menupopup id="org.eclipse.ui.views.ProblemView">
    <menuitem id="org.eclipse.ui.views.problems.sorting.item"
        accesskey="S"
        key="paste-key"
        label="Sorting..."
        oncommand="invokeCommand('org.eclipse.ui.views.problems.sorting')" />
    <menu id="org.eclipse.ui.views.problems.groupBy.menu"
        label="Group By"
        accesskey="G">
      <menupopup id="groupby.popup">
        <!-- this is where submenu items would go -->
      </menupopup>
    </menu>
  </menupopup>
</menubar>

XUL supports everything as a flavour of a DOM, and javascripting can drive your buttons to perform commands. I suspect the scripting would allow you to dynamically update menus (dynamic menus) on popup, depending on what events the DOM would report to you.


[edit] Expression Templates original suggestion

You can see that the <activeWhen/>, <enabledWhen/>, and probably the <visibleWhen/> are likely to be replicated over and over again. A possible option is some kind of expression template markup ... either in its own extension or supported by our UI extensions that can use core expressions.

Here's an example of using expression templates in its own extension point.

<extension point="org.eclipse.core.expression.templates">
  <expression id="isPartActive">
    <parameter id="partId" />
    <with variable="activePartId">
      <equals value="$partId" />
    </with>
  </expression>
  <expression id="isActionSetActive">
    <parameter id="actionSetId" />
    <with variable="activeContexts">
      <iterator operator="or">
        <equals value="$actionSetId" />
      </iterator>
    </with>
  </expression>
  <expression id="isContextActive">
    <parameter id="contextId" />
    <with variable="activeContexts">
      <iterator operator="or">
        <equals value="$contextId" />
      </iterator>
    </with>
  </expression>
  <expression id="isSelectionAvailable">
    <not>
      <count value="0" />
    </not>
  </expression>
</extension>

This could be used to simplify the handler definitions:

<extension point="org.eclipse.ui.handlers">
  <handler commandId="org.eclipse.ui.edit.copy"
      class="org.eclipse.ui.views.markers.internal.CopyMarkerHandler">
    <enabledWhen>
      <evaluate ref="isSelectionAvailable" />
    </enabledWhen>
    <activeWhen>
      <evaluate ref="isPartActive">
        <parameter id="partId" value="org.eclipse.ui.views.ProblemView" />
      </evaluate>
    </activeWhen>
  </handler>
</extension>

If we allow recursive template definitions, that would allow you to specify the concrete expression once and then reference it throughout your view.

<extension point="org.eclipse.core.expression.templates">
  <expression id="isProblemViewActive">
    <evaluate ref="isPartActive">
      <parameter id="partId" value="org.eclipse.ui.views.ProblemView" />
    </evaluate>
  </expression>
</extension>
<extension point="org.eclipse.ui.handlers">
  <handler commandId="org.eclipse.ui.edit.copy"
      class="org.eclipse.ui.views.markers.internal.CopyMarkerHandler">
    <enabledWhen>
      <evaluate ref="isSelectionAvailable" />
    </enabledWhen>
    <activeWhen>
      <evaluate ref="isProblemViewActive" />
    </activeWhen>
  </handler>
</extension>

This reduces the handler definition even more.


A similar option to reuse expressions as much as possible without turning them into their own procedural language would be to allow global definitions and then reuse them. No parameters and no expression composition:

<extension point="org.eclipse.core.expression.templates">
  <expression id="isProblemViewActive">
    <with variable="activePartId">
      <equals value="org.eclipse.ui.views.ProblemView" />
    </with>
  </expression>
  <expression id="isSelectionAvailable">
    <not>
      <count value="0" />
    </not>
  </expression>
</extension>
<extension point="org.eclipse.ui.handlers">
  <handler commandId="org.eclipse.ui.edit.copy"
      class="org.eclipse.ui.views.markers.internal.CopyMarkerHandler">
    <enabledWhen ref="isSelectionAvailable" />
    <activeWhen ref="isProblemViewActive" />
  </handler>
</extension>

[edit] Another Expression Alternative: Specify Context at Extension Level

Since enabledWhen and activeWhen specify context and the simple way to specify context in XML is enclosure, how about scoping context to the extension point rather than the handler:

<extension point="org.eclipse.ui.handlers">
  <enabledWhen>  <!-- context of all  handlers in this extension -->
    <not>
      <count value="0" />
    </not>
  </enabledWhen>
  <activeWhen>
    <with variable="activePartId">
      <equals value="org.eclipse.ui.views.ProblemView" />
    </with>
  </activeWhen>
  <handler commandId="org.eclipse.ui.edit.copy"
      class="org.eclipse.ui.views.markers.internal.CopyMarkerHandler" />
  <handler commandId="org.eclipse.ui.edit.paste"
      class="org.eclipse.ui.views.markers.internal.PasteMarkerHandler" />
  <handler commandId="org.eclipse.ui.edit.delete"
      class="org.eclipse.ui.views.markers.internal.RemoveMarkerHandler" />
  <handler commandId="org.eclipse.jdt.ui.edit.text.java.correction.assist.proposals"
      class="org.eclipse.ui.views.markers.internal.ResolveMarkerHandler" />
  <handler commandId="org.eclipse.ui.edit.selectAll"
      class="org.eclipse.ui.views.markers.internal.SelectAllMarkersHandler" />
  <handler commandId="org.eclipse.ui.file.properties"
      class="org.eclipse.ui.views.markers.internal.ProblemPropertiesHandler" />
</extension>

This gives compact markup without inventing a new language. Elements nested in the handler element could override the extension-wide settings.

[edit] Updating the menu and toolbar appearance

It was suggested in 3.2 that state on the command could be used to implement the old contribution story behaviours:

  1. changing label text and tooltips
  2. changing icons
  3. changing enablement
  4. setting the item state (like checked state)

In 3.3 the enablement is tied to the command, and for the other behaviours we've decided to go with UIElements approach.

[edit] UIElements represent each UI visible instance of a command

The command service keeps a list of registered UI elements, which can be updated by the active handler. The checked state can be updated through UIElement#setChecked(boolean); (note that updateElement below is from IElementUpdater):

private boolean isChecked() {
    return getStore().getBoolean(
            PreferenceConstants.EDITOR_MARK_OCCURRENCES);
}
 
public void updateElement(UIElement element, Map parameters) {
    element.setChecked(isChecked());
}

When the toggle handler runs, it can request that any UI elements have their appearance updated from its execute(*) method:

ICommandService service = (ICommandService) serviceLocator
        .getService(ICommandService.class);
service.refreshElements(IJavaEditorActionDefinitionIds.TOGGLE_MARK_OCCURRENCES, null);

[edit] State associated with the command is propogated to UI visible elements

First define the toggle mark occurrences command. Pretty straight forward, although it needs a "STYLE" state since it can be toggled. To allow handlers to update the label for the menu/toolbar items, we also add the "NAME" state.

<extension point="org.eclipse.ui.commands">
  <command categoryId="org.eclipse.jdt.ui.category.source"
      description="%jdt.ui.ToggleMarkOccurrences.description"
      id="org.eclipse.jdt.ui.edit.text.java.toggleMarkOccurrences"
      name="%jdt.ui.ToggleMarkOccurrences.name">
    <state id="NAME" class="org.eclipse.jface.menus.TextState" />
    <state id="STYLE" class="org.eclipse.jface.commands.ToggleState:true" />
  </command>
</extension>

[edit] Work

Progress in 3.3.

[edit] Available in 3.3

  • Ok green.gif the editor action bar contributor solution. EditorActionBarContributor will not be deprecated, but is not used in the commands/handler story. Menu Contributions have visibility tied to an active editor id, and editor specific handlers can be created in the editor init(*) or createPartControl(*) method using the handler service from getPartSite().getService(IHandlerService.class).
  • Ok green.gif Attributes for <command/>: helpContextId, style to support radio buttons and check boxes
  • Ok green.gif action sets as contexts - action sets are still defined using org.eclipse.ui.actionSets, and each actionSet generates an equivalent context. showing/hiding actionSets activates/deactivates the equivalent context.
  • Ok green.gif How do we give Trim widgets/toolbar widgets "focus" for command and handlers? There was an IFocusService added in 3.3 that allows a trim control to register itself. When that control has focus, the control and the ID it registered with are provided in the global application context to core expressions and handlers. This is available, but might not be the optimal solution if you just want cut, copy, and paste to work.
  • Ok green.gif Shortcuts to define reusable core expressions for <activeWhen/>, <enabledWhen/>, and <visibleWhen/>. This has been added as the org.eclipse.core.expressions.definitions extension point and the core expression <reference/> element.
  • Ok green.gif the mnemonic field for <command/> elements (decorating)
  • Ok green.gif display any keybinding for <command/> elements (decorating)
  • Ok green.gif toolbar <visibleWhen/> expressions

[edit] Available in 3.3M5

There is an example of the RCP Mail application template updated for 3.3M5 and converted to use the org.eclipse.ui.menus extension point as much as possible at Contribution Example.

  • Ok green.gif changing the menu item or tool item state from a handler, like updating the label or tooltip or checked state. Commands can contain <state/> elements, but that is not appropriate to use for providing feedback to the user. This will be done by adapting a callback provided by the UI element.
  • Ok green.gif the <separator/> element should have a name not an id
  • Ok green.gif support creating radio button or checked menu items
  • Ok green.gif creating new toolbars in the main coolbar/trim declaratively
  • Ok green.gif creating new toolbars in the main coolbar/trim programmatically
  • Ok green.gif org.eclipse.ui.popup.any as a context menu contribution
  • Ok green.gif Drop down toolbar items

We also have action sets activating and de-activating contexts in 3.3M5, but we'll need to decide the proper action set story for 3.3M6

We are still working on the EditorActionBarContributor story. It seems like we might be able to deprecate it. Editor instances can instantiate handlers upon creation for each command they support.

[edit] Available in 3.3M4

The basic menu API will be available in 3.3M4. It includes both declarative org.eclipse.ui.menus extension point with core expression support for visibility, and a programmatic interface accessed through the IMenuService.


We support contributing to the main menu, and the view menu, view toolbar, and any IDed context menu. We support contributing to existing toolbars in the main coolbar, and contributing trim widgets.

Programmatically we support the following types of contributions:

  • MenuManager
  • CommandContributionItem
  • CompoundContributionItem
  • ControlContribution (in 3.3M5)
  • Separator
  • GroupMarker

There are some specific mappings of elements and attributes on Menus Extension Mapping.


[edit] Work still to be done

A list of behaviours not supported or shipped with 3.3.

  • validate and possibly optimize the context menu population story and lifecycle. Many context menus set remove all when shown.
  • migrate Marker views
  • migrate standard workbench actions - a few were done
  • Check enabled visibleWhen support
  • Shortcuts placed on submenu items (like CTRL+N) (decorating)
  • ensure full visibleWhen support in the MenuManagers - i.e. should empty menus display (empty)
  • do we want to manage trim with a TrimContributionManager? This removes the coolbar, but has RCP implications.
  • the menu override capability - does this tie into the Customize Perspective dialog and action sets
  • A set of default programmatic core expressions. For example, ActionContextExpression or ActivePartExpression
  • deprecate the 4 extension: actionSets, viewActions, editorActions, popupMenus
  • read old extensions in terms of new extension
  • convert platform UI extensions to new extension
  • migration guide - what are the most common migration paths for Action and IActionDelegate to Command/IHandler.
  • Attributes for <command/>: state for checkboxes and radio buttons
  • possibly provide an plugin.xml converter for actionSets to menus
  • possibly provide an Action -> Handler converter
  • Error.gif status manager contributions


Legend:

  • nothing - TBD
  • Glass.gif - investigating
  • Progress.gif - in progress
  • Ok green.gif - completed
  • Error.gif - dropped