blob: 7ceb6a153349fc52fc8a84c3744d2323a0369e4a [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2008, 2021 IBM Corporation and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0.
#
# SPDX-License-Identifier: EPL-2.0
#
# Contributors:
# IBM Corporation - org.eclipse.jdt: initial API and implementation
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.ltk.ui.sourceediting;
import static org.eclipse.statet.jcommons.lang.ObjectUtils.nonNullAssert;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Position;
import org.eclipse.ui.texteditor.ResourceMarkerAnnotationModel;
import org.eclipse.statet.jcommons.collections.ImList;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.ltk.core.Ltk;
import org.eclipse.statet.ltk.issues.core.Issue;
import org.eclipse.statet.ltk.issues.core.IssueRequestor;
import org.eclipse.statet.ltk.issues.core.IssueTypeSet;
import org.eclipse.statet.ltk.issues.core.IssueTypeSet.ProblemCategory;
import org.eclipse.statet.ltk.issues.core.IssueTypeSet.ProblemTypes;
import org.eclipse.statet.ltk.issues.core.IssueTypeSet.TaskCategory;
import org.eclipse.statet.ltk.issues.core.Problem;
import org.eclipse.statet.ltk.issues.core.impl.BasicIssueRequestor;
import org.eclipse.statet.ltk.ui.sourceediting.SourceProblemAnnotation.PresentationConfig;
/**
* Abstract annotation model dealing with marker annotations and temporary problems.
* Also acts as problem requester for its source unit.
*/
@NonNullByDefault
public abstract class SourceAnnotationModel extends ResourceMarkerAnnotationModel {
protected class SourceAnnotationIssueRequestor extends BasicIssueRequestor {
public SourceAnnotationIssueRequestor(final IssueTypeSet issueTypeSet) {
super(issueTypeSet, Ltk.EDITOR_CONTEXT);
}
@Override
protected boolean shouldAccept(final ProblemCategory category) {
return isHandlingTemporaryProblems(category);
}
@Override
protected boolean shouldAccept(final TaskCategory category) {
return false;
}
@Override
protected void reportIssues(final @Nullable TaskBatch taskBatch,
final ImList<ProblemBatch> problemBatches)
throws CoreException {
SourceAnnotationModel.this.reportIssues(problemBatches);
}
}
private final IssueTypeSet issueTypeSet;
private final AtomicInteger reportingCounter= new AtomicInteger();
private final List<SourceProblemAnnotation> problemAnnotations= new ArrayList<>();
// private ReverseMap reverseMap= new ReverseMap();
// private List previouslyOverlaid= null;
// private List currentlyOverlaid= new ArrayList();
public SourceAnnotationModel(final IResource resource, final IssueTypeSet issueTypeSet) {
super(resource);
this.issueTypeSet= issueTypeSet;
}
protected IssueTypeSet getIssueTypeSet() {
return this.issueTypeSet;
}
protected abstract boolean isHandlingTemporaryProblems(ProblemCategory category);
// @Override
// protected MarkerAnnotation createMarkerAnnotation(IMarker marker) {
// if (JavaMarkerAnnotation.isJavaAnnotation(marker))
// return new JavaMarkerAnnotation(marker);
// return super.createMarkerAnnotation(marker);
// }
// @Override
// protected AnnotationModelEvent createAnnotationModelEvent() {
// return new CompilationUnitAnnotationModelEvent(this, getResource());
// }
public final IssueRequestor createIssueRequestor() {
this.reportingCounter.incrementAndGet();
return doCreateIssueRequestor();
}
protected IssueRequestor doCreateIssueRequestor() {
return new SourceAnnotationIssueRequestor(getIssueTypeSet());
}
public void clearProblems(final @Nullable String category) {
synchronized (getLockObject()) {
if (this.problemAnnotations.size() > 0) {
if (category == null) {
removeAnnotations(this.problemAnnotations, true, true);
this.problemAnnotations.clear();
}
else {
final Iterator<SourceProblemAnnotation> iter= this.problemAnnotations.iterator();
List<SourceProblemAnnotation> toRemove= null;
while (iter.hasNext()) {
final SourceProblemAnnotation annotation= iter.next();
if (annotation.getProblem().getCategoryId() == category) {
iter.remove();
if (toRemove == null) {
toRemove= new ArrayList<>();
}
toRemove.add(annotation);
}
}
if (toRemove != null) {
removeAnnotations(toRemove, true, true);
}
}
}
}
}
private void reportIssues(final ImList<BasicIssueRequestor.ProblemBatch> problemBatches) {
boolean reportedIssuesChanged= false;
synchronized (getLockObject()) {
if (this.reportingCounter.decrementAndGet() != 0) {
return;
}
// this.previouslyOverlaid= this.currentlyOverlaid;
// this.currentlyOverlaid= new ArrayList();
if (this.problemAnnotations.size() > 0) {
reportedIssuesChanged= true;
removeAnnotations(this.problemAnnotations, false, true);
this.problemAnnotations.clear();
}
for (final var problemBatch : problemBatches) {
final ProblemTypes types= nonNullAssert(
problemBatch.getCategory().getTypes(Ltk.EDITOR_CONTEXT) );
for (final Problem problem : problemBatch.getAcceptedIssues()) {
final Position position= createPosition(problem);
if (position != null) {
try {
final var annotation= new SourceProblemAnnotation(
types.getType(problem.getSeverity()), problem,
getPresentationConfig(problem) );
// overlayMarkers(position, annotation);
if (annotation != null) {
addAnnotation(annotation, position, false);
this.problemAnnotations.add(annotation);
reportedIssuesChanged= true;
}
} catch (final BadLocationException x) {
// ignore invalid position
}
}
}
}
// removeMarkerOverlays(isCanceled);
// this.previouslyOverlaid= null;
}
if (reportedIssuesChanged) {
fireModelChanged();
}
}
// private void overlayMarkers(Position position, ProblemAnnotation problemAnnotation) {
// Object value= getAnnotations(position);
// if (value instanceof List) {
// List list= (List) value;
// for (Iterator e= list.iterator(); e.hasNext();)
// setOverlay(e.next(), problemAnnotation);
// } else {
// setOverlay(value, problemAnnotation);
// }
// }
//
// private void setOverlay(Object value, ProblemAnnotation problemAnnotation) {
// if (value instanceof JavaMarkerAnnotation) {
// JavaMarkerAnnotation annotation= (JavaMarkerAnnotation) value;
// if (annotation.isProblem()) {
// annotation.setOverlay(problemAnnotation);
// this.previouslyOverlaid.remove(annotation);
// this.currentlyOverlaid.add(annotation);
// }
// } else {
// }
// }
//
// private void removeMarkerOverlays(boolean isCanceled) {
// if (isCanceled) {
// this.currentlyOverlaid.addAll(this.previouslyOverlaid);
// } else if (this.previouslyOverlaid != null) {
// Iterator e= this.previouslyOverlaid.iterator();
// while (e.hasNext()) {
// JavaMarkerAnnotation annotation= (JavaMarkerAnnotation) e.next();
// annotation.setOverlay(null);
// }
// }
// }
protected Position createPosition(final Issue issue) {
final int start= issue.getSourceStartOffset();
final int end= issue.getSourceEndOffset();
if (start < 0 && end < 0) {
assert (start >= 0 && end >= 0);
}
return new Position(start, end-start);
}
protected PresentationConfig getPresentationConfig(final Problem problem) {
switch (problem.getSeverity()) {
case Problem.SEVERITY_ERROR:
return SourceProblemAnnotation.ERROR_CONFIG;
case Problem.SEVERITY_WARNING:
return SourceProblemAnnotation.WARNING_CONFIG;
default:
return SourceProblemAnnotation.INFO_CONFIG;
}
}
// @Override
// protected void addAnnotation(Annotation annotation, Position position, boolean fireModelChanged) throws BadLocationException {
// super.addAnnotation(annotation, position, fireModelChanged);
//
// synchronized (getLockObject()) {
// Object cached= this.reverseMap.get(position);
// if (cached == null)
// this.reverseMap.put(position, annotation);
// else if (cached instanceof List) {
// List list= (List) cached;
// list.add(annotation);
// } else if (cached instanceof Annotation) {
// List list= new ArrayList(2);
// list.add(cached);
// list.add(annotation);
// this.reverseMap.put(position, list);
// }
// }
// }
//
// @Override
// protected void removeAllAnnotations(boolean fireModelChanged) {
// super.removeAllAnnotations(fireModelChanged);
// synchronized (getLockObject()) {
// this.reverseMap.clear();
// }
// }
//
// @Override
// protected void removeAnnotation(Annotation annotation, boolean fireModelChanged) {
// Position position= getPosition(annotation);
// synchronized (getLockObject()) {
// Object cached= this.reverseMap.get(position);
// if (cached instanceof List) {
// List list= (List) cached;
// list.remove(annotation);
// if (list.size() == 1) {
// this.reverseMap.put(position, list.get(0));
// list.clear();
// }
// } else if (cached instanceof Annotation) {
// this.reverseMap.remove(position);
// }
// }
// super.removeAnnotation(annotation, fireModelChanged);
// }
}