/******************************************************************************* * Copyright (c) 2000, 2015 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.ide.registry; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; 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.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.ui.IMarkerHelpRegistry; import org.eclipse.ui.IMarkerResolution; import org.eclipse.ui.IMarkerResolutionGenerator; import org.eclipse.ui.IMarkerResolutionGenerator2; import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin; import org.eclipse.ui.internal.ide.Policy; import org.eclipse.ui.statushandlers.StatusManager; import org.osgi.framework.Bundle; /** * This class is a registry for marker help contexts and resolutions. */ public class MarkerHelpRegistry implements IMarkerHelpRegistry { /** * Table of queries for marker F1 help. */ private Map helpQueries = new HashMap(); /** * Sorted list of help queries. Used to ensure that the "most specific" * query is tried first */ private List sortedHelpQueries; /** * Table of queries for marker resolutions */ private Map<MarkerQuery, Map> resolutionQueries = new LinkedHashMap<>(); /** * Help context id attribute in configuration element */ private static final String ATT_HELP = "helpContextId"; //$NON-NLS-1$ /** * Resolution class attribute name in configuration element */ private static final String ATT_CLASS = "class"; //$NON-NLS-1$ private class QueryComparator implements Comparator { @Override public boolean equals(Object o) { if (!(o instanceof QueryComparator)) { return false; } return true; } @Override public int compare(Object o1, Object o2) { // more attribues come first MarkerQuery q1 = (MarkerQuery) o1; MarkerQuery q2 = (MarkerQuery) o2; int size1 = q1.getAttributes().length; int size2 = q2.getAttributes().length; if (size1 > size2) { return -1; } if (size1 == size2) { return 0; } return 1; } } @Override public String getHelp(IMarker marker) { if (sortedHelpQueries == null) { Set set = helpQueries.keySet(); sortedHelpQueries = new ArrayList(set.size()); sortedHelpQueries.addAll(set); Collections.sort(sortedHelpQueries, new QueryComparator()); } // Return the first match (we assume there is only one) for (Iterator iter = sortedHelpQueries.iterator(); iter.hasNext();) { MarkerQuery query = (MarkerQuery) iter.next(); MarkerQueryResult result = query.performQuery(marker); if (result != null) { // See if a matching result is registered Map resultsTable = (Map) helpQueries.get(query); if (resultsTable.containsKey(result)) { Iterator elements = ((Collection) resultsTable.get(result)) .iterator(); while (elements.hasNext()) { IConfigurationElement element = (IConfigurationElement) elements .next(); // We have a match so return the help context id return element.getAttribute(ATT_HELP); } } } } return null; } @Override public boolean hasResolutions(IMarker marker) { // Detect a match for (Entry<MarkerQuery, Map> entry : resolutionQueries.entrySet()) { MarkerQuery query = entry.getKey(); MarkerQueryResult result = query.performQuery(marker); if (result != null) { // See if a matching result is registered Map resultsTable = entry.getValue(); if (resultsTable.containsKey(result)) { Iterator elements = ((Collection) resultsTable.get(result)) .iterator(); while (elements.hasNext()) { IConfigurationElement element = (IConfigurationElement) elements .next(); if (hasResolution(marker, element)) return true; } } } } return false; } /** * Return whether or not this configuration element has a resolution for the * marker. * * @param marker * @param element * @return boolean <code>true</code> if there is a resolution. */ private boolean hasResolution(IMarker marker, IConfigurationElement element) { IMarkerResolutionGenerator generator = null; if (Platform.getBundle(element.getNamespace()).getState() == Bundle.ACTIVE) { // The element's plugin is loaded so we instantiate // the resolution try { generator = (IMarkerResolutionGenerator) element .createExecutableExtension(ATT_CLASS); } catch (CoreException e) { Policy.handle(e); } if (generator != null) { if (generator instanceof IMarkerResolutionGenerator2) { if (((IMarkerResolutionGenerator2) generator) .hasResolutions(marker)) { return true; } } else { IMarkerResolution[] resolutions = generator .getResolutions(marker); if (resolutions == null) { StatusManager.getManager().handle( new Status(IStatus.ERROR, IDEWorkbenchPlugin.IDE_WORKBENCH, IStatus.ERROR, "Failure in " + generator.getClass().getName()+ //$NON-NLS-1$ " from plugin " + element.getContributor().getName()+//$NON-NLS-1$ ": getResolutions(IMarker) must not return null",//$NON-NLS-1$ null),StatusManager.LOG); return false; } else if (resolutions.length > 0) { // there is at least one resolution return true; } } } } else { // The element's plugin in not loaded so we assume // the generator will produce resolutions for the marker return true; } return false; } @Override public IMarkerResolution[] getResolutions(IMarker marker) { // Collect all matches ArrayList resolutions = new ArrayList(); for (Object resolutionQueryEntry : resolutionQueries.entrySet()) { Map.Entry entry = (Entry) resolutionQueryEntry; MarkerQuery query = (MarkerQuery) entry.getKey(); MarkerQueryResult result = query.performQuery(marker); if (result != null) { // See if a matching result is registered Map resultsTable = (Map) entry.getValue(); if (resultsTable.containsKey(result)) { Iterator elements = ((Collection) resultsTable.get(result)).iterator(); while (elements.hasNext()) { IConfigurationElement element = (IConfigurationElement) elements.next(); IMarkerResolutionGenerator generator = null; try { generator = (IMarkerResolutionGenerator) element.createExecutableExtension(ATT_CLASS); } catch (CoreException e) { Policy.handle(e); } if (generator != null) { for (IMarkerResolution generatedResolution : generator.getResolutions(marker)) { resolutions.add(generatedResolution); } } } } } } return (IMarkerResolution[]) resolutions.toArray(new IMarkerResolution[resolutions.size()]); } /** * Adds a help query to the registry. * * @param query * a marker query * @param result * a result for the given query * @param element * the configuration element defining the result */ public void addHelpQuery(MarkerQuery query, MarkerQueryResult result, IConfigurationElement element) { addQuery(helpQueries, query, result, element); } /** * Adds a resolution query to the registry. * * @param query * a marker query * @param result * a result for the given query * @param element * the configuration element defining the result */ public void addResolutionQuery(MarkerQuery query, MarkerQueryResult result, IConfigurationElement element) { addQuery(resolutionQueries, query, result, element); } /** * Adds a query to the given table. * * @param table * the table to which the query is added * @param query * a marker query * @param result * a result for the given query * @param element * the configuration element defining the result */ private void addQuery(Map table, MarkerQuery query, MarkerQueryResult result, IConfigurationElement element) { // See if the query is already in the table Map results = (Map) table.get(query); if (results == null) { // Create a new results table results = new HashMap(); // Add the query to the table table.put(query, results); } if (results.containsKey(result)) { Collection currentElements = (Collection) results.get(result); currentElements.add(element); } else { Collection elements = new HashSet(); elements.add(element); // Add the new result results.put(result, elements); } } }