blob: 645de4771751d3c1c46ca40e058b4e52733b6677 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.internal.menus;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.eclipse.core.commands.ParameterizedCommand;
import org.eclipse.core.commands.common.HandleObject;
import org.eclipse.core.expressions.Expression;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionDelta;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IRegistryChangeEvent;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.menus.IWidget;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
import org.eclipse.ui.internal.services.RegistryPersistence;
/**
* <p>
* A static class for accessing the registry.
* </p>
* <p>
* This class is not intended for use outside of the
* <code>org.eclipse.ui.workbench</code> plug-in.
* </p>
*
* @since 3.2
*/
final class MenuPersistence extends RegistryPersistence {
/**
* The index of the action set elements in the indexed array.
*
* @see MenuPersistence#read()
*/
private static final int INDEX_ACTION_SETS = 0;
/**
* The index of the group elements in the indexed array.
*
* @see MenuPersistence#read()
*/
private static final int INDEX_GROUPS = 1;
/**
* The index of the item elements in the indexed array.
*
* @see MenuPersistence#read()
*/
private static final int INDEX_ITEMS = 2;
/**
* The index of the menu elements in the indexed array.
*
* @see MenuPersistence#read()
*/
private static final int INDEX_MENUS = 3;
/**
* The index of the widget elements in the indexed array.
*
* @see MenuPersistence#read()
*/
private static final int INDEX_WIDGETS = 4;
/**
* The menu contributions that have come from the registry. This is used to
* flush the contributions when the registry is re-read. This value is never
* <code>null</code>
*/
private static final Collection menuContributions = new ArrayList();
/**
* Removes all of the contributions made by this class, and then clears the
* collection. This should be called before every read.
*
* @param menuService
* The service handling the contributions; must not be
* <code>null</code>.
*/
private static final void clearContributions(final IMenuService menuService) {
menuService.removeContributions(menuContributions);
menuContributions.clear();
}
/**
* Reads the action sets from an array of action set elements from the menus
* extension point.
*
* @param configurationElements
* The configuration elements in the extension point; must not be
* <code>null</code>, but may be empty.
* @param configurationElementCount
* The number of configuration elements that are really in the
* array.
* @param menuService
* The menu service to which the action sets should be added;
* must not be <code>null</code>.
*/
private static final void readActionSetsFromRegistry(
final IConfigurationElement[] configurationElements,
final int configurationElementCount, final IMenuService menuService) {
// Undefine all the previous handle objects.
final HandleObject[] handleObjects = menuService.getDefinedActionSets();
if (handleObjects != null) {
for (int i = 0; i < handleObjects.length; i++) {
handleObjects[i].undefine();
}
}
final List warningsToLog = new ArrayList(1);
for (int i = 0; i < configurationElementCount; i++) {
final IConfigurationElement configurationElement = configurationElements[i];
// Read the menu identifier.
final String id = readRequired(configurationElement, ATT_ID,
warningsToLog, "Action sets need an id"); //$NON-NLS-1$
if (id == null) {
continue;
}
// Read the label.
final String label = readRequired(configurationElement,
ATT_LABEL, warningsToLog, "Action sets need a label"); //$NON-NLS-1$
if (label == null) {
continue;
}
// Read the description.
final String description = readOptional(configurationElement,
ATT_DESCRIPTION);
// Read the whether the action set is visible by default.
final boolean visible = readBoolean(configurationElement,
ATT_VISIBLE, false);
// Read the references.
final SReference[] references = readReferencesFromRegistry(
configurationElement, id, warningsToLog);
final SActionSet actionSet = menuService.getActionSet(id);
actionSet.define(label, description, visible, references);
}
logWarnings(
warningsToLog,
"Warnings while parsing the action sets from the 'org.eclipse.ui.menus' extension point"); //$NON-NLS-1$
}
/**
* Reads the bar element from a location or part element.
*
* @param parentElement
* The parent element from which to read; must not be
* <code>null</code>.
* @param warningsToLog
* The list of the warnings to log; must not be <code>null</code>.
* @param id
* The identifier of the menu element, for logging purposes; may
* be <code>null</code>.
* @return The bar element, if any; <code>null</code> if none.
*/
private static final SBar readBarFromRegistry(
final IConfigurationElement parentElement,
final List warningsToLog, final String id) {
// Check to see if we have a bar element.
final IConfigurationElement[] barElements = parentElement
.getChildren(TAG_BAR);
if (barElements.length > 0) {
// Check if we have too many bar elements.
if (barElements.length > 1) {
// There should only be one bar element
addWarning(warningsToLog,
"Location elements should only have one bar element", //$NON-NLS-1$
parentElement, id);
return null;
}
final IConfigurationElement barElement = barElements[0];
// Read the type attribute.
final String type = readRequired(barElement, ATT_TYPE,
warningsToLog, "Bar elements require a type element", id); //$NON-NLS-1$
if (!((SBar.TYPE_MENU.equals(type)) || (SBar.TYPE_TRIM.equals(type)))) {
// The position was not understood.
addWarning(warningsToLog, "The bar type was not understood", //$NON-NLS-1$
parentElement, id, "type", type); //$NON-NLS-1$
return null;
}
// Read the path attribute.
final String path = readOptional(barElement, ATT_PATH);
return new SBar(type, path);
}
return null;
}
/**
* Reads the dynamic menu information for a group or menu element.
*
* @param parentElement
* The group or menu element; must not be <code>null</code>.
* @param id
* The identifier of the menu element for which the location is
* being read; may be <code>null</code>.
* @param warningsToLog
* The collection of warnings to log; must not be
* <code>null</code>.
* @return The dynamic menu for this menu element; may be <code>null</code>
* if none.
*/
private static final IDynamicMenu readDynamicMenuFromRegistry(
final IConfigurationElement parentElement, final String id,
final List warningsToLog) {
// Check to see if we have an element.
final IConfigurationElement[] dynamicMenuElements = parentElement
.getChildren(TAG_DYNAMIC);
if (dynamicMenuElements.length > 0) {
// Check if we have too many elements.
if (dynamicMenuElements.length > 1) {
// There should only be one element
addWarning(
warningsToLog,
"Group and menu elements should only have one dynamic element", //$NON-NLS-1$
parentElement, id);
return null;
}
final IConfigurationElement dynamicMenuElement = dynamicMenuElements[0];
if (!checkClass(dynamicMenuElement, warningsToLog,
"Dynamic menu needs a class", id)) { //$NON-NLS-1$
return null;
}
return new DynamicMenuProxy(dynamicMenuElement, ATT_CLASS);
}
return null;
}
/**
* Reads the groups from an array of group elements from the menus extension
* point.
*
* @param configurationElements
* The configuration elements in the extension point; must not be
* <code>null</code>, but may be empty.
* @param configurationElementCount
* The number of configuration elements that are really in the
* array.
* @param menuService
* The menu service to which the groups should be added; must not
* be <code>null</code>.
*/
private static final void readGroupsFromRegistry(
final IConfigurationElement[] configurationElements,
final int configurationElementCount, final IMenuService menuService) {
// Undefine all the previous handle objects.
final HandleObject[] handleObjects = menuService.getDefinedGroups();
if (handleObjects != null) {
for (int i = 0; i < handleObjects.length; i++) {
handleObjects[i].undefine();
}
}
final List warningsToLog = new ArrayList(1);
for (int i = 0; i < configurationElementCount; i++) {
final IConfigurationElement configurationElement = configurationElements[i];
// Read the menu identifier.
final String id = readRequired(configurationElement, ATT_ID,
warningsToLog, "Groups need an id"); //$NON-NLS-1$
if (id == null) {
continue;
}
// Read whether the separators are visible.
final boolean separatorsVisible = readBoolean(configurationElement,
ATT_SEPARATORS_VISIBLE, true);
// Read out the visibleWhen expression.
final Expression visibleWhenExpression = readWhenElement(
configurationElement, TAG_VISIBLE_WHEN, id,
warningsToLog);
if (visibleWhenExpression == ERROR_EXPRESSION) {
continue;
}
// Read out the location elements.
final SLocation[] locations = readLocationElementsFromRegistry(
configurationElement, id, warningsToLog);
// Read out the dynamic elements.
final IDynamicMenu dynamicMenu = readDynamicMenuFromRegistry(
configurationElement, id, warningsToLog);
final SGroup group = menuService.getGroup(id);
group.define(separatorsVisible, locations, dynamicMenu);
menuContributions.add(menuService.contributeMenu(group,
visibleWhenExpression));
}
logWarnings(
warningsToLog,
"Warnings while parsing the groups from the 'org.eclipse.ui.menus' extension point"); //$NON-NLS-1$
}
/**
* Reads the items from an array of item elements from the menus extension
* point.
*
* @param configurationElements
* The configuration elements in the extension point; must not be
* <code>null</code>, but may be empty.
* @param configurationElementCount
* The number of configuration elements that are really in the
* array.
* @param menuService
* The menu service to which the items should be added; must not
* be <code>null</code>.
* @param commandService
* The command service providing commands for the workbench; must
* not be <code>null</code>.
*/
private static final void readItemsFromRegistry(
final IConfigurationElement[] configurationElements,
final int configurationElementCount,
final IMenuService menuService, final ICommandService commandService) {
// Undefine all the previous handle objects.
final HandleObject[] handleObjects = menuService.getDefinedItems();
if (handleObjects != null) {
for (int i = 0; i < handleObjects.length; i++) {
handleObjects[i].undefine();
}
}
final List warningsToLog = new ArrayList(1);
for (int i = 0; i < configurationElementCount; i++) {
final IConfigurationElement configurationElement = configurationElements[i];
// Read the item identifier.
final String id = readRequired(configurationElement, ATT_ID,
warningsToLog, "Items need an id"); //$NON-NLS-1$
if (id == null) {
continue;
}
// Read the parameterized command.
final ParameterizedCommand command = readParameterizedCommand(
configurationElement, commandService, warningsToLog,
"Items need a command id", id); //$NON-NLS-1$
// Read the menu identifier.
final String menuId = readOptional(configurationElement,
ATT_MENU_ID);
// Read out the visibleWhen expression.
final Expression visibleWhenExpression = readWhenElement(
configurationElement, TAG_VISIBLE_WHEN, id,
warningsToLog);
if (visibleWhenExpression == ERROR_EXPRESSION) {
continue;
}
// Read out the location elements.
final SLocation[] locations = readLocationElementsFromRegistry(
configurationElement, id, warningsToLog);
final SItem item = menuService.getItem(id);
item.define(command, menuId, locations);
menuContributions.add(menuService.contributeMenu(item,
visibleWhenExpression));
}
logWarnings(
warningsToLog,
"Warnings while parsing the items from the 'org.eclipse.ui.menus' extension point"); //$NON-NLS-1$
}
/**
* Reads the <code>layout</code> child element from the given
* configuration element. Warnings will be appended to
* <code>warningsToLog</code>.
*
* @param parentElement
* The configuration element which might have a
* <code>layout</code> element as a child; never
* <code>null</code>.
* @param id
* The identifier of the menu element whose <code>layout</code>
* elements are being read; never <code>null</code>.
* @param warningsToLog
* The list of warnings while parsing the extension point; never
* <code>null</code>.
* @return The layout for the <code>configurationElement</code>, if
* any; otherwise a default layout is returned.
*/
private static final SLayout readLayoutFromRegistry(
final IConfigurationElement parentElement, final String id,
final List warningsToLog) {
// Check to see if we have an activeWhen expression.
final IConfigurationElement[] layoutElements = parentElement
.getChildren(TAG_LAYOUT);
// If none is defined then return a default
if (layoutElements.length < 1) {
return new SLayout();
}
// Use the first one
IConfigurationElement layoutElement = layoutElements[0];
// If more than one is defined then log a warning and use the first
if (layoutElements.length > 1) {
addWarning(warningsToLog,
"There should only be a single layout element for a widget", //$NON-NLS-1$
parentElement, id);
}
// Get the values (a return of 'null' will give a value of 'false'
boolean fillMajor = readBoolean(layoutElement, ATT_FILL_MAJOR, false);
boolean fillMinor = readBoolean(layoutElement, ATT_FILL_MINOR, false);
return new SLayout(fillMajor, fillMinor);
}
/**
* Reads the <code>location</code> child elements from the given
* configuration element. Warnings will be appended to
* <code>warningsToLog</code>.
*
* @param parentElement
* The configuration element which might have
* <code>location</code> elements as a child; never
* <code>null</code>.
* @param id
* The identifier of the menu element whose <code>location</code>
* elements are being read; never <code>null</code>.
* @param warningsToLog
* The list of warnings while parsing the extension point; never
* <code>null</code>.
* @return The locations for the <code>configurationElement</code>, if
* any; otherwise, <code>null</code>.
*/
private static final SLocation[] readLocationElementsFromRegistry(
final IConfigurationElement parentElement, final String id,
final List warningsToLog) {
// Check to see if we have an activeWhen expression.
final IConfigurationElement[] locationElements = parentElement
.getChildren(TAG_LOCATION);
if (locationElements.length < 1) {
return null;
}
// Convert the location elements in an SLocation array.
final Collection locations = new ArrayList(locationElements.length);
for (int i = 0; i < locationElements.length; i++) {
final IConfigurationElement locationElement = locationElements[i];
// Read the mnemonic.
final String mnemonic = readOptional(locationElement,
ATT_MNEMONIC);
final char mnemonicChar;
if (mnemonic == null) {
mnemonicChar = SLocation.MNEMONIC_NONE;
} else if (mnemonic.length() != 1) {
addWarning(warningsToLog,
"The mnemonic should only be one character", //$NON-NLS-1$
parentElement, id, "mnemonic", mnemonic); //$NON-NLS-1$
mnemonicChar = SLocation.MNEMONIC_NONE;
} else {
mnemonicChar = mnemonic.charAt(0);
}
// Read the image style.
final String imageStyle = readOptional(locationElement,
ATT_IMAGE_STYLE);
// Read the position and the relativeTo attributes.
final SOrder ordering = readOrderingFromRegistry(locationElement,
id, warningsToLog);
// Read the menu location information.
final LocationElement menuLocation = readMenuLocationFromRegistry(
locationElement, warningsToLog, id);
if (menuLocation == null) {
continue;
}
final SLocation location = new SLocation(menuLocation, ordering,
mnemonicChar, imageStyle);
locations.add(location);
}
return (SLocation[]) locations.toArray(new SLocation[locations.size()]);
}
/**
* Reads the location information from a location element. This is either a
* <code>bar</code>, <code>part</code>, or <code>popup</code>
* element.
*
* @param parentElement
* The parent element from which to read; must not be
* <code>null</code>.
* @param warningsToLog
* The list of warnings to log at some future point in time; must
* not be <code>null</code>.
* @param id
* The identifier of the menu element, for logging purposes; may
* be <code>null</code>.
* @return The element providing the location for the menu; may be
* <code>null</code> if none.
*/
private static final LocationElement readMenuLocationFromRegistry(
final IConfigurationElement parentElement,
final List warningsToLog, final String id) {
LocationElement locationElement = null;
locationElement = readBarFromRegistry(parentElement, warningsToLog, id);
if (locationElement == null) {
locationElement = readPartFromRegistry(parentElement,
warningsToLog, id);
if (locationElement == null) {
locationElement = readPopupFromRegistry(parentElement,
warningsToLog, id);
}
}
if (locationElement == null) {
addWarning(warningsToLog,
"A bar, part or popup element is required", parentElement, //$NON-NLS-1$
id);
}
return locationElement;
}
/**
* Reads the menus from an array of menu elements from the menus extension
* point.
*
* @param configurationElements
* The configuration elements in the extension point; must not be
* <code>null</code>, but may be empty.
* @param configurationElementCount
* The number of configuration elements that are really in the
* array.
* @param menuService
* The menu service to which the menus should be added; must not
* be <code>null</code>.
*/
private static final void readMenusFromRegistry(
final IConfigurationElement[] configurationElements,
final int configurationElementCount, final IMenuService menuService) {
// Undefine all the previous handle objects.
final HandleObject[] handleObjects = menuService.getDefinedMenus();
if (handleObjects != null) {
for (int i = 0; i < handleObjects.length; i++) {
handleObjects[i].undefine();
}
}
final List warningsToLog = new ArrayList(1);
for (int i = 0; i < configurationElementCount; i++) {
final IConfigurationElement configurationElement = configurationElements[i];
// Read the menu identifier.
final String id = readRequired(configurationElement, ATT_ID,
warningsToLog, "Menus need an id"); //$NON-NLS-1$
if (id == null) {
continue;
}
// Read the label.
final String label = readOptional(configurationElement,
ATT_LABEL);
// Read out the visibleWhen expression.
final Expression visibleWhenExpression = readWhenElement(
configurationElement, TAG_VISIBLE_WHEN, id,
warningsToLog);
if (visibleWhenExpression == ERROR_EXPRESSION) {
continue;
}
// Read out the location elements.
final SLocation[] locations = readLocationElementsFromRegistry(
configurationElement, id, warningsToLog);
// Read out the dynamic elements.
final IDynamicMenu dynamicMenu = readDynamicMenuFromRegistry(
configurationElement, id, warningsToLog);
final SMenu menu = menuService.getMenu(id);
menu.define(label, locations, dynamicMenu);
menuContributions.add(menuService.contributeMenu(menu,
visibleWhenExpression));
}
logWarnings(
warningsToLog,
"Warnings while parsing the menus from the 'org.eclipse.ui.menus' extension point"); //$NON-NLS-1$
}
/**
* Reads the ordering information for a location element.
*
* @param parentElement
* The location configuration element; must not be
* <code>null</code>.
* @param id
* The identifier of the menu element for which the location is
* being read; may be <code>null</code>.
* @param warningsToLog
* The collection of warnings to log; must not be
* <code>null</code>.
* @return The ordering constraint for this location element; may be
* <code>null</code> if none.
*/
private static final SOrder readOrderingFromRegistry(
final IConfigurationElement parentElement, final String id,
final List warningsToLog) {
// Check to see if we have an order element.
final IConfigurationElement[] orderingElements = parentElement
.getChildren(TAG_ORDER);
final int length = orderingElements.length;
if (length < 1) {
return null;
} else if (length > 1) {
addWarning(warningsToLog,
"There can only be one ordering constraint", parentElement, //$NON-NLS-1$
id);
}
final IConfigurationElement orderingElement = orderingElements[0];
// Read the position attribute.
final String position = readRequired(orderingElement,
ATT_POSITION, warningsToLog,
"Order elements require a position element", id); //$NON-NLS-1$
final int positionInteger;
if (POSITION_AFTER.equals(position)) {
positionInteger = SOrder.POSITION_AFTER;
} else if (POSITION_BEFORE.equals(position)) {
positionInteger = SOrder.POSITION_BEFORE;
} else if (POSITION_START.equals(position)) {
positionInteger = SOrder.POSITION_START;
} else if (POSITION_END.equals(position)) {
positionInteger = SOrder.POSITION_END;
} else {
// The position was not understood.
addWarning(warningsToLog, "The position was not understood", //$NON-NLS-1$
parentElement, id, "position", position); //$NON-NLS-1$
return null;
}
// Read the relativeTo attribute.
String relativeTo = null;
if ((positionInteger == SOrder.POSITION_AFTER)
|| (positionInteger == SOrder.POSITION_BEFORE)) {
relativeTo = readRequired(
orderingElement,
ATT_RELATIVE_TO,
warningsToLog,
"A relativeTo attribute is required if the position is 'after' or 'before'", //$NON-NLS-1$
id);
if (relativeTo == null) {
return null;
}
} else {
// There should be no relativeTo attribute.
relativeTo = readOptional(orderingElement, ATT_RELATIVE_TO);
if (relativeTo != null) {
addWarning(
warningsToLog,
"relativeTo should not be specified unless the position is before or after", //$NON-NLS-1$
parentElement, id, ATT_RELATIVE_TO, relativeTo);
return null;
}
}
final SOrder order = new SOrder(positionInteger, relativeTo);
return order;
}
/**
* Reads the part element from a location element.
*
* @param parentElement
* The parent element from which to read; must not be
* <code>null</code>.
* @param warningsToLog
* The list of the warnings to log; must not be <code>null</code>.
* @param id
* The identifier of the menu element, for logging purposes; may
* be <code>null</code>.
* @return The part element, if any; <code>null</code> if none.
*/
private static final SPart readPartFromRegistry(
final IConfigurationElement parentElement,
final List warningsToLog, final String id) {
// Check to see if we have a part element.
final IConfigurationElement[] partElements = parentElement
.getChildren(TAG_BAR);
if (partElements.length > 0) {
// Check if we have too many part elements.
if (partElements.length > 1) {
// There should only be one part element
addWarning(warningsToLog,
"Location elements should only have one part element", //$NON-NLS-1$
parentElement, id);
return null;
}
final IConfigurationElement partElement = partElements[0];
// Read the leaf location element.
LeafLocationElement leafLocationElement = null;
leafLocationElement = readBarFromRegistry(parentElement,
warningsToLog, id);
if (leafLocationElement == null) {
leafLocationElement = readPopupFromRegistry(parentElement,
warningsToLog, id);
}
if (leafLocationElement == null) {
addWarning(warningsToLog, "A bar or popup element is required", //$NON-NLS-1$
parentElement, id);
return null;
}
// Read the two optional attributes.
final String partId = readOptional(partElement, ATT_ID);
final String clazz = readOptional(partElement, ATT_CLASS);
if ((partId == null) && (clazz == null)) {
addWarning(warningsToLog,
"A part id or a part class is required", parentElement, //$NON-NLS-1$
id);
return null;
} else if ((partId != null) && (clazz != null)) {
addWarning(warningsToLog,
"Only a part id or a part class is allowed, not both", //$NON-NLS-1$
parentElement, id);
return null;
} else if (partId != null) {
return new SPart(partId, SPart.TYPE_ID, leafLocationElement);
} else {
return new SPart(clazz, SPart.TYPE_CLASS, leafLocationElement);
}
}
return null;
}
/**
* Reads the popup element from a location or part element.
*
* @param parentElement
* The parent element from which to read; must not be
* <code>null</code>.
* @param warningsToLog
* The list of the warnings to log; must not be <code>null</code>.
* @param id
* The identifier of the menu element, for logging purposes; may
* be <code>null</code>.
* @return The popup element, if any; <code>null</code> if none.
*/
private static final SPopup readPopupFromRegistry(
final IConfigurationElement parentElement,
final List warningsToLog, final String id) {
// Check to see if we have a popup element.
final IConfigurationElement[] popupElements = parentElement
.getChildren(TAG_BAR);
if (popupElements.length > 0) {
// Check if we have too many popup elements.
if (popupElements.length > 1) {
// There should only be one popup element
addWarning(warningsToLog,
"Location elements should only have one popup element", //$NON-NLS-1$
parentElement, id);
return null;
}
final IConfigurationElement popupElement = popupElements[0];
final String popupId = readOptional(popupElement, ATT_ID);
final String path = readOptional(popupElement, ATT_PATH);
return new SPopup(popupId, path);
}
return null;
}
/**
* Reads the <code>reference</code> child elements from the given
* configuration element. Warnings will be appended to
* <code>warningsToLog</code>.
*
* @param parentElement
* The configuration element which might have
* <code>reference</code> elements as a child; never
* <code>null</code>.
* @param id
* The identifier of the action set whose <code>reference</code>
* elements are being read; never <code>null</code>.
* @param warningsToLog
* The list of warnings while parsing the extension point; never
* <code>null</code>.
* @return The references for the <code>configurationElement</code>, if
* any; otherwise, <code>null</code>.
*/
private static final SReference[] readReferencesFromRegistry(
final IConfigurationElement parentElement, final String id,
final List warningsToLog) {
final IConfigurationElement[] referenceElements = parentElement
.getChildren(TAG_REFERENCE);
if (referenceElements.length < 1) {
return null;
}
final Collection references = new ArrayList(referenceElements.length);
for (int i = 0; i < referenceElements.length; i++) {
final IConfigurationElement referenceElement = referenceElements[i];
// Read the id.
final String referenceId = readRequired(referenceElement,
ATT_ID, warningsToLog, "References are required", id); //$NON-NLS-1$
if (referenceId == null) {
continue;
}
// Read the type attribute.
final String type = readRequired(referenceElement, ATT_TYPE,
warningsToLog, "Reference elements require a type", id); //$NON-NLS-1$
final int typeInteger;
if (TYPE_ITEM.equals(type)) {
typeInteger = SReference.TYPE_ITEM;
} else if (TYPE_MENU.equals(type)) {
typeInteger = SReference.TYPE_MENU;
} else if (TYPE_GROUP.equals(type)) {
typeInteger = SReference.TYPE_GROUP;
} else if (TYPE_WIDGET.equals(type)) {
typeInteger = SReference.TYPE_WIDGET;
} else {
// The position was not understood.
addWarning(warningsToLog,
"The reference type was not understood", parentElement, //$NON-NLS-1$
id, "type", type); //$NON-NLS-1$
return null;
}
final SReference reference = new SReference(typeInteger,
referenceId);
references.add(reference);
}
return (SReference[]) references.toArray(new SReference[references
.size()]);
}
/**
* Reads the widgets from an array of widget elements from the menus
* extension point.
*
* @param configurationElements
* The configuration elements in the extension point; must not be
* <code>null</code>, but may be empty.
* @param configurationElementCount
* The number of configuration elements that are really in the
* array.
* @param menuService
* The menu service to which the widgets should be added; must
* not be <code>null</code>.
*/
private static final void readWidgetsFromRegistry(
final IConfigurationElement[] configurationElements,
final int configurationElementCount, final IMenuService menuService) {
// Undefine all the previous handle objects.
final HandleObject[] handleObjects = menuService.getDefinedWidgets();
if (handleObjects != null) {
for (int i = 0; i < handleObjects.length; i++) {
handleObjects[i].undefine();
}
}
final List warningsToLog = new ArrayList(1);
for (int i = 0; i < configurationElementCount; i++) {
final IConfigurationElement configurationElement = configurationElements[i];
// Read the widget identifier.
final String id = readRequired(configurationElement, ATT_ID,
warningsToLog, "Widgets need an id"); //$NON-NLS-1$
if (id == null) {
continue;
}
// Read the widget class.
if (!checkClass(configurationElement, warningsToLog,
"Widget needs a class", id)) { //$NON-NLS-1$
continue;
}
final IWidget widgetClass = new WidgetProxy(configurationElement,
ATT_CLASS);
// Read out the visibleWhen expression.
final Expression visibleWhenExpression = readWhenElement(
configurationElement, TAG_VISIBLE_WHEN, id,
warningsToLog);
if (visibleWhenExpression == ERROR_EXPRESSION) {
continue;
}
// Read out the location elements.
final SLocation[] locations = readLocationElementsFromRegistry(
configurationElement, id, warningsToLog);
// Read the (optional) trim layout info from the regsitry
final SLayout layout = readLayoutFromRegistry(
configurationElement, id, warningsToLog);
final SWidget widget = menuService.getWidget(id);
widget.define(widgetClass, locations, layout);
menuContributions.add(menuService.contributeMenu(widget,
visibleWhenExpression));
}
logWarnings(
warningsToLog,
"Warnings while parsing the items from the 'org.eclipse.ui.menus' extension point"); //$NON-NLS-1$
}
/**
* The command service which is providing the commands for the workbench;
* must not be <code>null</code>.
*/
private final ICommandService commandService;
/**
* The menu service which should be populated with the values from the
* registry; must not be <code>null</code>.
*/
private final IMenuService menuService;
/**
* Constructs a new instance of {@link MenuPersistence}.
*
* @param menuService
* The menu service which should be populated with the values
* from the registry; must not be <code>null</code>.
* @param commandService
* The command service which is providing the commands for the
* workbench; must not be <code>null</code>.
*/
MenuPersistence(final IMenuService menuService,
final ICommandService commandService) {
if (menuService == null) {
throw new NullPointerException("The menu service cannot be null"); //$NON-NLS-1$
}
if (commandService == null) {
throw new NullPointerException("The command service cannot be null"); //$NON-NLS-1$
}
this.commandService = commandService;
this.menuService = menuService;
}
public final void dispose() {
super.dispose();
clearContributions(menuService);
}
protected final boolean isChangeImportant(final IRegistryChangeEvent event) {
/*
* TODO Menus will need to be re-read (i.e., re-verified) if any of the
* menu extensions change (i.e., menus), or if any of the command
* extensions change (i.e., action definitions).
*/
final IExtensionDelta[] menuDeltas = event.getExtensionDeltas(
PlatformUI.PLUGIN_ID, IWorkbenchRegistryConstants.PL_MENUS);
if (menuDeltas.length == 0) {
return false;
}
return true;
}
/**
* <p>
* Reads all of the menu elements and action sets from the registry.
* </p>
* <p>
* TODO Add support for modifications.
* </p>
*/
protected final void read() {
super.read();
// Create the extension registry mementos.
final IExtensionRegistry registry = Platform.getExtensionRegistry();
int itemCount = 0;
int menuCount = 0;
int groupCount = 0;
int widgetCount = 0;
int actionSetCount = 0;
final IConfigurationElement[][] indexedConfigurationElements = new IConfigurationElement[5][];
// Sort the commands extension point based on element name.
final IConfigurationElement[] menusExtensionPoint = registry
.getConfigurationElementsFor(EXTENSION_MENUS);
for (int i = 0; i < menusExtensionPoint.length; i++) {
final IConfigurationElement configurationElement = menusExtensionPoint[i];
final String name = configurationElement.getName();
// Check if it is a handler submission or a command definition.
if (TAG_ITEM.equals(name)) {
addElementToIndexedArray(configurationElement,
indexedConfigurationElements, INDEX_ITEMS, itemCount++);
} else if (TAG_MENU.equals(name)) {
addElementToIndexedArray(configurationElement,
indexedConfigurationElements, INDEX_MENUS, menuCount++);
} else if (TAG_GROUP.equals(name)) {
addElementToIndexedArray(configurationElement,
indexedConfigurationElements, INDEX_GROUPS,
groupCount++);
} else if (TAG_WIDGET.equals(name)) {
addElementToIndexedArray(configurationElement,
indexedConfigurationElements, INDEX_WIDGETS,
widgetCount++);
} else if (TAG_ACTION_SET.equals(name)) {
addElementToIndexedArray(configurationElement,
indexedConfigurationElements, INDEX_ACTION_SETS,
actionSetCount++);
}
}
clearContributions(menuService);
readItemsFromRegistry(indexedConfigurationElements[INDEX_ITEMS],
itemCount, menuService, commandService);
readMenusFromRegistry(indexedConfigurationElements[INDEX_MENUS],
menuCount, menuService);
readGroupsFromRegistry(indexedConfigurationElements[INDEX_GROUPS],
groupCount, menuService);
readWidgetsFromRegistry(indexedConfigurationElements[INDEX_WIDGETS],
widgetCount, menuService);
readActionSetsFromRegistry(
indexedConfigurationElements[INDEX_ACTION_SETS],
actionSetCount, menuService);
}
}