001: /*******************************************************************************
002: * Copyright (c) 2001, 2007 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.views.properties.tabbed.view;
011:
012: import java.util.ArrayList;
013: import java.util.Collections;
014: import java.util.Comparator;
015: import java.util.Iterator;
016: import java.util.List;
017:
018: import org.eclipse.core.runtime.CoreException;
019: import org.eclipse.core.runtime.IConfigurationElement;
020: import org.eclipse.core.runtime.IExtensionPoint;
021: import org.eclipse.core.runtime.IStatus;
022: import org.eclipse.core.runtime.Platform;
023: import org.eclipse.core.runtime.Status;
024: import org.eclipse.jface.viewers.ILabelProvider;
025: import org.eclipse.jface.viewers.ISelection;
026: import org.eclipse.jface.viewers.IStructuredContentProvider;
027: import org.eclipse.ui.IWorkbenchPart;
028: import org.eclipse.ui.internal.views.properties.tabbed.TabbedPropertyViewPlugin;
029: import org.eclipse.ui.internal.views.properties.tabbed.TabbedPropertyViewStatusCodes;
030: import org.eclipse.ui.internal.views.properties.tabbed.l10n.TabbedPropertyMessages;
031: import org.eclipse.ui.views.properties.tabbed.AbstractTabDescriptor;
032: import org.eclipse.ui.views.properties.tabbed.IActionProvider;
033: import org.eclipse.ui.views.properties.tabbed.ISectionDescriptor;
034: import org.eclipse.ui.views.properties.tabbed.ISectionDescriptorProvider;
035: import org.eclipse.ui.views.properties.tabbed.ITabDescriptor;
036: import org.eclipse.ui.views.properties.tabbed.ITabDescriptorProvider;
037: import org.eclipse.ui.views.properties.tabbed.ITypeMapper;
038:
039: import com.ibm.icu.text.MessageFormat;
040:
041: /**
042: * Provides information about the tabbed property extension points. Each tabbed
043: * property registry is associated with a unique contributor ID.
044: *
045: * @author Anthony Hunter
046: */
047: public class TabbedPropertyRegistry {
048:
049: private final static String NO_TAB_ERROR = TabbedPropertyMessages.TabbedPropertyRegistry_Non_existing_tab;
050:
051: private final static String CONTRIBUTOR_ERROR = TabbedPropertyMessages.TabbedPropertyRegistry_contributor_error;
052:
053: // extension point constants
054: private static final String EXTPT_CONTRIBUTOR = "propertyContributor"; //$NON-NLS-1$
055:
056: private static final String EXTPT_TABS = "propertyTabs"; //$NON-NLS-1$
057:
058: private static final String EXTPT_SECTIONS = "propertySections"; //$NON-NLS-1$
059:
060: private static final String ELEMENT_TAB = "propertyTab"; //$NON-NLS-1$
061:
062: private static final String ELEMENT_SECTION = "propertySection"; //$NON-NLS-1$
063:
064: private static final String ELEMENT_PROPERTY_CATEGORY = "propertyCategory"; //$NON-NLS-1$
065:
066: private static final String ATT_CATEGORY = "category"; //$NON-NLS-1$
067:
068: private static final String ATT_CONTRIBUTOR_ID = "contributorId"; //$NON-NLS-1$
069:
070: private static final String ATT_TYPE_MAPPER = "typeMapper"; //$NON-NLS-1$
071:
072: private static final String ATT_LABEL_PROVIDER = "labelProvider"; //$NON-NLS-1$
073:
074: private static final String ATT_ACTION_PROVIDER = "actionProvider"; //$NON-NLS-1$
075:
076: private static final String ATT_SECTION_DESCRIPTOR_PROVIDER = "sectionDescriptorProvider"; //$NON-NLS-1$
077:
078: private static final String ATT_TAB_DESCRIPTOR_PROVIDER = "tabDescriptorProvider"; //$NON-NLS-1$
079:
080: private static final String ATT_OVERRIDABLE_TAB_LIST_CONTENT_PROVIDER = "overridableTabListContentProvider"; //$NON-NLS-1$
081:
082: private static final String TOP = "top"; //$NON-NLS-1$
083:
084: protected String contributorId;
085:
086: protected IConfigurationElement contributorConfigurationElement;
087:
088: protected List propertyCategories;
089:
090: protected ILabelProvider labelProvider;
091:
092: protected IActionProvider actionProvider;
093:
094: protected ITypeMapper typeMapper;
095:
096: protected ISectionDescriptorProvider sectionDescriptorProvider;
097:
098: protected ITabDescriptorProvider tabDescriptorProvider;
099:
100: protected ITabDescriptor[] tabDescriptors;
101:
102: protected static final AbstractTabDescriptor[] EMPTY_DESCRIPTOR_ARRAY = new TabDescriptor[0];
103:
104: protected boolean overridableTabListContentProvider = false;
105:
106: /**
107: * There is one details registry for each contributor type.
108: */
109: protected TabbedPropertyRegistry(String id) {
110: this .contributorId = id;
111: this .propertyCategories = new ArrayList();
112: IConfigurationElement[] extensions = getConfigurationElements(EXTPT_CONTRIBUTOR);
113: for (int i = 0; i < extensions.length; i++) {
114: IConfigurationElement configurationElement = extensions[i];
115: String contributor = configurationElement
116: .getAttribute(ATT_CONTRIBUTOR_ID);
117: if (contributor == null || !id.equals(contributor)) {
118: continue;
119: }
120: this .contributorConfigurationElement = configurationElement;
121: try {
122: if (configurationElement
123: .getAttribute(ATT_LABEL_PROVIDER) != null) {
124: labelProvider = (ILabelProvider) configurationElement
125: .createExecutableExtension(ATT_LABEL_PROVIDER);
126: }
127: if (configurationElement
128: .getAttribute(ATT_ACTION_PROVIDER) != null) {
129: actionProvider = (IActionProvider) configurationElement
130: .createExecutableExtension(ATT_ACTION_PROVIDER);
131: }
132: if (configurationElement.getAttribute(ATT_TYPE_MAPPER) != null) {
133: typeMapper = (ITypeMapper) configurationElement
134: .createExecutableExtension(ATT_TYPE_MAPPER);
135: }
136: if (configurationElement
137: .getAttribute(ATT_SECTION_DESCRIPTOR_PROVIDER) != null) {
138: sectionDescriptorProvider = (ISectionDescriptorProvider) configurationElement
139: .createExecutableExtension(ATT_SECTION_DESCRIPTOR_PROVIDER);
140: }
141: if (configurationElement
142: .getAttribute(ATT_TAB_DESCRIPTOR_PROVIDER) != null) {
143: tabDescriptorProvider = (ITabDescriptorProvider) configurationElement
144: .createExecutableExtension(ATT_TAB_DESCRIPTOR_PROVIDER);
145: }
146: if (configurationElement
147: .getAttribute(ATT_OVERRIDABLE_TAB_LIST_CONTENT_PROVIDER) != null) {
148: String attributeBoolean = configurationElement
149: .getAttribute(ATT_OVERRIDABLE_TAB_LIST_CONTENT_PROVIDER);
150: overridableTabListContentProvider = attributeBoolean
151: .equals("true");//$NON-NLS-1$
152: }
153: } catch (CoreException exception) {
154: handleConfigurationError(id, exception);
155: }
156: addPropertyCategories(configurationElement);
157: }
158: if (propertyCategories == null || contributorId == null
159: || contributorConfigurationElement == null) {
160: handleConfigurationError(id, null);
161: this .contributorId = null;
162: }
163: }
164:
165: /**
166: * Gets the categories that are valid for this contributor.
167: *
168: * @param configurationElement
169: * the configuration element for this contributor.
170: */
171: private void addPropertyCategories(
172: IConfigurationElement configurationElement) {
173: IConfigurationElement[] elements = configurationElement
174: .getChildren(ELEMENT_PROPERTY_CATEGORY);
175: for (int i = 0; i < elements.length; i++) {
176: IConfigurationElement element = elements[i];
177: propertyCategories.add(element.getAttribute(ATT_CATEGORY));
178: }
179: }
180:
181: /**
182: * Handle the error when an issue is found loading from the configuration
183: * element.
184: *
185: * @param configurationElement
186: * the configuration element
187: * @param exception
188: * an optional CoreException
189: */
190: private void handleConfigurationError(String id,
191: CoreException exception) {
192: String message = MessageFormat.format(CONTRIBUTOR_ERROR,
193: new Object[] { id });
194: IStatus status = new Status(IStatus.ERROR,
195: TabbedPropertyViewPlugin.getPlugin().getBundle()
196: .getSymbolicName(),
197: TabbedPropertyViewStatusCodes.CONTRIBUTOR_ERROR,
198: message, exception);
199: TabbedPropertyViewPlugin.getPlugin().getLog().log(status);
200: }
201:
202: /**
203: * Reads property section extensions. Returns all section descriptors for
204: * the current contributor id or an empty array if none is found.
205: */
206: protected ISectionDescriptor[] readSectionDescriptors() {
207: List result = new ArrayList();
208: IConfigurationElement[] extensions = getConfigurationElements(EXTPT_SECTIONS);
209: for (int i = 0; i < extensions.length; i++) {
210: IConfigurationElement extension = extensions[i];
211: IConfigurationElement[] sections = extension
212: .getChildren(ELEMENT_SECTION);
213: for (int j = 0; j < sections.length; j++) {
214: IConfigurationElement section = sections[j];
215: ISectionDescriptor descriptor = new SectionDescriptor(
216: section, typeMapper);
217: result.add(descriptor);
218: }
219: }
220: return (ISectionDescriptor[]) result
221: .toArray(new ISectionDescriptor[result.size()]);
222: }
223:
224: /**
225: * Returns the configuration elements targeted for the given extension point
226: * and the current contributor id. The elements are also sorted by plugin
227: * prerequisite order.
228: */
229: protected IConfigurationElement[] getConfigurationElements(
230: String extensionPointId) {
231: if (contributorId == null) {
232: return new IConfigurationElement[0];
233: }
234: IExtensionPoint point = Platform.getExtensionRegistry()
235: .getExtensionPoint(
236: TabbedPropertyViewPlugin.getPlugin()
237: .getBundle().getSymbolicName(),
238: extensionPointId);
239: IConfigurationElement[] extensions = point
240: .getConfigurationElements();
241: List unordered = new ArrayList(extensions.length);
242: for (int i = 0; i < extensions.length; i++) {
243: IConfigurationElement extension = extensions[i];
244: if (!extension.getName().equals(extensionPointId)) {
245: continue;
246: }
247: String contributor = extension
248: .getAttribute(ATT_CONTRIBUTOR_ID);
249: if (!contributorId.equals(contributor)) {
250: continue;
251: }
252: unordered.add(extension);
253: }
254: return (IConfigurationElement[]) unordered
255: .toArray(new IConfigurationElement[unordered.size()]);
256: }
257:
258: /**
259: * Returns the index of the given element in the array.
260: */
261: private int getIndex(Object[] array, Object target) {
262: for (int i = 0; i < array.length; i++) {
263: if (array[i].equals(target)) {
264: return i;
265: }
266: }
267: return -1; // should never happen
268: }
269:
270: /**
271: * Returns all section descriptors for the provided selection.
272: *
273: * @param part
274: * the workbench part containing the selection
275: * @param selection
276: * the current selection.
277: * @return all section descriptors.
278: */
279: public ITabDescriptor[] getTabDescriptors(IWorkbenchPart part,
280: ISelection selection) {
281: if (selection == null || selection.isEmpty()) {
282: return EMPTY_DESCRIPTOR_ARRAY;
283: }
284:
285: ITabDescriptor[] allDescriptors = null;
286: if (tabDescriptorProvider == null) {
287: allDescriptors = getAllTabDescriptors();
288: } else {
289: allDescriptors = tabDescriptorProvider.getTabDescriptors(
290: part, selection);
291: }
292:
293: ITabDescriptor[] result = filterTabDescriptors(allDescriptors,
294: part, selection);
295: return result;
296: }
297:
298: /**
299: * Filters out the tab descriptors that do not have any sections for the
300: * given input.
301: */
302: protected ITabDescriptor[] filterTabDescriptors(
303: ITabDescriptor[] descriptors, IWorkbenchPart part,
304: ISelection selection) {
305: List result = new ArrayList();
306: for (int i = 0; i < descriptors.length; i++) {
307: ITabDescriptor descriptor = adaptDescriptorFor(
308: descriptors[i], part, selection);
309: if (!descriptor.getSectionDescriptors().isEmpty()) {
310: result.add(descriptor);
311: }
312: }
313: if (result.size() == 0) {
314: return EMPTY_DESCRIPTOR_ARRAY;
315: }
316: return (ITabDescriptor[]) result
317: .toArray(new ITabDescriptor[result.size()]);
318: }
319:
320: /**
321: * Given a property tab descriptor remove all its section descriptors that
322: * do not apply to the given input object.
323: */
324: protected ITabDescriptor adaptDescriptorFor(ITabDescriptor target,
325: IWorkbenchPart part, ISelection selection) {
326: List filteredSectionDescriptors = new ArrayList();
327: List descriptors = target.getSectionDescriptors();
328: for (Iterator iter = descriptors.iterator(); iter.hasNext();) {
329: ISectionDescriptor descriptor = (ISectionDescriptor) iter
330: .next();
331: if (descriptor.appliesTo(part, selection)) {
332: filteredSectionDescriptors.add(descriptor);
333: }
334: }
335: AbstractTabDescriptor result = (AbstractTabDescriptor) ((AbstractTabDescriptor) target)
336: .clone();
337: result.setSectionDescriptors(filteredSectionDescriptors);
338: return result;
339: }
340:
341: /**
342: * Reads property tab extensions. Returns all tab descriptors for the
343: * current contributor id or an empty array if none is found.
344: */
345: protected ITabDescriptor[] getAllTabDescriptors() {
346: if (tabDescriptors == null) {
347: List temp = readTabDescriptors();
348: populateWithSectionDescriptors(temp);
349: temp = sortTabDescriptorsByCategory(temp);
350: temp = sortTabDescriptorsByAfterTab(temp);
351: tabDescriptors = (TabDescriptor[]) temp
352: .toArray(new TabDescriptor[temp.size()]);
353: }
354: return tabDescriptors;
355: }
356:
357: /**
358: * Reads property tab extensions. Returns all tab descriptors for the
359: * current contributor id or an empty list if none is found.
360: */
361: protected List readTabDescriptors() {
362: List result = new ArrayList();
363: IConfigurationElement[] extensions = getConfigurationElements(EXTPT_TABS);
364: for (int i = 0; i < extensions.length; i++) {
365: IConfigurationElement extension = extensions[i];
366: IConfigurationElement[] tabs = extension
367: .getChildren(ELEMENT_TAB);
368: for (int j = 0; j < tabs.length; j++) {
369: IConfigurationElement tab = tabs[j];
370: TabDescriptor descriptor = new TabDescriptor(tab);
371: result.add(descriptor);
372: }
373: }
374: return result;
375: }
376:
377: /**
378: * Populates the given tab descriptors with section descriptors.
379: */
380: protected void populateWithSectionDescriptors(List aTabDescriptors) {
381: ISectionDescriptor[] sections = null;
382: if (sectionDescriptorProvider != null) {
383: sections = sectionDescriptorProvider
384: .getSectionDescriptors();
385: } else {
386: sections = readSectionDescriptors();
387: }
388: for (int i = 0; i < sections.length; i++) {
389: ISectionDescriptor section = sections[i];
390: appendToTabDescriptor(section, aTabDescriptors);
391: }
392: }
393:
394: /**
395: * Appends the given section to a tab from the list.
396: */
397: protected void appendToTabDescriptor(ISectionDescriptor section,
398: List aTabDescriptors) {
399: for (Iterator i = aTabDescriptors.iterator(); i.hasNext();) {
400: TabDescriptor tab = (TabDescriptor) i.next();
401: if (tab.append(section)) {
402: return;
403: }
404: }
405: // could not append the section to any of the existing tabs - log error
406: String message = MessageFormat
407: .format(NO_TAB_ERROR, new Object[] { section.getId(),
408: section.getTargetTab() });
409: IStatus status = new Status(IStatus.ERROR,
410: TabbedPropertyViewPlugin.getPlugin().getBundle()
411: .getSymbolicName(),
412: TabbedPropertyViewStatusCodes.NO_TAB_ERROR, message,
413: null);
414: TabbedPropertyViewPlugin.getPlugin().getLog().log(status);
415: }
416:
417: /**
418: * Sorts the tab descriptors in the given list according to category.
419: */
420: protected List sortTabDescriptorsByCategory(List descriptors) {
421: Collections.sort(descriptors, new Comparator() {
422:
423: public int compare(Object arg0, Object arg1) {
424: TabDescriptor one = (TabDescriptor) arg0;
425: TabDescriptor two = (TabDescriptor) arg1;
426: String categoryOne = one.getCategory();
427: String categoryTwo = two.getCategory();
428: int categoryOnePosition = getIndex(propertyCategories
429: .toArray(), categoryOne);
430: int categoryTwoPosition = getIndex(propertyCategories
431: .toArray(), categoryTwo);
432: return categoryOnePosition - categoryTwoPosition;
433: }
434: });
435: return descriptors;
436: }
437:
438: /**
439: * Sorts the tab descriptors in the given list according to afterTab.
440: */
441: protected List sortTabDescriptorsByAfterTab(List tabs) {
442: if (tabs.size() == 0 || propertyCategories == null) {
443: return tabs;
444: }
445: List sorted = new ArrayList();
446: int categoryIndex = 0;
447: for (int i = 0; i < propertyCategories.size(); i++) {
448: List categoryList = new ArrayList();
449: String category = (String) propertyCategories.get(i);
450: int topOfCategory = categoryIndex;
451: int endOfCategory = categoryIndex;
452: while (endOfCategory < tabs.size()
453: && ((TabDescriptor) tabs.get(endOfCategory))
454: .getCategory().equals(category)) {
455: endOfCategory++;
456: }
457: for (int j = topOfCategory; j < endOfCategory; j++) {
458: TabDescriptor tab = (TabDescriptor) tabs.get(j);
459: if (tab.getAfterTab().equals(TOP)) {
460: categoryList.add(0, tabs.get(j));
461: } else {
462: categoryList.add(tabs.get(j));
463: }
464: }
465: Collections.sort(categoryList, new Comparator() {
466:
467: public int compare(Object arg0, Object arg1) {
468: TabDescriptor one = (TabDescriptor) arg0;
469: TabDescriptor two = (TabDescriptor) arg1;
470: if (two.getAfterTab().equals(one.getId())) {
471: return -1;
472: } else if (one.getAfterTab().equals(two.getId())) {
473: return 1;
474: } else {
475: return 0;
476: }
477: }
478: });
479: for (int j = 0; j < categoryList.size(); j++) {
480: sorted.add(categoryList.get(j));
481: }
482: categoryIndex = endOfCategory;
483: }
484: return sorted;
485: }
486:
487: /**
488: * Gets the type mapper for the contributor.
489: *
490: * @return the type mapper for the contributor.
491: */
492: public ITypeMapper getTypeMapper() {
493: return typeMapper;
494: }
495:
496: /**
497: * Gets the label provider for the contributor.
498: *
499: * @return the label provider for the contributor.
500: */
501: public ILabelProvider getLabelProvider() {
502: return labelProvider;
503: }
504:
505: /**
506: * Gets the action provider for the contributor.
507: *
508: * @return the action provider for the contributor.
509: */
510: public IActionProvider getActionProvider() {
511: return actionProvider;
512: }
513:
514: /**
515: * Gets the tab list content provider for the contributor.
516: *
517: * @return the tab list content provider for the contributor.
518: */
519: public IStructuredContentProvider getTabListContentProvider() {
520: if (overridableTabListContentProvider) {
521: return new OverridableTabListContentProvider(this );
522: }
523: return new TabListContentProvider(this);
524: }
525: }
|