/*******************************************************************************
* Copyright (c) 2015 Anton Tanasenko
* 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:
* Anton Tanasenko - Refactor marker resolutions and quick fixes (Bug #484359)
*******************************************************************************/
package org.eclipse.m2e.core.ui.internal.markers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.ICompletionProposalExtension5;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.swt.graphics.Point;
import org.eclipse.ui.IMarkerResolution;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.views.markers.WorkbenchMarkerResolution;
/**
* A single superclass for marker resolutions that can also act as completion proposals in text editor (e.g. shown when
* called on ctrl+1)
*
* @author atanasenko
*/
public abstract class MavenProblemResolution extends WorkbenchMarkerResolution
implements ICompletionProposal, ICompletionProposalExtension5 {
protected final Logger LOG = LoggerFactory.getLogger(this.getClass());
private final IMarker marker;
protected MavenProblemResolution(IMarker marker) {
this.marker = marker;
}
public IMarker getMarker() {
return this.marker;
}
public int getOrder() {
return Integer.MAX_VALUE;
}
/**
* Run this resolution for specified markers
*/
protected abstract void fix(IMarker[] markers, IDocument document, IProgressMonitor monitor);
/**
* Tells whether this resolution should only be present once in a list of resolutions for any number of supported
* markers and will always try to resolve them all
*/
public boolean isSingleton() {
return false;
}
public abstract boolean canFix(IMarker marker) throws CoreException;
public Point getSelection(IDocument document) {
return null;
}
public final String getDisplayString() {
return getLabel();
}
public String getDescription() {
return getLabel();
}
public String getAdditionalProposalInfo() {
Object o = getAdditionalProposalInfo(new NullProgressMonitor());
return o == null ? null : o.toString();
}
public Object getAdditionalProposalInfo(IProgressMonitor monitor) {
return getDescription();
}
public IContextInformation getContextInformation() {
return null;
}
public final void run(IMarker marker) {
run(marker, null);
}
public final void apply(IDocument document) {
run(marker, document);
}
public final void run(IMarker[] markers, IProgressMonitor monitor) {
fix(markers, null, monitor);
}
private void run(IMarker marker, IDocument document) {
IMarker[] handledMarkers;
if(isSingleton()) {
try {
IMarker[] allMarkers = ResourcesPlugin.getWorkspace().getRoot().findMarkers(null, true,
IResource.DEPTH_INFINITE);
handledMarkers = findOtherMarkers(allMarkers, true);
} catch(CoreException e) {
// fall back to running with a single marker
handledMarkers = new IMarker[] {marker};
}
} else {
handledMarkers = new IMarker[] {marker};
}
fix(handledMarkers, document, new NullProgressMonitor());
}
private IMarker[] findOtherMarkers(IMarker[] markers, boolean includeSelf) {
List<IMarker> result = new ArrayList<>();
for(IMarker marker : markers) {
if(marker == this.marker && !includeSelf) {
continue;
}
try {
if(canFix(marker)) {
result.add(marker);
}
} catch(CoreException ex) {
LOG.error(ex.getMessage(), ex);
}
}
return result.toArray(new IMarker[result.size()]);
}
public final IMarker[] findOtherMarkers(IMarker[] markers) {
return findOtherMarkers(markers, false);
}
public boolean includeResolution(List<? super IMarkerResolution> resolutions) {
if(shouldBeAdded(resolutions)) {
resolutions.add(this);
return true;
}
return false;
}
public boolean includeProposal(List<? super ICompletionProposal> proposals) {
if(shouldBeAdded(proposals)) {
proposals.add(this);
return true;
}
return false;
}
private boolean shouldBeAdded(List<?> list) {
if(isSingleton()) {
for(Object o : list) {
if(o.getClass().equals(this.getClass()))
return false;
}
}
return true;
}
protected Set<IProject> getProjects(Stream<IMarker> markers) {
return markers.map(m -> m.getResource().getProject()).collect(Collectors.toSet());
}
public static List<IMarkerResolution> getResolutions(IMarker marker) {
IMarkerResolution[] resolutions = IDE.getMarkerHelpRegistry().getResolutions(marker);
List<IMarkerResolution> sortedResolutions = Arrays.asList(resolutions);
Collections.sort(sortedResolutions,
Comparator.<IMarkerResolution, Integer> comparing(MavenProblemResolution::getOrder)
.thenComparing(IMarkerResolution::getLabel));
return sortedResolutions;
}
public static int getOrder(IMarkerResolution res) {
if(res instanceof MavenProblemResolution) {
MavenProblemResolution mr = (MavenProblemResolution) res;
return mr.getOrder();
}
return Integer.MAX_VALUE;
}
public static boolean hasResolutions(IMarker marker) {
return IDE.getMarkerHelpRegistry().hasResolutions(marker);
}
}