blob: 6eeb707b80b2f5e4fccada3b26b646f33c2489ab [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2010 IBM Corporation, See4sys and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
*
* Contributors:
* IBM Corporation - initial API and implementation
* See4sys - added support for problem markers on model objects (rather than
* only on workspace resources). Unfortunately, there was no other
* choice than copying the whole code from
* org.eclipse.ui.views.markers.internal for that purpose because
* many of the relevant classes, methods, and fields are private or
* package private.
*******************************************************************************/
package org.eclipse.sphinx.emf.validation.ui.views;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
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.osgi.util.NLS;
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 0.7.0
*/
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 String MARKER_CATEGORY = "markerTypeCategory";//$NON-NLS-1$
private static final String ATTRIBUTE_MAPPING = "markerAttributeMapping"; //$NON-NLS-1$
private static final String 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 final String LABEL = "label"; //$NON-NLS-1$
private static final String MARKER_ATTRIBUTE_GROUPING = "markerAttributeGrouping";//$NON-NLS-1$
private static final String DEFAULT_GROUPING_ENTRY = "defaultGroupingEntry";//$NON-NLS-1$
private static final String MARKER_TYPE = "markerType";//$NON-NLS-1$
private static final String PRIORITY = "priority"; //$NON-NLS-1$
private static final String MARKER_GROUPING_ENTRY = "markerGroupingEntry"; //$NON-NLS-1$
private static final Object SEVERITY_ID = "org.eclipse.ui.ide.severity";//$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 MarkerSupportRegistry
*/
public static MarkerSupportRegistry getInstance() {
if (singleton == null) {
synchronized (creationLock) {
if (singleton == null) {
// thread
singleton = new MarkerSupportRegistry();
}
}
}
return singleton;
}
private Collection registeredFilters = new ArrayList();
private Map markerGroups = new HashMap();
private Map markerGroupingEntries = new HashMap();
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
Map groupingEntries = new HashMap();
Set attributeMappings = new HashSet();
for (IExtension extension : extensions) {
processExtension(tracker, extension, groupingEntries, attributeMappings);
}
postProcessExtensions(groupingEntries, attributeMappings);
tracker.registerHandler(this, ExtensionTracker.createExtensionPointFilter(point));
}
/**
* Process the extension and register the result with the tracker. Fill the map of groupingEntries and
* attribueMappings processed for post processing.
*
* @param tracker
* @param extension
* @param groupingEntries
* Mapping of group names to the markerGroupingEntries registered for them
* @param attributeMappings
* the markerAttributeGroupings found
* @see #postProcessExtensions(Map, Collection)
*/
private void processExtension(IExtensionTracker tracker, IExtension extension, Map groupingEntries, Collection attributeMappings) {
IConfigurationElement[] elements = extension.getConfigurationElements();
for (IConfigurationElement element : elements) {
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)) {
FieldMarkerGroup group = new FieldMarkerGroup(element.getAttribute(LABEL), element.getAttribute(ID));
markerGroups.put(group.getId(), group);
tracker.registerObject(extension, group, IExtensionTracker.REF_STRONG);
}
if (element.getName().equals(MARKER_GROUPING_ENTRY)) {
MarkerGroupingEntry entry = new MarkerGroupingEntry(element.getAttribute(LABEL), element.getAttribute(ID), Integer.valueOf(
element.getAttribute(PRIORITY)).intValue());
String groupName = element.getAttribute(MARKER_GROUPING);
Collection entries;
if (groupingEntries.containsKey(groupName)) {
entries = (Collection) groupingEntries.get(groupName);
} else {
entries = new HashSet();
}
entries.add(entry);
groupingEntries.put(groupName, entries);
tracker.registerObject(extension, entry, IExtensionTracker.REF_STRONG);
}
if (element.getName().equals(MARKER_ATTRIBUTE_GROUPING)) {
AttributeMarkerGrouping grouping = new AttributeMarkerGrouping(element.getAttribute(ATTRIBUTE), element.getAttribute(MARKER_TYPE),
element.getAttribute(DEFAULT_GROUPING_ENTRY), element);
attributeMappings.add(grouping);
tracker.registerObject(extension, grouping, IExtensionTracker.REF_STRONG);
}
if (element.getName().equals(MARKER_CATEGORY)) {
String[] markerTypes = getMarkerTypes(element);
String categoryName = element.getAttribute(NAME);
for (String element2 : markerTypes) {
categories.put(element2, categoryName);
}
tracker.registerObject(extension, categoryName, IExtensionTracker.REF_STRONG);
}
}
}
/**
* Process the cross references after all of the extensions have been read.
*
* @param groupingEntries
* @param attributeMappings
* @param groupingEntries
* Mapping of group names to the markerGroupingEntries registered for them
* @param attributeMappings
* the markerAttributeGroupings found
*/
private void postProcessExtensions(Map groupingEntries, Collection attributeMappings) {
processGroupingEntries(groupingEntries);
processAttributeMappings(attributeMappings);
}
/**
* Process the grouping entries into thier required grouping entries.
*
* @param groupingEntries
*/
private void processGroupingEntries(Map groupingEntries) {
Iterator entriesIterator = groupingEntries.keySet().iterator();
while (entriesIterator.hasNext()) {
String nextGroupId = (String) entriesIterator.next();
Iterator nextEntriesIterator = ((Collection) groupingEntries.get(nextGroupId)).iterator();
if (markerGroups.containsKey(nextGroupId)) {
while (nextEntriesIterator.hasNext()) {
MarkerGroupingEntry next = (MarkerGroupingEntry) nextEntriesIterator.next();
markerGroupingEntries.put(next.getId(), next);
next.setGroupingEntry((FieldMarkerGroup) markerGroups.get(nextGroupId));
}
} else {
while (nextEntriesIterator.hasNext()) {
MarkerGroupingEntry next = (MarkerGroupingEntry) nextEntriesIterator.next();
IDEWorkbenchPlugin.log(NLS.bind("markerGroupingEntry {0} defines invalid group {1}",//$NON-NLS-1$
new String[] { next.getId(), nextGroupId }));
}
}
}
}
/**
* Process the attribute mappings into their required grouping entries.
*
* @param attributeMappings
*/
private void processAttributeMappings(Collection attributeMappings) {
Iterator mappingsIterator = attributeMappings.iterator();
while (mappingsIterator.hasNext()) {
AttributeMarkerGrouping next = (AttributeMarkerGrouping) mappingsIterator.next();
String defaultEntryId = next.getDefaultGroupingEntry();
if (defaultEntryId != null) {
if (markerGroupingEntries.containsKey(defaultEntryId)) {
MarkerGroupingEntry entry = (MarkerGroupingEntry) markerGroupingEntries.get(defaultEntryId);
entry.setAsDefault(next.getMarkerType());
} else {
IDEWorkbenchPlugin.log(NLS.bind("Reference to invalid markerGroupingEntry {0}",//$NON-NLS-1$
defaultEntryId));
}
}
IConfigurationElement[] mappings = next.getElement().getChildren(ATTRIBUTE_MAPPING);
for (IConfigurationElement element : mappings) {
String entryId = element.getAttribute(MARKER_GROUPING_ENTRY);
if (markerGroupingEntries.containsKey(entryId)) {
MarkerGroupingEntry entry = (MarkerGroupingEntry) markerGroupingEntries.get(entryId);
entry.mapAttribute(next.getMarkerType(), next.getAttribute(), element.getAttribute(VALUE));
} else {
IDEWorkbenchPlugin.log(NLS.bind("Reference to invaild markerGroupingEntry {0}", //$NON-NLS-1$
defaultEntryId));
}
}
}
}
/**
* 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;
}
/*
* (non-Javadoc)
* @see
* org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler#addExtension(org.eclipse.core.runtime.dynamichelpers
* .IExtensionTracker, org.eclipse.core.runtime.IExtension)
*/
@Override
public void addExtension(IExtensionTracker tracker, IExtension extension) {
Map groupingEntries = new HashMap();
Set attributeMappings = new HashSet();
processExtension(tracker, extension, groupingEntries, attributeMappings);
postProcessExtensions(groupingEntries, attributeMappings);
}
/**
* 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 (IConfigurationElement element2 : types) {
String markerId = element2.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) {
// specified
filter.setSelectedTypes(selectedTypes);
}
return filter;
}
/*
* (non-Javadoc)
* @see
* org.eclipse.core.runtime.dynamichelpers.IExtensionChangeHandler#removeExtension(org.eclipse.core.runtime.IExtension
* , java.lang.Object[])
*/
@Override
public void removeExtension(IExtension extension, Object[] objects) {
Collection removedGroups = new ArrayList();
for (Object element : objects) {
if (element instanceof ProblemFilter) {
registeredFilters.remove(element);
}
if (element instanceof FieldMarkerGroup) {
markerGroups.remove(((FieldMarkerGroup) element).getId());
removedGroups.add(element);
}
if (element instanceof MarkerGroupingEntry) {
MarkerGroupingEntry entry = (MarkerGroupingEntry) element;
entry.getMarkerGroup().remove(entry);
markerGroupingEntries.remove(entry.getId());
}
if (element instanceof String) {
removeValues(element, categories);
}
}
Iterator entriesIterator = markerGroupingEntries.keySet().iterator();
Collection removedKeys = new ArrayList();
while (entriesIterator.hasNext()) {
String entryId = (String) entriesIterator.next();
MarkerGroupingEntry entry = (MarkerGroupingEntry) markerGroupingEntries.get(entryId);
if (removedGroups.contains(entry.getMarkerGroup())) {
removedKeys.add(entryId);
}
}
Iterator removedIterator = removedKeys.iterator();
while (removedIterator.hasNext()) {
markerGroupingEntries.remove(removedIterator.next());
}
}
/**
* 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 TableComparator getSorterFor(String type) {
if (hierarchyOrders.containsKey(type)) {
return (TableComparator) hierarchyOrders.get(type);
}
TableComparator sorter = findSorterInChildren(type, getRootType());
if (sorter == null) {
return new TableComparator(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 TableComparator findSorterInChildren(String typeName, MarkerType type) {
MarkerType[] types = type.getAllSubTypes();
TableComparator defaultSorter = null;
if (hierarchyOrders.containsKey(type.getId())) {
defaultSorter = (TableComparator) hierarchyOrders.get(type.getId());
}
for (MarkerType element : types) {
MarkerType[] subtypes = element.getAllSubTypes();
for (MarkerType element2 : subtypes) {
TableComparator sorter = findSorterInChildren(typeName, element2);
if (sorter != null) {
return sorter;
}
}
}
return defaultSorter;
}
/**
* Return the FieldMarkerGroups in the receiver.
*
* @return Collection of FieldMarkerGroup
*/
public Collection getMarkerGroups() {
return markerGroups.values();
}
/**
* Return the default group.
*
* @return IField
*/
public IField getDefaultGroup() {
return (IField) markerGroups.get(SEVERITY_ID);
}
public void addMarkerGroups(IField group) {
markerGroups.put(group.getDescription(), group);
}
}