| /******************************************************************************* |
| * Copyright (c) 2001, 2010 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.views.properties.tabbed.view; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import com.ibm.icu.text.MessageFormat; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExtensionPoint; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.core.runtime.Status; |
| |
| import org.eclipse.jface.viewers.ILabelProvider; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.IStructuredContentProvider; |
| |
| import org.eclipse.ui.IWorkbenchPart; |
| import org.eclipse.ui.internal.views.properties.tabbed.TabbedPropertyViewPlugin; |
| import org.eclipse.ui.internal.views.properties.tabbed.TabbedPropertyViewStatusCodes; |
| import org.eclipse.ui.internal.views.properties.tabbed.l10n.TabbedPropertyMessages; |
| import org.eclipse.ui.views.properties.tabbed.AbstractTabDescriptor; |
| import org.eclipse.ui.views.properties.tabbed.IActionProvider; |
| import org.eclipse.ui.views.properties.tabbed.ISectionDescriptor; |
| import org.eclipse.ui.views.properties.tabbed.ISectionDescriptorProvider; |
| import org.eclipse.ui.views.properties.tabbed.ITabDescriptor; |
| import org.eclipse.ui.views.properties.tabbed.ITabDescriptorProvider; |
| import org.eclipse.ui.views.properties.tabbed.ITypeMapper; |
| |
| /** |
| * Provides information about the tabbed property extension points. Each tabbed |
| * property registry is associated with a unique contributor ID. |
| * |
| * @author Anthony Hunter |
| */ |
| public class TabbedPropertyRegistry { |
| |
| private final static String NO_TAB_ERROR = TabbedPropertyMessages.TabbedPropertyRegistry_Non_existing_tab; |
| |
| private final static String CONTRIBUTOR_ERROR = TabbedPropertyMessages.TabbedPropertyRegistry_contributor_error; |
| |
| private final static String TAB_ERROR = TabbedPropertyMessages.TabDescriptor_Tab_unknown_category; |
| |
| // extension point constants |
| private static final String EXTPT_CONTRIBUTOR = "propertyContributor"; //$NON-NLS-1$ |
| |
| private static final String EXTPT_TABS = "propertyTabs"; //$NON-NLS-1$ |
| |
| private static final String EXTPT_SECTIONS = "propertySections"; //$NON-NLS-1$ |
| |
| private static final String ELEMENT_TAB = "propertyTab"; //$NON-NLS-1$ |
| |
| private static final String ELEMENT_SECTION = "propertySection"; //$NON-NLS-1$ |
| |
| private static final String ELEMENT_PROPERTY_CATEGORY = "propertyCategory"; //$NON-NLS-1$ |
| |
| private static final String ATT_CATEGORY = "category"; //$NON-NLS-1$ |
| |
| private static final String ATT_CONTRIBUTOR_ID = "contributorId"; //$NON-NLS-1$ |
| |
| private static final String ATT_TYPE_MAPPER = "typeMapper"; //$NON-NLS-1$ |
| |
| private static final String ATT_LABEL_PROVIDER = "labelProvider"; //$NON-NLS-1$ |
| |
| private static final String ATT_ACTION_PROVIDER = "actionProvider"; //$NON-NLS-1$ |
| |
| private static final String ATT_SECTION_DESCRIPTOR_PROVIDER = "sectionDescriptorProvider"; //$NON-NLS-1$ |
| |
| private static final String ATT_TAB_DESCRIPTOR_PROVIDER = "tabDescriptorProvider"; //$NON-NLS-1$ |
| |
| private static final String ATT_OVERRIDABLE_TAB_LIST_CONTENT_PROVIDER = "overridableTabListContentProvider"; //$NON-NLS-1$ |
| |
| private static final String TOP = "top"; //$NON-NLS-1$ |
| |
| protected String contributorId; |
| |
| protected IConfigurationElement contributorConfigurationElement; |
| |
| protected List propertyCategories; |
| |
| protected ILabelProvider labelProvider; |
| |
| protected IActionProvider actionProvider; |
| |
| protected ITypeMapper typeMapper; |
| |
| protected ISectionDescriptorProvider sectionDescriptorProvider; |
| |
| protected ITabDescriptorProvider tabDescriptorProvider; |
| |
| protected ITabDescriptor[] tabDescriptors; |
| |
| protected static final AbstractTabDescriptor[] EMPTY_DESCRIPTOR_ARRAY = new TabDescriptor[0]; |
| |
| protected boolean overridableTabListContentProvider = false; |
| |
| /** |
| * There is one details registry for each contributor type. |
| */ |
| protected TabbedPropertyRegistry(String id) { |
| this.contributorId = id; |
| this.propertyCategories = new ArrayList(); |
| IConfigurationElement[] extensions = getConfigurationElements(EXTPT_CONTRIBUTOR); |
| for (int i = 0; i < extensions.length; i++) { |
| IConfigurationElement configurationElement = extensions[i]; |
| String contributor = configurationElement |
| .getAttribute(ATT_CONTRIBUTOR_ID); |
| if (contributor == null || !id.equals(contributor)) { |
| continue; |
| } |
| this.contributorConfigurationElement = configurationElement; |
| try { |
| if (configurationElement.getAttribute(ATT_LABEL_PROVIDER) != null) { |
| labelProvider = (ILabelProvider) configurationElement |
| .createExecutableExtension(ATT_LABEL_PROVIDER); |
| } |
| if (configurationElement.getAttribute(ATT_ACTION_PROVIDER) != null) { |
| actionProvider = (IActionProvider) configurationElement |
| .createExecutableExtension(ATT_ACTION_PROVIDER); |
| } |
| if (configurationElement.getAttribute(ATT_TYPE_MAPPER) != null) { |
| typeMapper = (ITypeMapper) configurationElement |
| .createExecutableExtension(ATT_TYPE_MAPPER); |
| } |
| if (configurationElement |
| .getAttribute(ATT_SECTION_DESCRIPTOR_PROVIDER) != null) { |
| sectionDescriptorProvider = (ISectionDescriptorProvider) configurationElement |
| .createExecutableExtension(ATT_SECTION_DESCRIPTOR_PROVIDER); |
| } |
| if (configurationElement |
| .getAttribute(ATT_TAB_DESCRIPTOR_PROVIDER) != null) { |
| tabDescriptorProvider = (ITabDescriptorProvider) configurationElement |
| .createExecutableExtension(ATT_TAB_DESCRIPTOR_PROVIDER); |
| } |
| if (configurationElement |
| .getAttribute(ATT_OVERRIDABLE_TAB_LIST_CONTENT_PROVIDER) != null) { |
| String attributeBoolean = configurationElement |
| .getAttribute(ATT_OVERRIDABLE_TAB_LIST_CONTENT_PROVIDER); |
| overridableTabListContentProvider = attributeBoolean |
| .equals("true");//$NON-NLS-1$ |
| } |
| } catch (CoreException exception) { |
| handleConfigurationError(id, exception); |
| } |
| addPropertyCategories(configurationElement); |
| } |
| if (propertyCategories == null || contributorId == null || |
| contributorConfigurationElement == null) { |
| handleConfigurationError(id, null); |
| this.contributorId = null; |
| } |
| } |
| |
| /** |
| * Gets the categories that are valid for this contributor. |
| * |
| * @param configurationElement |
| * the configuration element for this contributor. |
| */ |
| private void addPropertyCategories( |
| IConfigurationElement configurationElement) { |
| IConfigurationElement[] elements = configurationElement |
| .getChildren(ELEMENT_PROPERTY_CATEGORY); |
| for (int i = 0; i < elements.length; i++) { |
| IConfigurationElement element = elements[i]; |
| propertyCategories.add(element.getAttribute(ATT_CATEGORY)); |
| } |
| } |
| |
| /** |
| * Handle the error when an issue is found loading from the configuration |
| * element. |
| * |
| * @param id |
| * the configuration id. |
| * @param exception |
| * an optional CoreException |
| */ |
| private void handleConfigurationError(String id, CoreException exception) { |
| String message = MessageFormat.format(CONTRIBUTOR_ERROR, |
| new Object[] { id }); |
| IStatus status = new Status(IStatus.ERROR, TabbedPropertyViewPlugin |
| .getPlugin().getBundle().getSymbolicName(), |
| TabbedPropertyViewStatusCodes.CONTRIBUTOR_ERROR, message, |
| exception); |
| TabbedPropertyViewPlugin.getPlugin().getLog().log(status); |
| } |
| |
| /** |
| * Reads property section extensions. Returns all section descriptors for |
| * the current contributor id or an empty array if none is found. |
| */ |
| protected ISectionDescriptor[] readSectionDescriptors() { |
| List result = new ArrayList(); |
| IConfigurationElement[] extensions = getConfigurationElements(EXTPT_SECTIONS); |
| for (int i = 0; i < extensions.length; i++) { |
| IConfigurationElement extension = extensions[i]; |
| IConfigurationElement[] sections = extension |
| .getChildren(ELEMENT_SECTION); |
| for (int j = 0; j < sections.length; j++) { |
| IConfigurationElement section = sections[j]; |
| ISectionDescriptor descriptor = new SectionDescriptor(section, |
| typeMapper); |
| result.add(descriptor); |
| } |
| } |
| return (ISectionDescriptor[]) result |
| .toArray(new ISectionDescriptor[result.size()]); |
| } |
| |
| /** |
| * Returns the configuration elements targeted for the given extension point |
| * and the current contributor id. The elements are also sorted by plugin |
| * prerequisite order. |
| */ |
| protected IConfigurationElement[] getConfigurationElements( |
| String extensionPointId) { |
| if (contributorId == null) { |
| return new IConfigurationElement[0]; |
| } |
| // RAP modified to use 'org.eclipse.ui.views.properties.tabbed' namespace |
| IExtensionPoint point = Platform.getExtensionRegistry() |
| .getExtensionPoint( |
| "org.eclipse.ui.views.properties.tabbed", extensionPointId); //$NON-NLS-1$ |
| IConfigurationElement[] extensions = point.getConfigurationElements(); |
| List unordered = new ArrayList(extensions.length); |
| for (int i = 0; i < extensions.length; i++) { |
| IConfigurationElement extension = extensions[i]; |
| if (!extension.getName().equals(extensionPointId)) { |
| continue; |
| } |
| String contributor = extension.getAttribute(ATT_CONTRIBUTOR_ID); |
| if (!contributorId.equals(contributor)) { |
| continue; |
| } |
| unordered.add(extension); |
| } |
| return (IConfigurationElement[]) unordered |
| .toArray(new IConfigurationElement[unordered.size()]); |
| } |
| |
| /** |
| * Returns the index of the given element in the array. |
| */ |
| private int getIndex(Object[] array, Object target) { |
| for (int i = 0; i < array.length; i++) { |
| if (array[i].equals(target)) { |
| return i; |
| } |
| } |
| return -1; // should never happen |
| } |
| |
| /** |
| * Returns all section descriptors for the provided selection. |
| * |
| * @param part |
| * the workbench part containing the selection |
| * @param selection |
| * the current selection. |
| * @return all section descriptors. |
| */ |
| public ITabDescriptor[] getTabDescriptors(IWorkbenchPart part, |
| ISelection selection) { |
| if (selection == null || selection.isEmpty()) { |
| return EMPTY_DESCRIPTOR_ARRAY; |
| } |
| |
| ITabDescriptor[] allDescriptors = null; |
| if (tabDescriptorProvider == null) { |
| allDescriptors = getAllTabDescriptors(); |
| } else { |
| allDescriptors = tabDescriptorProvider.getTabDescriptors(part, |
| selection); |
| } |
| |
| ITabDescriptor[] result = filterTabDescriptors(allDescriptors, part, |
| selection); |
| return result; |
| } |
| |
| /** |
| * Filters out the tab descriptors that do not have any sections for the |
| * given input. |
| */ |
| protected ITabDescriptor[] filterTabDescriptors( |
| ITabDescriptor[] descriptors, IWorkbenchPart part, |
| ISelection selection) { |
| List result = new ArrayList(); |
| for (int i = 0; i < descriptors.length; i++) { |
| ITabDescriptor descriptor = adaptDescriptorFor(descriptors[i], |
| part, selection); |
| if (!descriptor.getSectionDescriptors().isEmpty()) { |
| result.add(descriptor); |
| } |
| } |
| if (result.size() == 0) { |
| return EMPTY_DESCRIPTOR_ARRAY; |
| } |
| return (ITabDescriptor[]) result.toArray(new ITabDescriptor[result |
| .size()]); |
| } |
| |
| /** |
| * Given a property tab descriptor remove all its section descriptors that |
| * do not apply to the given input object. |
| */ |
| protected ITabDescriptor adaptDescriptorFor(ITabDescriptor target, |
| IWorkbenchPart part, ISelection selection) { |
| List filteredSectionDescriptors = new ArrayList(); |
| List descriptors = target.getSectionDescriptors(); |
| for (Iterator iter = descriptors.iterator(); iter.hasNext();) { |
| ISectionDescriptor descriptor = (ISectionDescriptor) iter.next(); |
| if (descriptor.appliesTo(part, selection)) { |
| filteredSectionDescriptors.add(descriptor); |
| } |
| } |
| AbstractTabDescriptor result = (AbstractTabDescriptor) ((AbstractTabDescriptor) target) |
| .clone(); |
| result.setSectionDescriptors(filteredSectionDescriptors); |
| return result; |
| } |
| |
| /** |
| * Reads property tab extensions. Returns all tab descriptors for the |
| * current contributor id or an empty array if none is found. |
| */ |
| protected ITabDescriptor[] getAllTabDescriptors() { |
| if (tabDescriptors == null) { |
| List temp = readTabDescriptors(); |
| populateWithSectionDescriptors(temp); |
| temp = sortTabDescriptorsByCategory(temp); |
| temp = sortTabDescriptorsByAfterTab(temp); |
| tabDescriptors = (TabDescriptor[]) temp |
| .toArray(new TabDescriptor[temp.size()]); |
| } |
| return tabDescriptors; |
| } |
| |
| /** |
| * Reads property tab extensions. Returns all tab descriptors for the |
| * current contributor id or an empty list if none is found. |
| */ |
| protected List readTabDescriptors() { |
| List result = new ArrayList(); |
| IConfigurationElement[] extensions = getConfigurationElements(EXTPT_TABS); |
| for (int i = 0; i < extensions.length; i++) { |
| IConfigurationElement extension = extensions[i]; |
| IConfigurationElement[] tabs = extension.getChildren(ELEMENT_TAB); |
| for (int j = 0; j < tabs.length; j++) { |
| IConfigurationElement tab = tabs[j]; |
| TabDescriptor descriptor = new TabDescriptor(tab); |
| if (getIndex(propertyCategories.toArray(), descriptor |
| .getCategory()) == -1) { |
| /* tab descriptor has unknown category */ |
| handleTabError(tab, descriptor.getCategory() == null ? "" //$NON-NLS-1$ |
| : descriptor.getCategory()); |
| } else { |
| result.add(descriptor); |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Populates the given tab descriptors with section descriptors. |
| */ |
| protected void populateWithSectionDescriptors(List aTabDescriptors) { |
| ISectionDescriptor[] sections = null; |
| if (sectionDescriptorProvider != null) { |
| sections = sectionDescriptorProvider.getSectionDescriptors(); |
| } else { |
| sections = readSectionDescriptors(); |
| } |
| for (int i = 0; i < sections.length; i++) { |
| ISectionDescriptor section = sections[i]; |
| appendToTabDescriptor(section, aTabDescriptors); |
| } |
| } |
| |
| /** |
| * Appends the given section to a tab from the list. |
| */ |
| protected void appendToTabDescriptor(ISectionDescriptor section, |
| List aTabDescriptors) { |
| for (Iterator i = aTabDescriptors.iterator(); i.hasNext();) { |
| TabDescriptor tab = (TabDescriptor) i.next(); |
| if (tab.append(section)) { |
| return; |
| } |
| } |
| // could not append the section to any of the existing tabs - log error |
| String message = MessageFormat.format(NO_TAB_ERROR, new Object[] { |
| section.getId(), section.getTargetTab() }); |
| IStatus status = new Status(IStatus.ERROR, TabbedPropertyViewPlugin |
| .getPlugin().getBundle().getSymbolicName(), |
| TabbedPropertyViewStatusCodes.NO_TAB_ERROR, message, null); |
| TabbedPropertyViewPlugin.getPlugin().getLog().log(status); |
| } |
| |
| /** |
| * Sorts the tab descriptors in the given list according to category. |
| */ |
| protected List sortTabDescriptorsByCategory(List descriptors) { |
| Collections.sort(descriptors, new Comparator() { |
| |
| public int compare(Object arg0, Object arg1) { |
| TabDescriptor one = (TabDescriptor) arg0; |
| TabDescriptor two = (TabDescriptor) arg1; |
| String categoryOne = one.getCategory(); |
| String categoryTwo = two.getCategory(); |
| int categoryOnePosition = getIndex( |
| propertyCategories.toArray(), categoryOne); |
| int categoryTwoPosition = getIndex( |
| propertyCategories.toArray(), categoryTwo); |
| return categoryOnePosition - categoryTwoPosition; |
| } |
| }); |
| return descriptors; |
| } |
| |
| /** |
| * Sorts the tab descriptors in the given list according to afterTab. |
| */ |
| protected List sortTabDescriptorsByAfterTab(List tabs) { |
| if (tabs.size() == 0 || propertyCategories == null) { |
| return tabs; |
| } |
| List sorted = new ArrayList(); |
| int categoryIndex = 0; |
| for (int i = 0; i < propertyCategories.size(); i++) { |
| List categoryList = new ArrayList(); |
| String category = (String) propertyCategories.get(i); |
| int topOfCategory = categoryIndex; |
| int endOfCategory = categoryIndex; |
| while (endOfCategory < tabs.size() && |
| ((TabDescriptor) tabs.get(endOfCategory)).getCategory() |
| .equals(category)) { |
| endOfCategory++; |
| } |
| for (int j = topOfCategory; j < endOfCategory; j++) { |
| TabDescriptor tab = (TabDescriptor) tabs.get(j); |
| if (tab.getAfterTab().equals(TOP)) { |
| categoryList.add(0, tabs.get(j)); |
| } else { |
| categoryList.add(tabs.get(j)); |
| } |
| } |
| Collections.sort(categoryList, new Comparator() { |
| |
| public int compare(Object arg0, Object arg1) { |
| TabDescriptor one = (TabDescriptor) arg0; |
| TabDescriptor two = (TabDescriptor) arg1; |
| if (two.getAfterTab().equals(one.getId())) { |
| return -1; |
| } else if (one.getAfterTab().equals(two.getId())) { |
| return 1; |
| } else { |
| return 0; |
| } |
| } |
| }); |
| for (int j = 0; j < categoryList.size(); j++) { |
| sorted.add(categoryList.get(j)); |
| } |
| categoryIndex = endOfCategory; |
| } |
| return sorted; |
| } |
| |
| /** |
| * Gets the type mapper for the contributor. |
| * |
| * @return the type mapper for the contributor. |
| */ |
| public ITypeMapper getTypeMapper() { |
| return typeMapper; |
| } |
| |
| /** |
| * Gets the label provider for the contributor. |
| * |
| * @return the label provider for the contributor. |
| */ |
| public ILabelProvider getLabelProvider() { |
| return labelProvider; |
| } |
| |
| /** |
| * Gets the action provider for the contributor. |
| * |
| * @return the action provider for the contributor. |
| */ |
| public IActionProvider getActionProvider() { |
| return actionProvider; |
| } |
| |
| /** |
| * Gets the tab list content provider for the contributor. |
| * |
| * @return the tab list content provider for the contributor. |
| */ |
| public IStructuredContentProvider getTabListContentProvider() { |
| if (overridableTabListContentProvider) { |
| return new OverridableTabListContentProvider(this); |
| } |
| return new TabListContentProvider(this); |
| } |
| |
| /** |
| * Handle the tab error when an issue is found loading from the |
| * configuration element. |
| * |
| * @param configurationElement |
| * the configuration element |
| */ |
| private void handleTabError(IConfigurationElement configurationElement, |
| String category) { |
| String pluginId = configurationElement.getDeclaringExtension() |
| .getNamespaceIdentifier(); |
| String message = MessageFormat.format(TAB_ERROR, new Object[] { |
| pluginId, category }); |
| IStatus status = new Status(IStatus.ERROR, pluginId, |
| TabbedPropertyViewStatusCodes.TAB_ERROR, message, null); |
| TabbedPropertyViewPlugin.getPlugin().getLog().log(status); |
| } |
| |
| /** |
| * Disposes this registry. |
| * |
| * @since 3.7 |
| */ |
| public void dispose() { |
| if (labelProvider != null) { |
| labelProvider.dispose(); |
| labelProvider = null; |
| } |
| |
| if (tabDescriptors != null) { |
| for (int i= 0; i < tabDescriptors.length; i++) { |
| if (tabDescriptors[i] instanceof TabDescriptor) |
| ((TabDescriptor)tabDescriptors[i]).dispose(); |
| } |
| } |
| } |
| } |