/******************************************************************************* * Copyright (c) 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.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.core.expressions.Expression; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.Platform; import org.eclipse.jface.action.IContributionItem; import org.eclipse.jface.menus.IWidget; import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants; import org.eclipse.ui.internal.util.Util; import org.eclipse.ui.menus.IMenuService; import org.eclipse.ui.menus.IWorkbenchWidget; /** * Handles the top level caching for 3.2 style trim * contributions. * * @since 3.3 * */ public class TrimAdditionCacheEntry { private IConfigurationElement additionElement; private MenuLocationURI uri = null; /** * The map contains {@link IWorkbenchWidget} entries * for widgets that have failed to load on a previous * attempt. Used to prevent multiple retries at * loading a widget (which spams the log). */ private Map failedWidgets = new HashMap(); /** * Maps the widget back to it's configurtation element */ private Map widgetToConfigElementMap = new HashMap(); // Caches /** * Maps an IContributionItem to its corresponding IConfigurationElement */ Map iciToConfigElementMap = new HashMap(); public TrimAdditionCacheEntry(IConfigurationElement element, MenuLocationURI uri, IMenuService service) { this.additionElement = element; this.uri = uri; } /** * Populate the list * * @param additions */ public void getContributionItems(List additions) { additions.clear(); } /* (non-Javadoc) * @see org.eclipse.ui.internal.menus.MenuCacheEntry#generateSubCaches() */ public void generateSubCaches() { // TODO Auto-generated method stub } /* (non-Javadoc) * @see org.eclipse.ui.internal.menus.MenuCacheEntry#getVisibleWhenForItem(org.eclipse.jface.action.IContributionItem) */ public Expression getVisibleWhenForItem(IContributionItem item) { // TODO Auto-generated method stub return null; } /** * @return */ public String getId() { return additionElement.getAttribute(IWorkbenchRegistryConstants.ATT_ID); } /** * @return <code>true</code> iff the group is positioned at the start * (or 'before') the entry that it is relative to. Default is true * */ public boolean isAtStart() { IConfigurationElement location = additionElement.getChildren(IWorkbenchRegistryConstants.TAG_LOCATION)[0]; if (location.getChildren(IWorkbenchRegistryConstants.TAG_ORDER).length > 0) { IConfigurationElement order = location.getChildren(IWorkbenchRegistryConstants.TAG_ORDER)[0]; String pos = order.getAttribute(IWorkbenchRegistryConstants.ATT_POSITION); if (pos != null) return (pos.equals("start") | pos.equals("before")); //$NON-NLS-1$//$NON-NLS-2$ } return true; } /** * Returns whether or not the defining {@link IConfigurationElement} * declares that the widget should use extra space in the 'major' * dimension (ie. use extra horizontal space in the status area). * The space is equally divided with other elementa in the same * trim area that also want to use the extra space. * * @param widgetElement the {@link IConfigurationElement} declaring this * widget. * * @return <code>true</code> iff the resulting widget should use * extra major space */ public boolean fillMajor(IConfigurationElement widgetElement) { if (widgetElement.getChildren(IWorkbenchRegistryConstants.TAG_LAYOUT).length==0) { return false; } IConfigurationElement layout = widgetElement.getChildren(IWorkbenchRegistryConstants.TAG_LAYOUT)[0]; String fillMajorVal = layout.getAttribute(IWorkbenchRegistryConstants.ATT_FILL_MAJOR); return (fillMajorVal != null && fillMajorVal.equals("true")); //$NON-NLS-1$ } /** * Returns whether or not the defining {@link IConfigurationElement} * declares that the widget should use extra space in the 'minor' * dimension (ie. use extra vertical space in the status area) * * @param widgetElement the {@link IConfigurationElement} declaring this * widget. * * @return <code>true</code> iff the resulting widget should use * extra minor space */ public boolean fillMinor(IConfigurationElement widgetElement) { if (widgetElement.getChildren(IWorkbenchRegistryConstants.TAG_LAYOUT).length==0) { return false; } IConfigurationElement layout = widgetElement.getChildren(IWorkbenchRegistryConstants.TAG_LAYOUT)[0]; String fillMinorVal = layout.getAttribute(IWorkbenchRegistryConstants.ATT_FILL_MINOR); return (fillMinorVal != null && fillMinorVal.equals("true")); //$NON-NLS-1$ } /** * @return The list of IConfigurationElements representing * widgets to be added into this 'group' */ private List getWidgetConfigs() { List widgetConfigs = new ArrayList(); // Return to the 'root' of the config tree and gather all elements // for this 'group'. Note that while this is sub-optimal // performace-wise that there are expected to be -very- // few contributions in total (i.e. 10's, not 100's) final IExtensionRegistry registry = Platform.getExtensionRegistry(); final IConfigurationElement[] widgetElements = registry .getConfigurationElementsFor(IWorkbenchRegistryConstants.EXTENSION_MENUS); // Locate all 'widget' additions appropriate for -this- group for (int i = 0; i < widgetElements.length; i++) { // Only process 'widget' entries if (!IWorkbenchRegistryConstants.TAG_WIDGET.equals(widgetElements[i].getName())) continue; // Define the initial URI spec if (widgetElements[i].getChildren(IWorkbenchRegistryConstants.TAG_LOCATION).length > 0) { IConfigurationElement location = widgetElements[i].getChildren(IWorkbenchRegistryConstants.TAG_LOCATION)[0]; if (location.getChildren(IWorkbenchRegistryConstants.TAG_BAR).length > 0) { IConfigurationElement bar = location.getChildren(IWorkbenchRegistryConstants.TAG_BAR)[0]; // The bar's path represents the 'group' it should go into String path = bar.getAttribute(IWorkbenchRegistryConstants.ATT_PATH); if (path != null && path.equals(getId())) widgetConfigs.add(widgetElements[i]); } } } return widgetConfigs; } /** * Attempts to load -all- widgets for this entry and * keeps track of the successful loads only. Only elements * who can be successfully loaded will be seen by the * builder. * * @return The list of <code>IWorkbenchWidget</code> entries * that have been successfully loaded */ public List getWidgets() { List loadedWidgets = new ArrayList(); // Get the widget config elements for this 'group' List widgetConfigs = getWidgetConfigs(); for (Iterator iterator = widgetConfigs.iterator(); iterator .hasNext();) { IConfigurationElement widgetCE = (IConfigurationElement) iterator.next(); // skip elements that are known to fail if (failedWidgets.containsKey(widgetCE)) continue; IWorkbenchWidget loadedWidget = loadWidget(widgetCE); // Either add it to the 'valid' list or mark it // as failed if (loadedWidget != null) { loadedWidgets.add(loadedWidget); widgetToConfigElementMap.put(loadedWidget, widgetCE); } else failedWidgets.put(widgetCE, widgetCE); } return loadedWidgets; } /** * Attempts to load the executable extension defined within the given * configuration element. An error is logged for any widget that fails * to load. * * @param widgetCE The {@link IConfigurationElement} containing the * widget's 'class' specification. * * @return The loaded {@link IWorkbenchWidget} or <code>null</code> * if the loading fails */ private IWorkbenchWidget loadWidget(IConfigurationElement widgetCE) { return (IWorkbenchWidget) Util.safeLoadExecutableExtension(widgetCE, IWorkbenchRegistryConstants.ATT_CLASS, IWorkbenchWidget.class); } /** * @param widget The {@link IWorkbenchWidget} to get the defining configuration * element for. * * @return The defining {@link IConfigurationElement} */ public IConfigurationElement getElement(IWorkbenchWidget widget) { return (IConfigurationElement) widgetToConfigElementMap.get(widget); } /** * @param widget */ public void removeWidget(IWidget widget) { widgetToConfigElementMap.remove(widget); } public MenuLocationURI getUri() { return uri; } }