blob: 45f3fa461c17ef327400b21d4e14be2842368c3e [file] [log] [blame]
package org.eclipse.ui.views.markers.internal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
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.core.runtime.dynamichelpers.ExtensionTracker;
import org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler;
import org.eclipse.core.runtime.dynamichelpers.IExtensionTracker;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
/**
* The ProblemFilterRegistryReader is the registry reader for declarative
* problem filters. See the org.eclipse.ui.markerSupport extension point.
*
* @since 3.2
*
*/
public class MarkerSupportRegistry implements IExtensionChangeHandler {
private static final String DESCRIPTION = "onDescription"; //$NON-NLS-1$
private static final String ENABLED = "enabled"; //$NON-NLS-1$
private static final Object ERROR = "ERROR";//$NON-NLS-1$
static final String ID = "id"; //$NON-NLS-1$
private static final Object INFO = "INFO";//$NON-NLS-1$
private static final Object WARNING = "WARNING";//$NON-NLS-1$
private static final String MARKER_ID = "markerId"; //$NON-NLS-1$
/**
* The tag for the marker support extension
*/
public static final String MARKER_SUPPORT = "markerSupport";//$NON-NLS-1$
private static final String NAME = "name"; //$NON-NLS-1$
private static final Object ON_ANY = "ON_ANY"; //$NON-NLS-1$
private static final Object ON_ANY_IN_SAME_CONTAINER = "ON_ANY_IN_SAME_CONTAINER";//$NON-NLS-1$
private static final Object ON_SELECTED_AND_CHILDREN = "ON_SELECTED_AND_CHILDREN";//$NON-NLS-1$
private static final Object ON_SELECTED_ONLY = "ON_SELECTED_ONLY"; //$NON-NLS-1$
private static final Object PROBLEM_FILTER = "problemFilter";//$NON-NLS-1$
private static final String SCOPE = "scope"; //$NON-NLS-1$
private static final String SELECTED_TYPE = "selectedType"; //$NON-NLS-1$
private static final String SEVERITY = "severity";//$NON-NLS-1$
private static final String MARKER_TYPE_REFERENCE = "markerTypeReference"; //$NON-NLS-1$
private static final Object MARKER_CATEGORY = "markerCategory";//$NON-NLS-1$
private static final Object HIERARCHY = "hierarchy";//$NON-NLS-1$
private static final String HIERARCHY_REFERENCE = "hierarchyReference";//$NON-NLS-1$
private static final String TYPE = "type";//$NON-NLS-1$
private static final String PATH = "PATH";//$NON-NLS-1$
private static final String MESSAGE = "MESSAGE";//$NON-NLS-1$
private static final String RESOURCE = "RESOURCE";//$NON-NLS-1$
private static final String SEVERITY_HIERARCHY = "SEVERITY";//$NON-NLS-1$
private static final String DIRECTION = "direction";//$NON-NLS-1$
private static final String ASCENDING = "ASCENDING"; //$NON-NLS-1$
private static final String ATTRIBUTE_MAPPING = "markerAttributeMapping"; //$NON-NLS-1$
private static final Object MARKER_GROUPING = "markerGrouping"; //$NON-NLS-1$
private static final String ATTRIBUTE = "attribute"; //$NON-NLS-1$
private static final String VALUE = "value"; //$NON-NLS-1$
private static MarkerSupportRegistry singleton;
// Create a lock so that initiization happens in one thread
private static Object creationLock = new Object();
/**
* Get the instance of the registry.
*
* @return ProblemFilterRegistry
*/
public static MarkerSupportRegistry getInstance() {
if (singleton == null) {
synchronized (creationLock) {
if (singleton == null)// May have been created by blocking
// thread
singleton = new MarkerSupportRegistry();
}
}
return singleton;
}
private Collection registeredFilters = new ArrayList();
private Collection markerGroups = new ArrayList();
private HashMap categories = new HashMap();
private HashMap hierarchyOrders = new HashMap();
private MarkerType rootType;
/**
* Create a new instance of the receiver and read the registry.
*/
private MarkerSupportRegistry() {
IExtensionTracker tracker = PlatformUI.getWorkbench()
.getExtensionTracker();
IExtensionPoint point = Platform.getExtensionRegistry()
.getExtensionPoint(IDEWorkbenchPlugin.IDE_WORKBENCH,
MARKER_SUPPORT);
if (point == null)
return;
IExtension[] extensions = point.getExtensions();
// initial population
for (int i = 0; i < extensions.length; i++) {
IExtension extension = extensions[i];
processExtension(tracker, extension);
}
tracker.registerHandler(this, ExtensionTracker
.createExtensionPointFilter(point));
}
/**
* Process the extension and register the result with the tracker.
*
* @param tracker
* @param extension
*/
private void processExtension(IExtensionTracker tracker,
IExtension extension) {
IConfigurationElement[] elements = extension.getConfigurationElements();
for (int j = 0; j < elements.length; j++) {
IConfigurationElement element = elements[j];
if (element.getName().equals(PROBLEM_FILTER)) {
ProblemFilter filter = newFilter(element);
registeredFilters.add(filter);
tracker.registerObject(extension, filter,
IExtensionTracker.REF_STRONG);
continue;
}
if (element.getName().equals(MARKER_GROUPING)) {
String[] markerTypes = getMarkerTypes(element);
Map providers = getProviders(element);
String name = element.getAttribute(NAME);
String attribute = element.getAttribute(ATTRIBUTE);
FieldMarkerGroup group = new FieldMarkerGroup(name, attribute, providers,
markerTypes);
markerGroups.add(group);
tracker.registerObject(extension, group,
IExtensionTracker.REF_STRONG);
}
if (element.getName().equals(MARKER_CATEGORY)) {
String[] markerTypes = getMarkerTypes(element);
String categoryName = element.getAttribute(NAME);
for (int i = 0; i < markerTypes.length; i++) {
categories.put(markerTypes[i], categoryName);
}
tracker.registerObject(extension, categoryName,
IExtensionTracker.REF_STRONG);
}
if (element.getName().equals(HIERARCHY)) {
String markerType = getMarkerTypes(element)[0];
IConfigurationElement[] types = element
.getChildren(HIERARCHY_REFERENCE);
IField[] properties = new IField[types.length];
int[] directions = new int[types.length];
for (int i = 0; i < types.length; i++) {
properties[i] = getFieldFor(types[i].getAttribute(TYPE));
String direction = types[i].getAttribute(DIRECTION);
if (direction == ASCENDING)
directions[i] = TableSorter.ASCENDING;
else
directions[i] = TableSorter.DESCENDING;
}
int[] priorities = new int[properties.length];
for (int i = 0; i < priorities.length; i++) {
priorities[i] = i;
}
TableSorter sorter = new TableSorter(properties, priorities,
directions);
hierarchyOrders.put(markerType, sorter);
tracker.registerObject(extension, sorter,
IExtensionTracker.REF_STRONG);
}
}
}
/**
* Return the field that matches attribute
*
* @param attribute
* @return IField or <code>null</code> if there is no matching field.
*/
private IField getFieldFor(String attribute) {
if (attribute.equals(PATH))
return new FieldFolder();
if (attribute.equals(MESSAGE))
return new FieldMessage();
if (attribute.equals(SEVERITY_HIERARCHY))
return new FieldSeverity();
if (attribute.equals(RESOURCE))
return new FieldResource();
return null;
}
/**
* Get the markerTypes defined in element.
*
* @param element
* @return String[]
*/
private String[] getMarkerTypes(IConfigurationElement element) {
IConfigurationElement[] types = element
.getChildren(MARKER_TYPE_REFERENCE);
String[] ids = new String[types.length];
for (int i = 0; i < ids.length; i++) {
ids[i] = types[i].getAttribute(ID);
}
return ids;
}
/**
* Find the attributeMappings from element.
*
* @param element
* @return Map
*/
private Map getProviders(final IConfigurationElement element) {
IConfigurationElement[] mappings = element
.getChildren(ATTRIBUTE_MAPPING);
HashMap valuesToStrings = new HashMap();
for (int i = 0; i < mappings.length; i++) {
valuesToStrings.put(mappings[i].getAttribute(VALUE), mappings[i]
.getAttribute(NAME));
}
return valuesToStrings;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler#addExtension(org.eclipse.core.runtime.dynamichelpers.IExtensionTracker,
* org.eclipse.core.runtime.IExtension)
*/
public void addExtension(IExtensionTracker tracker, IExtension extension) {
processExtension(tracker, extension);
}
/**
* Get the collection of currently registered filters.
*
* @return Collection of ProblemFilter
*/
public Collection getRegisteredFilters() {
Collection filteredFilters = new ArrayList();
Iterator registeredIterator = registeredFilters.iterator();
while (registeredIterator.hasNext()) {
ProblemFilter next = (ProblemFilter) registeredIterator.next();
if (next.isFilteredOutByActivity())
continue;
filteredFilters.add(next);
}
return filteredFilters;
}
/**
* Get the constant for scope from element. Return -1 if there is no value.
*
* @param element
* @return int one of MarkerView#ON_ANY MarkerView#ON_SELECTED_ONLY
* MarkerView#ON_SELECTED_AND_CHILDREN
* MarkerView#ON_ANY_IN_SAME_CONTAINER
*/
private int getScopeValue(IConfigurationElement element) {
String scope = element.getAttribute(SCOPE);
if (scope == null)
return -1;
if (scope.equals(ON_ANY))
return MarkerFilter.ON_ANY;
if (scope.equals(ON_SELECTED_ONLY))
return MarkerFilter.ON_SELECTED_ONLY;
if (scope.equals(ON_SELECTED_AND_CHILDREN))
return MarkerFilter.ON_SELECTED_AND_CHILDREN;
if (scope.equals(ON_ANY_IN_SAME_CONTAINER))
return MarkerFilter.ON_ANY_IN_SAME_CONTAINER;
return -1;
}
/**
* Get the constant for scope from element. Return -1 if there is no value.
*
* @param element
* @return int one of MarkerView#ON_ANY MarkerView#ON_SELECTED_ONLY
* MarkerView#ON_SELECTED_AND_CHILDREN
* MarkerView#ON_ANY_IN_SAME_CONTAINER
*/
private int getSeverityValue(IConfigurationElement element) {
String severity = element.getAttribute(SEVERITY);
if (severity == null)
return -1;
if (severity.equals(INFO))
return ProblemFilter.SEVERITY_INFO;
if (severity.equals(WARNING))
return ProblemFilter.SEVERITY_WARNING;
if (severity.equals(ERROR))
return ProblemFilter.SEVERITY_ERROR;
return -1;
}
/**
* Read the problem filters in the receiver.
*
* @param element
* the filter element
* @return ProblemFilter
*/
private ProblemFilter newFilter(IConfigurationElement element) {
ProblemFilter filter = new ProblemFilter(element.getAttribute(NAME));
filter.createContributionFrom(element);
String enabledValue = element.getAttribute(ENABLED);
filter.setEnabled(enabledValue == null
|| Boolean.valueOf(enabledValue).booleanValue());
int scopeValue = getScopeValue(element);
if (scopeValue >= 0) {
filter.setOnResource(scopeValue);
}
String description = element.getAttribute(DESCRIPTION);
if (description != null) {
boolean contains = true;
if (description.charAt(0) == '!') {// does not contain flag
description = description.substring(1, description.length());
contains = false;
}
filter.setContains(contains);
filter.setDescription(description);
}
int severityValue = getSeverityValue(element);
if (severityValue > 0) {
filter.setSelectBySeverity(true);
filter.setSeverity(severityValue);
} else
filter.setSelectBySeverity(false);
List selectedTypes = new ArrayList();
IConfigurationElement[] types = element.getChildren(SELECTED_TYPE);
for (int j = 0; j < types.length; j++) {
String markerId = types[j].getAttribute(MARKER_ID);
if (markerId != null) {
MarkerType type = filter.getMarkerType(markerId);
if (type == null) {
IStatus status = new Status(IStatus.WARNING,
IDEWorkbenchPlugin.IDE_WORKBENCH, IStatus.WARNING,
MarkerMessages.ProblemFilterRegistry_nullType, null);
IDEWorkbenchPlugin.getDefault().getLog().log(status);
} else
selectedTypes.add(type);
}
}
if (selectedTypes.size() > 0) // Only set the types if there are any
// specified
filter.setSelectedTypes(selectedTypes);
return filter;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler#removeExtension(org.eclipse.core.runtime.IExtension,
* java.lang.Object[])
*/
public void removeExtension(IExtension extension, Object[] objects) {
for (int i = 0; i < objects.length; i++) {
if (objects[i] instanceof ProblemFilter)
registeredFilters.remove(objects[i]);
if (objects[i] instanceof FieldMarkerGroup) {
markerGroups.remove(objects[i]);
}
if (objects[i] instanceof String) {
removeValues(objects[i], categories);
}
if (objects[i] instanceof TableSorter) {
removeValues(objects[i], hierarchyOrders);
}
}
}
/**
* Remove the value from all of the collection sets in cache. If the
* collection is empty remove the key as well.
*
* @param value
* @param cache
*/
private void removeValues(Object value, HashMap cache) {
Collection keysToRemove = new ArrayList();
Iterator keys = cache.keySet().iterator();
while (keys.hasNext()) {
String key = (String) keys.next();
Object next = cache.get(key);
if (next instanceof Collection) {
Collection collection = (Collection) next;
if (collection.contains(value)) {
collection.remove(value);
if (collection.isEmpty())
keysToRemove.add(key);
break;
}
} else {
if (cache.get(key).equals(value))
keysToRemove.add(key);
}
}
Iterator keysToRemoveIterator = keysToRemove.iterator();
while (keysToRemoveIterator.hasNext()) {
cache.remove(keysToRemoveIterator.next());
}
}
/**
* Get the category associated with marker. Return <code>null</code> if
* there are none.
*
* @param marker
* @return String or <code>null</code>
*/
public String getCategory(IMarker marker) {
try {
return getCategory(marker.getType());
} catch (CoreException e) {
Util.log(e);
}
return null;
}
/**
* Get the category associated with markerType. Return <code>null</code>
* if there are none.
*
* @param markerType
* @return String or <code>null</code>
*/
public String getCategory(String markerType) {
if (categories.containsKey(markerType))
return (String) categories.get(markerType);
return null;
}
/**
* Return the TableSorter that corresponds to type.
*
* @param type
* @return TableSorter
*/
public TableSorter getSorterFor(String type) {
if (hierarchyOrders.containsKey(type))
return (TableSorter) hierarchyOrders.get(type);
TableSorter sorter = findSorterInChildren(type, getRootType());
if (sorter == null)
return new TableSorter(new IField[0], new int[0], new int[0]);
return sorter;
}
/**
* Return the list of root marker types.
*
* @return List of MarkerType.
*/
private MarkerType getRootType() {
if (rootType == null) {
rootType = (MarkerTypesModel.getInstance())
.getType(IMarker.PROBLEM);
}
return rootType;
}
/**
* Find the best match sorter for typeName in the children. If it cannot be
* found then return <code>null</code>.
*
* @param typeName
* @param type
* @return TableSorter or <code>null</code>.
*/
private TableSorter findSorterInChildren(String typeName, MarkerType type) {
MarkerType[] types = type.getAllSubTypes();
TableSorter defaultSorter = null;
if (hierarchyOrders.containsKey(type.getId()))
defaultSorter = (TableSorter) hierarchyOrders.get(type.getId());
for (int i = 0; i < types.length; i++) {
MarkerType[] subtypes = types[i].getAllSubTypes();
for (int j = 0; j < subtypes.length; j++) {
TableSorter sorter = findSorterInChildren(typeName, subtypes[j]);
if (sorter != null)
return sorter;
}
}
return defaultSorter;
}
/**
* Return the FieldMarkerGroups in the receiver.
* @return Collection of FieldMarkerGroup
*/
public Collection getMarkerGroups() {
return markerGroups;
}
}