001: /*******************************************************************************
002: * Copyright (c) 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: ******************************************************************************/package org.eclipse.ui.internal.menus;
011:
012: import java.util.ArrayList;
013: import java.util.HashMap;
014: import java.util.Iterator;
015: import java.util.List;
016: import java.util.Map;
017:
018: import org.eclipse.core.expressions.Expression;
019: import org.eclipse.core.runtime.IConfigurationElement;
020: import org.eclipse.core.runtime.IExtensionRegistry;
021: import org.eclipse.core.runtime.Platform;
022: import org.eclipse.jface.action.IContributionItem;
023: import org.eclipse.jface.menus.IWidget;
024: import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
025: import org.eclipse.ui.internal.util.Util;
026: import org.eclipse.ui.menus.IMenuService;
027: import org.eclipse.ui.menus.IWorkbenchWidget;
028:
029: /**
030: * Handles the top level caching for 3.2 style trim
031: * contributions.
032: *
033: * @since 3.3
034: *
035: */
036: public class TrimAdditionCacheEntry {
037: private IConfigurationElement additionElement;
038: private MenuLocationURI uri = null;
039:
040: /**
041: * The map contains {@link IWorkbenchWidget} entries
042: * for widgets that have failed to load on a previous
043: * attempt. Used to prevent multiple retries at
044: * loading a widget (which spams the log).
045: */
046: private Map failedWidgets = new HashMap();
047: /**
048: * Maps the widget back to it's configurtation element
049: */
050: private Map widgetToConfigElementMap = new HashMap();
051:
052: // Caches
053:
054: /**
055: * Maps an IContributionItem to its corresponding IConfigurationElement
056: */
057: Map iciToConfigElementMap = new HashMap();
058:
059: public TrimAdditionCacheEntry(IConfigurationElement element,
060: MenuLocationURI uri, IMenuService service) {
061: this .additionElement = element;
062: this .uri = uri;
063: }
064:
065: /**
066: * Populate the list
067: *
068: * @param additions
069: */
070: public void getContributionItems(List additions) {
071: additions.clear();
072:
073: }
074:
075: /* (non-Javadoc)
076: * @see org.eclipse.ui.internal.menus.MenuCacheEntry#generateSubCaches()
077: */
078: public void generateSubCaches() {
079: // TODO Auto-generated method stub
080:
081: }
082:
083: /* (non-Javadoc)
084: * @see org.eclipse.ui.internal.menus.MenuCacheEntry#getVisibleWhenForItem(org.eclipse.jface.action.IContributionItem)
085: */
086: public Expression getVisibleWhenForItem(IContributionItem item) {
087: // TODO Auto-generated method stub
088: return null;
089: }
090:
091: /**
092: * @return
093: */
094: public String getId() {
095: return additionElement
096: .getAttribute(IWorkbenchRegistryConstants.ATT_ID);
097: }
098:
099: /**
100: * @return <code>true</code> iff the group is positioned at the start
101: * (or 'before') the entry that it is relative to. Default is true
102: *
103: */
104: public boolean isAtStart() {
105: IConfigurationElement location = additionElement
106: .getChildren(IWorkbenchRegistryConstants.TAG_LOCATION)[0];
107: if (location.getChildren(IWorkbenchRegistryConstants.TAG_ORDER).length > 0) {
108: IConfigurationElement order = location
109: .getChildren(IWorkbenchRegistryConstants.TAG_ORDER)[0];
110:
111: String pos = order
112: .getAttribute(IWorkbenchRegistryConstants.ATT_POSITION);
113: if (pos != null)
114: return (pos.equals("start") | pos.equals("before")); //$NON-NLS-1$//$NON-NLS-2$
115: }
116: return true;
117: }
118:
119: /**
120: * Returns whether or not the defining {@link IConfigurationElement}
121: * declares that the widget should use extra space in the 'major'
122: * dimension (ie. use extra horizontal space in the status area).
123: * The space is equally divided with other elementa in the same
124: * trim area that also want to use the extra space.
125: *
126: * @param widgetElement the {@link IConfigurationElement} declaring this
127: * widget.
128: *
129: * @return <code>true</code> iff the resulting widget should use
130: * extra major space
131: */
132: public boolean fillMajor(IConfigurationElement widgetElement) {
133: if (widgetElement
134: .getChildren(IWorkbenchRegistryConstants.TAG_LAYOUT).length == 0) {
135: return false;
136: }
137: IConfigurationElement layout = widgetElement
138: .getChildren(IWorkbenchRegistryConstants.TAG_LAYOUT)[0];
139: String fillMajorVal = layout
140: .getAttribute(IWorkbenchRegistryConstants.ATT_FILL_MAJOR);
141:
142: return (fillMajorVal != null && fillMajorVal.equals("true")); //$NON-NLS-1$
143: }
144:
145: /**
146: * Returns whether or not the defining {@link IConfigurationElement}
147: * declares that the widget should use extra space in the 'minor'
148: * dimension (ie. use extra vertical space in the status area)
149: *
150: * @param widgetElement the {@link IConfigurationElement} declaring this
151: * widget.
152: *
153: * @return <code>true</code> iff the resulting widget should use
154: * extra minor space
155: */
156: public boolean fillMinor(IConfigurationElement widgetElement) {
157: if (widgetElement
158: .getChildren(IWorkbenchRegistryConstants.TAG_LAYOUT).length == 0) {
159: return false;
160: }
161: IConfigurationElement layout = widgetElement
162: .getChildren(IWorkbenchRegistryConstants.TAG_LAYOUT)[0];
163: String fillMinorVal = layout
164: .getAttribute(IWorkbenchRegistryConstants.ATT_FILL_MINOR);
165:
166: return (fillMinorVal != null && fillMinorVal.equals("true")); //$NON-NLS-1$
167: }
168:
169: /**
170: * @return The list of IConfigurationElements representing
171: * widgets to be added into this 'group'
172: */
173: private List getWidgetConfigs() {
174: List widgetConfigs = new ArrayList();
175:
176: // Return to the 'root' of the config tree and gather all elements
177: // for this 'group'. Note that while this is sub-optimal
178: // performace-wise that there are expected to be -very-
179: // few contributions in total (i.e. 10's, not 100's)
180: final IExtensionRegistry registry = Platform
181: .getExtensionRegistry();
182: final IConfigurationElement[] widgetElements = registry
183: .getConfigurationElementsFor(IWorkbenchRegistryConstants.EXTENSION_MENUS);
184:
185: // Locate all 'widget' additions appropriate for -this- group
186: for (int i = 0; i < widgetElements.length; i++) {
187: // Only process 'widget' entries
188: if (!IWorkbenchRegistryConstants.TAG_WIDGET
189: .equals(widgetElements[i].getName()))
190: continue;
191:
192: // Define the initial URI spec
193: if (widgetElements[i]
194: .getChildren(IWorkbenchRegistryConstants.TAG_LOCATION).length > 0) {
195: IConfigurationElement location = widgetElements[i]
196: .getChildren(IWorkbenchRegistryConstants.TAG_LOCATION)[0];
197: if (location
198: .getChildren(IWorkbenchRegistryConstants.TAG_BAR).length > 0) {
199: IConfigurationElement bar = location
200: .getChildren(IWorkbenchRegistryConstants.TAG_BAR)[0];
201:
202: // The bar's path represents the 'group' it should go into
203: String path = bar
204: .getAttribute(IWorkbenchRegistryConstants.ATT_PATH);
205: if (path != null && path.equals(getId()))
206: widgetConfigs.add(widgetElements[i]);
207: }
208: }
209: }
210:
211: return widgetConfigs;
212: }
213:
214: /**
215: * Attempts to load -all- widgets for this entry and
216: * keeps track of the successful loads only. Only elements
217: * who can be successfully loaded will be seen by the
218: * builder.
219: *
220: * @return The list of <code>IWorkbenchWidget</code> entries
221: * that have been successfully loaded
222: */
223: public List getWidgets() {
224: List loadedWidgets = new ArrayList();
225:
226: // Get the widget config elements for this 'group'
227: List widgetConfigs = getWidgetConfigs();
228: for (Iterator iterator = widgetConfigs.iterator(); iterator
229: .hasNext();) {
230: IConfigurationElement widgetCE = (IConfigurationElement) iterator
231: .next();
232:
233: // skip elements that are known to fail
234: if (failedWidgets.containsKey(widgetCE))
235: continue;
236:
237: IWorkbenchWidget loadedWidget = loadWidget(widgetCE);
238:
239: // Either add it to the 'valid' list or mark it
240: // as failed
241: if (loadedWidget != null) {
242: loadedWidgets.add(loadedWidget);
243: widgetToConfigElementMap.put(loadedWidget, widgetCE);
244: } else
245: failedWidgets.put(widgetCE, widgetCE);
246: }
247:
248: return loadedWidgets;
249: }
250:
251: /**
252: * Attempts to load the executable extension defined within the given
253: * configuration element. An error is logged for any widget that fails
254: * to load.
255: *
256: * @param widgetCE The {@link IConfigurationElement} containing the
257: * widget's 'class' specification.
258: *
259: * @return The loaded {@link IWorkbenchWidget} or <code>null</code>
260: * if the loading fails
261: */
262: private IWorkbenchWidget loadWidget(IConfigurationElement widgetCE) {
263: return (IWorkbenchWidget) Util.safeLoadExecutableExtension(
264: widgetCE, IWorkbenchRegistryConstants.ATT_CLASS,
265: IWorkbenchWidget.class);
266: }
267:
268: /**
269: * @param widget The {@link IWorkbenchWidget} to get the defining configuration
270: * element for.
271: *
272: * @return The defining {@link IConfigurationElement}
273: */
274: public IConfigurationElement getElement(IWorkbenchWidget widget) {
275: return (IConfigurationElement) widgetToConfigElementMap
276: .get(widget);
277: }
278:
279: /**
280: * @param widget
281: */
282: public void removeWidget(IWidget widget) {
283: widgetToConfigElementMap.remove(widget);
284: }
285:
286: public MenuLocationURI getUri() {
287: return uri;
288: }
289: }
|