17.1. Customizing a menu or a toolBar without redefining it from scratch

The insert child element, the insert, replace, replaceEnd attributes may be used to customize to the previous definition of a menu or a toolBar. In this section, we'll use menus in the examples, but it works exactly the same with tool bars.

Extending a menu

There are two ways to extend previously defined menu:

  1. by using the insert child element;

  2. by using the insert attribute.

Both methods cannot be used in the same menu element. The insert attribute is silently ignored when an insert child element has been specified.

  1. Using the insert child element. Example:

    <!-- ==============================================
    Let's suppose this menu is initially defined as follows:
    
    <menu label="Insert">
      <item label="Insert..." command="insert" parameter="into" />
    </menu>
    =============================================== -->
    
    <menu label="Insert">
      <item label="Insert Before..." command="insert"
         parameter="before[implicitElement]" />
      <insert />
      <item label="Insert After..." command="insert" 
        parameter="after[implicitElement]" />
    </menu>

    The insert child element is a directive which means: insert all the items of the previous definition of the same menu here.

    About the label attribute

    When you extend a previously defined menu, the label attribute specifies the title of the extended menu. This means that you can change the title of a menu at the same time you extend it.

    If you don't want to do that, which is often the case, simply specify label="-" in the menu extension. This is simpler and safer than repeating the original label of the menu. In such case, the above example becomes:

    <menu label="-">
      <item label="Insert Before..." command="insert"
         parameter="before[implicitElement]" />
      <insert />
      <item label="Insert After..." command="insert" 
        parameter="after[implicitElement]" />
    </menu>
  2. Using the insert attribute. Example:

    <!-- ==============================================
    Let's suppose this menu is initially defined as follows:
    
    <menu label="Insert">
      <item label="Insert Before..." command="insert"
         parameter="before[implicitElement]" />
      <item label="Insert After..." command="insert" 
        parameter="after[implicitElement]" />
    </menu>
    =============================================== -->
    
    <menu label="-" insert="Insert After...">
      <item label="Insert..." command="insert" parameter="into" />
    </menu>

    The insert attribute is a directive which means: insert all the items found in this menu into the previous definition of the same menu, and this, at specified position.

    The value of the insert attribute is the label of an item found in the previous definition of the same menu. This label may be preceded by modifier "before " or by modifier "after ". Modifier "before " is the implicit one.

    In the above example, extending menu "Insert" could have also been achieved by using:

    <menu label="-" insert="before Insert After...">
      <item label="Insert..." command="insert" parameter="into" />
    </menu>

    or by using:

    <menu label="-" insert="after Insert Before...">
      <item label="Insert..." command="insert" parameter="into" />
    </menu>

    Alternatively, the value of the insert attribute may be ##first or ##last. Value ##first specifies the first item of the previous definition of the same menu. Value ##last specifies the last item of the previous definition of the same menu. Example:

    <menu label="-" insert="before ##last">
      <item label="Insert..." command="insert" parameter="into" />
    </menu>

    The value of the insert attribute may start with ifDefined(system_property_name). In such case, the previously defined menu is extended if and only if a system property called system_property_name has been defined (no matter its value). Example:

    <menu label="-" 
          insert="ifDefined(HAS_CONVERT_SUBMENU)after ##last">
      <separator />
      <menu label="_Convert Document">
      ...
      </menu>
    </menu>

    In addition to ifDefined(system_property_name), the following conditional processing constructs are also supported:

    • In ifDefined(test), the test is not limited to testing the existence of a system property. It is also possible to specify:

      system_property_name=value

      The test evaluates to true when specified system property exists and is equal to specified value.

      system_property_name^=value

      The test evaluates to true when specified system property exists and starts with specified value.

      system_property_name$=value

      The test evaluates to true when specified system property exists and ends with specified value.

      system_property_name*=value

      The test evaluates to true when specified system property exists and contains specified value.

    • It's also possible to specify ifNotDefined(test). Example (a customization which is applied on Windows and on the Mac, but not on Linux):

      <menu label="-" 
            insert="ifNotDefined(os.name*=Linux)after ##last">
        <separator />
        <menu label="_Convert Document">
        ...
        </menu>
      </menu>

Removing or replacing items inside a menu

Removing or replacing some items inside a menu is done by the means of the replace attribute and, optionally, also the replaceEnd attribute. The replaceEnd attribute is needed to specify a range of sibling items.

Note that the replace and replaceEnd attributes are silently ignored when an insert child element or an insert attribute has been specified.

Remove items example:

<!-- ==============================================
Let's suppose this menu is initially defined as follows:

<menu label="XHTML">
  <item label="Move _Up"
        command="moveElement" parameter="up" />
  <item label="Move _Down"
        command="moveElement" parameter="down" />
</menu>
=============================================== -->

<menu label="-" replace="Move _Up" />

results in the following menu:

<menu label="XHTML">
  <item label="Move _Down"
        command="moveElement" parameter="down" />
</menu>

This could have been specified as follows:

<menu label="-" replace="before Move _Down" />

or as follows:

<menu label="-" replace="##first" />

In fact, the replace and replaceEnd attributes support exactly the same values as the insert attribute. See above. However, there is a pitfall. While attributes insert="before Move _Down" and insert="Move _Down" are equivalent, attributes replace="before Move _Down" and replace="Move _Down" are not equivalent.

Replace items example:

<!-- ==============================================
Let's suppose this menu is initially defined as follows:

<menu label="XHTML">
  <item label="Move _Up"
        command="moveElement" parameter="up" />
  <separator />
  <item label="Pre_view"
        command="xhtml.preview" />
</menu>
=============================================== -->

<menu label="-" replace="before Pre_view" replaceEnd="Pre_view">
  <item label="Move _Down"
        command="moveElement" parameter="down" />
</menu>

results in the following menu:

<menu label="XHTML">
  <item label="Move _Up"
        command="moveElement" parameter="up" />
  <item label="Move _Down"
        command="moveElement" parameter="down" />
</menu>