Bug 575504: [SourceEditor] Improve presentation of issues in vertical
ruler
Change-Id: I487f5e745fedc0f6e1688e0bc1e2e57ec1cca1dc
diff --git a/ltk/org.eclipse.statet.ltk.core/plugin.xml b/ltk/org.eclipse.statet.ltk.core/plugin.xml
index 233b520..025df8a 100644
--- a/ltk/org.eclipse.statet.ltk.core/plugin.xml
+++ b/ltk/org.eclipse.statet.ltk.core/plugin.xml
@@ -25,8 +25,24 @@
name="LKT Model Adapters"
schema="schema/ModelAdapters.exsd"/>
- <extension-point id="org.eclipse.statet.ltk.ContentTypeActivation"
+ <extension-point id="org.eclipse.statet.ltk.ContentTypeActivation"
name="Additional activation for content types"
schema="schema/ContentTypeActivation.exsd"/>
+ <extension point="org.eclipse.core.resources.markers"
+ id="org.eclipse.statet.ltk.resourceMarkers.SourceTask">
+ <super type="org.eclipse.core.resources.taskmarker"/>
+ <super type="org.eclipse.core.resources.textmarker"/>
+ <persistent value="true"/>
+ </extension>
+ <extension
+ point="org.eclipse.core.resources.markers"
+ id="org.eclipse.statet.ltk.resourceMarkers.SourceProblem">
+ <super type="org.eclipse.core.resources.problemmarker"/>
+ <super type="org.eclipse.core.resources.textmarker"/>
+ <persistent value="true"/>
+ <attribute name="categoryId"/>
+ <attribute name="code"/>
+ </extension>
+
</plugin>
diff --git a/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/error-away.png b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/error-away.png
new file mode 100644
index 0000000..f4464e1
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/error-away.png
Binary files differ
diff --git a/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/error-away@2x.png b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/error-away@2x.png
new file mode 100644
index 0000000..62f47a7
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/error-away@2x.png
Binary files differ
diff --git a/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/error.png b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/error.png
new file mode 100644
index 0000000..487b5d7
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/error.png
Binary files differ
diff --git a/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/error@2x.png b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/error@2x.png
new file mode 100644
index 0000000..12f6520
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/error@2x.png
Binary files differ
diff --git a/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/info-away.png b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/info-away.png
new file mode 100644
index 0000000..0431f32
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/info-away.png
Binary files differ
diff --git a/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/info-away@2x.png b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/info-away@2x.png
new file mode 100644
index 0000000..b219762
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/info-away@2x.png
Binary files differ
diff --git a/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/info-obj.png b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/info-obj.png
new file mode 100644
index 0000000..7c96dd9
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/info-obj.png
Binary files differ
diff --git a/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/info@2x.png b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/info@2x.png
new file mode 100644
index 0000000..5384d0c
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/info@2x.png
Binary files differ
diff --git a/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/warning-away.png b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/warning-away.png
new file mode 100644
index 0000000..961b3e6
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/warning-away.png
Binary files differ
diff --git a/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/warning-away@2x.png b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/warning-away@2x.png
new file mode 100644
index 0000000..4162496
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/warning-away@2x.png
Binary files differ
diff --git a/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/warning.png b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/warning.png
new file mode 100644
index 0000000..f3129b3
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/warning.png
Binary files differ
diff --git a/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/warning@2x.png b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/warning@2x.png
new file mode 100644
index 0000000..0c46027
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/icons/obj_16/warning@2x.png
Binary files differ
diff --git a/ltk/org.eclipse.statet.ltk.ui/plugin.xml b/ltk/org.eclipse.statet.ltk.ui/plugin.xml
index 5fd6aba..bddfeb0 100644
--- a/ltk/org.eclipse.statet.ltk.ui/plugin.xml
+++ b/ltk/org.eclipse.statet.ltk.ui/plugin.xml
@@ -757,13 +757,26 @@
<extension
point="org.eclipse.ui.editors.annotationTypes">
<type
+ name="org.eclipse.statet.ltk.editorAnnotations.ErrorProblem"
+ super="org.eclipse.ui.workbench.texteditor.error"
+ markerType="org.eclipse.statet.ltk.resourceMarkers.SourceProblem"
+ markerSeverity="2"/>
+ <type
+ name="org.eclipse.statet.ltk.editorAnnotations.WarningProblem"
+ super="org.eclipse.ui.workbench.texteditor.warning"
+ markerType="org.eclipse.statet.ltk.resourceMarkers.SourceProblem"
+ markerSeverity="1"/>
+ <type
+ name="org.eclipse.statet.ltk.editorAnnotations.InfoProblem"
+ super="org.eclipse.ui.workbench.texteditor.info"
+ markerType="org.eclipse.statet.ltk.resourceMarkers.SourceProblem"
+ markerSeverity="0"/>
+ <type
name="org.eclipse.statet.ecommons.text.editorAnnotations.CommonOccurrences"
- super="org.eclipse.jdt.ui.occurrences">
- </type>
+ super="org.eclipse.jdt.ui.occurrences"/>
<type
name="org.eclipse.statet.ecommons.text.editorAnnotations.WriteOccurrences"
- super="org.eclipse.jdt.ui.occurrences.write">
- </type>
+ super="org.eclipse.jdt.ui.occurrences.write"/>
<type
name="org.eclipse.statet.ecommons.text.editorAnnotations.ContentAssistOverwrite">
</type>
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/internal/ltk/ui/LtkUIPlugin.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/internal/ltk/ui/LtkUIPlugin.java
index 9f6ae25..61393a4 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/internal/ltk/ui/LtkUIPlugin.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/internal/ltk/ui/LtkUIPlugin.java
@@ -29,12 +29,15 @@
import org.eclipse.ui.statushandlers.StatusManager;
import org.eclipse.statet.jcommons.lang.Disposable;
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.ecommons.ui.util.ImageRegistryUtil;
import org.eclipse.statet.ltk.ui.LtkUI;
+import org.eclipse.statet.ltk.ui.LtkUIResources;
+@NonNullByDefault
public class LtkUIPlugin extends AbstractUIPlugin {
@@ -136,9 +139,16 @@
}
final ImageRegistryUtil util= new ImageRegistryUtil(this);
- util.register(LtkUI.OBJ_TEXT_TEMPLATE_IMAGE_ID, ImageRegistryUtil.T_OBJ, "text-template.png"); //$NON-NLS-1$
- util.register(LtkUI.OBJ_TEXT_AT_TAG_IMAGE_ID, ImageRegistryUtil.T_OBJ, "text-at_tag.png"); //$NON-NLS-1$
- util.register(LtkUI.OBJ_TEXT_LINKEDRENAME_IMAGE_ID, ImageRegistryUtil.T_OBJ, "linked_rename.png"); //$NON-NLS-1$
+ util.register(LtkUIResources.OBJ_ERROR_IMAGE_ID, ImageRegistryUtil.T_OBJ, "error.png"); //$NON-NLS-1$
+ util.register(LtkUIResources.OBJ_ERROR_AWAY_IMAGE_ID, ImageRegistryUtil.T_OBJ, "error-away.png"); //$NON-NLS-1$
+ util.register(LtkUIResources.OBJ_WARNING_IMAGE_ID, ImageRegistryUtil.T_OBJ, "warning.png"); //$NON-NLS-1$
+ util.register(LtkUIResources.OBJ_WARNING_AWAY_IMAGE_ID, ImageRegistryUtil.T_OBJ, "warning-away.png"); //$NON-NLS-1$
+ util.register(LtkUIResources.OBJ_INFO_IMAGE_ID, ImageRegistryUtil.T_OBJ, "info.png"); //$NON-NLS-1$
+ util.register(LtkUIResources.OBJ_INFO_AWAY_IMAGE_ID, ImageRegistryUtil.T_OBJ, "info-away.png"); //$NON-NLS-1$
+
+ util.register(LtkUIResources.OBJ_TEXT_TEMPLATE_IMAGE_ID, ImageRegistryUtil.T_OBJ, "text-template.png"); //$NON-NLS-1$
+ util.register(LtkUIResources.OBJ_TEXT_AT_TAG_IMAGE_ID, ImageRegistryUtil.T_OBJ, "text-at_tag.png"); //$NON-NLS-1$
+ util.register(LtkUIResources.OBJ_TEXT_LINKEDRENAME_IMAGE_ID, ImageRegistryUtil.T_OBJ, "linked_rename.png"); //$NON-NLS-1$
}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/internal/ltk/ui/sourceediting/AnnotationPresentationConfig.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/internal/ltk/ui/sourceediting/AnnotationPresentationConfig.java
new file mode 100644
index 0000000..5f25dff
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/internal/ltk/ui/sourceediting/AnnotationPresentationConfig.java
@@ -0,0 +1,86 @@
+/*=============================================================================#
+ # Copyright (c) 2021 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.internal.ltk.ui.sourceediting;
+
+import org.eclipse.jface.text.source.IAnnotationAccessExtension;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.editors.text.EditorsUI;
+import org.eclipse.ui.texteditor.AnnotationPreference;
+
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+import org.eclipse.statet.jcommons.lang.Nullable;
+
+import org.eclipse.statet.ltk.ui.LtkUI;
+
+
+@NonNullByDefault
+public class AnnotationPresentationConfig {
+
+ private final int level;
+
+ private final @Nullable String defaultImageId;
+ private @Nullable Image defaultImage;
+
+ private final @Nullable String awayImageId;
+ private @Nullable Image awayImage;
+
+
+ public AnnotationPresentationConfig(final @Nullable String referenceType, final int levelDiff,
+ final @Nullable String defaultImageId, final @Nullable String awayImageId) {
+ final AnnotationPreference preference= EditorsUI.getAnnotationPreferenceLookup().getAnnotationPreference(referenceType);
+
+ if (levelDiff != Integer.MIN_VALUE) {
+ this.level= ((preference != null) ?
+ preference.getPresentationLayer() :
+ IAnnotationAccessExtension.DEFAULT_LAYER ) +
+ levelDiff;
+ }
+ else {
+ this.level= 0;
+ }
+
+ this.defaultImageId= defaultImageId;
+ this.awayImageId= awayImageId;
+ }
+
+ public final int getLevel() {
+ return this.level;
+ }
+
+ public final @Nullable Image getImage() {
+ Image image= this.defaultImage;
+ if (image == null) {
+ final String imageId= this.defaultImageId;
+ if (imageId != null) {
+ image= LtkUI.getUIResources().getImage(imageId);
+ this.defaultImage= image;
+ }
+ }
+ return image;
+ }
+
+ public final @Nullable Image getAwayImage() {
+ Image image= this.awayImage;
+ if (image == null) {
+ final String imageId= this.awayImageId;
+ if (imageId != null) {
+ image= LtkUI.getUIResources().getImage(imageId);
+ this.awayImage= image;
+ }
+ }
+ return image;
+ }
+
+}
\ No newline at end of file
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/LtkUI.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/LtkUI.java
index 3b6ab9c..679aaa9 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/LtkUI.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/LtkUI.java
@@ -18,8 +18,6 @@
import org.eclipse.statet.ecommons.ui.util.UIResources;
-import org.eclipse.statet.internal.ltk.ui.LtkUIPlugin;
-
@NonNullByDefault
public class LtkUI {
@@ -28,20 +26,8 @@
public static final String BUNDLE_ID= "org.eclipse.statet.ltk.ui"; //$NON-NLS-1$
- private static final String NS= BUNDLE_ID;
-
- public static final String OBJ_TEXT_TEMPLATE_IMAGE_ID= NS + "/image/obj/text.template"; //$NON-NLS-1$
- public static final String OBJ_TEXT_AT_TAG_IMAGE_ID= NS + "/image/obj/text.at_tag"; //$NON-NLS-1$
-
- public static final String OBJ_TEXT_LINKEDRENAME_IMAGE_ID= NS + "/image/obj/assist.linked_rename"; //$NON-NLS-1$
-
-
- private static class UIInstance {
- private static final UIResources RESOURCES= new UIResources(LtkUIPlugin.getInstance().getImageRegistry());
- }
-
public static UIResources getUIResources() {
- return UIInstance.RESOURCES;
+ return LtkUIResources.INSTANCE;
}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/LtkUIResources.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/LtkUIResources.java
new file mode 100644
index 0000000..d814ee3
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/LtkUIResources.java
@@ -0,0 +1,51 @@
+/*=============================================================================#
+ # Copyright (c) 2009, 2021 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.ltk.ui;
+
+import org.eclipse.statet.jcommons.lang.NonNullByDefault;
+
+import org.eclipse.statet.ecommons.ui.util.UIResources;
+
+import org.eclipse.statet.internal.ltk.ui.LtkUIPlugin;
+
+
+@NonNullByDefault
+public class LtkUIResources extends UIResources {
+
+
+ private static final String NS= LtkUI.BUNDLE_ID;
+
+ public static final String OBJ_ERROR_IMAGE_ID= NS + "/image/obj/Error"; //$NON-NLS-1$
+ public static final String OBJ_ERROR_AWAY_IMAGE_ID= NS + "/image/obj/Error.away"; //$NON-NLS-1$
+ public static final String OBJ_WARNING_IMAGE_ID= NS + "/image/obj/Warning"; //$NON-NLS-1$
+ public static final String OBJ_WARNING_AWAY_IMAGE_ID= NS + "/image/obj/Warning.away"; //$NON-NLS-1$
+ public static final String OBJ_INFO_IMAGE_ID= NS + "/image/obj/Info"; //$NON-NLS-1$
+ public static final String OBJ_INFO_AWAY_IMAGE_ID= NS + "/image/obj/Info.away"; //$NON-NLS-1$
+
+ public static final String OBJ_TEXT_TEMPLATE_IMAGE_ID= NS + "/image/obj/text.template"; //$NON-NLS-1$
+ public static final String OBJ_TEXT_AT_TAG_IMAGE_ID= NS + "/image/obj/text.at_tag"; //$NON-NLS-1$
+
+ public static final String OBJ_TEXT_LINKEDRENAME_IMAGE_ID= NS + "/image/obj/assist.linked_rename"; //$NON-NLS-1$
+
+
+ static final LtkUIResources INSTANCE= new LtkUIResources();
+
+
+ private LtkUIResources() {
+ super(LtkUIPlugin.getInstance().getImageRegistry());
+ }
+
+
+}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceAnnotationModel.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceAnnotationModel.java
index 7ceb6a1..e791b8d 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceAnnotationModel.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceAnnotationModel.java
@@ -19,15 +19,23 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
+import org.eclipse.core.resources.IMarker;
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.jface.text.source.Annotation;
+import org.eclipse.ui.texteditor.MarkerAnnotation;
+import org.eclipse.ui.texteditor.MarkerUtilities;
import org.eclipse.ui.texteditor.ResourceMarkerAnnotationModel;
+import org.eclipse.statet.jcommons.collections.ImCollections;
import org.eclipse.statet.jcommons.collections.ImList;
+import org.eclipse.statet.jcommons.collections.ImSet;
+import org.eclipse.statet.jcommons.lang.NonNull;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
@@ -35,12 +43,11 @@
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.IssueCategory;
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;
/**
@@ -51,6 +58,96 @@
public abstract class SourceAnnotationModel extends ResourceMarkerAnnotationModel {
+ private static class PositionMap<V> implements Iterable<PositionMap.Entry<V>> {
+
+ static class Entry<V> {
+
+ final Position position;
+
+ ImList<V> annotations;
+
+ public Entry(final Position position, final V value) {
+ this.position= position;
+ this.annotations= ImCollections.newList(value);
+ }
+
+ }
+
+
+ private final List<Entry<V>> list= new ArrayList<>();
+ private int anchor= 0;
+
+
+ public PositionMap() {
+ }
+
+
+ private int indexOf(final Position position) {
+ final int length= this.list.size();
+ for (int i= 0; i < length; i++) {
+ final var entry= this.list.get(i);
+ if (entry.position.equals(position)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public @Nullable ImList<V> get(final Position position) {
+ final int length= this.list.size();
+ // behind anchor
+ for (int i= this.anchor; i < length; i++) {
+ final var entry= this.list.get(i);
+ if (entry.position.equals(position)) {
+ this.anchor= i;
+ return entry.annotations;
+ }
+ }
+ // before anchor
+ for (int i= 0; i < this.anchor; i++) {
+ final var entry= this.list.get(i);
+ if (entry.position.equals(position)) {
+ this.anchor= i;
+ return entry.annotations;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Iterator<Entry<V>> iterator() {
+ return this.list.iterator();
+ }
+
+ public void add(final Position position, final V value) {
+ final int index= indexOf(position);
+ if (index >= 0) {
+ final var entry= this.list.get(index);
+ entry.annotations= ImCollections.addElement(entry.annotations, value);
+ }
+ else {
+ this.list.add(new Entry<>(position, value));
+ }
+ }
+
+ public void remove(final Position position, final Object value) {
+ final int index= indexOf(position);
+ if (index >= 0) {
+ final var entry= this.list.get(index);
+ entry.annotations= ImCollections.removeElement(entry.annotations, value);
+ if (entry.annotations.isEmpty()) {
+ this.list.remove(index);
+ }
+ }
+ }
+
+ public void clear() {
+ this.list.clear();
+ }
+
+ }
+
+
protected class SourceAnnotationIssueRequestor extends BasicIssueRequestor {
@@ -84,11 +181,12 @@
private final AtomicInteger reportingCounter= new AtomicInteger();
- private final List<SourceProblemAnnotation> problemAnnotations= new ArrayList<>();
+ private final List<SourceIssueEditorAnnotation> editorAnnotations= new ArrayList<>();
-// private ReverseMap reverseMap= new ReverseMap();
-// private List previouslyOverlaid= null;
-// private List currentlyOverlaid= new ArrayList();
+ private final PositionMap<SourceIssueMarkerAnnotation<?>> markerAnnotations= new PositionMap<>();
+
+ private @Nullable ImSet<IssueCategory<?>> reportedConfig;
+ private List<SourceIssueMarkerAnnotation<?>> overlaidMarkerAnnotations= new ArrayList<>();
public SourceAnnotationModel(final IResource resource, final IssueTypeSet issueTypeSet) {
@@ -101,14 +199,26 @@
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);
-// }
+ protected abstract boolean isHandlingTemporaryProblems(ProblemCategory issueCategory);
+
+
+ @Override
+ protected @Nullable MarkerAnnotation createMarkerAnnotation(final IMarker marker) {
+ String markerType= MarkerUtilities.getMarkerType(marker);
+ if (markerType != null) {
+ markerType= markerType.intern();
+ final var issueCategory= this.issueTypeSet.getCategory(Ltk.PERSISTENCE_CONTEXT, markerType);
+ if (issueCategory != null) {
+ final var annotationType= issueCategory.mapType(Ltk.PERSISTENCE_CONTEXT, Ltk.EDITOR_CONTEXT,
+ markerType );
+ if (annotationType != null) {
+ return new SourceIssueMarkerAnnotation<>(issueCategory, annotationType, marker);
+ }
+ }
+ }
+ return super.createMarkerAnnotation(marker);
+ }
// @Override
// protected AnnotationModelEvent createAnnotationModelEvent() {
@@ -124,116 +234,77 @@
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();
+ { final Set<IssueCategory<?>> prevConfig= this.reportedConfig;
+ final @NonNull IssueCategory<?>[] enabledCagetories= new @NonNull IssueCategory[problemBatches.size()];
+ int numEnabled= 0;
+ for (final var problemBatch : problemBatches) {
+ final var issueCategory= problemBatch.getCategory();
+ if (problemBatch.isEnabled()) {
+ enabledCagetories[numEnabled++]= issueCategory;
+ if (prevConfig != null && !prevConfig.contains(issueCategory)) {
+ resetMarkerAnnotationsControl(issueCategory, true);
+ }
+ }
+ else {
+ if (prevConfig != null && prevConfig.contains(issueCategory)) {
+ resetMarkerAnnotationsControl(issueCategory, false);
+ }
+ }
+ }
+ this.reportedConfig= ImCollections.newIdentitySet(enabledCagetories, 0, numEnabled);
+ }
+
+ final var prevControlledAnnotations= this.overlaidMarkerAnnotations;
+ this.overlaidMarkerAnnotations= new ArrayList<>();
+
+ if (this.editorAnnotations.size() > 0) {
+ removeAnnotations(this.editorAnnotations, false, true);
+ this.editorAnnotations.clear();
}
for (final var problemBatch : problemBatches) {
- final ProblemTypes types= nonNullAssert(
+ final var problemTypes= 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) {
+ if (problemBatch.isEnabled()) {
+ for (final Problem problem : problemBatch.getAcceptedIssues()) {
+ final Position position= createPosition(problem);
+ if (position != null) {
+ try {
+ final var annotation= new SourceIssueEditorAnnotation(
+ problemBatch.getCategory(),
+ problemTypes.getType(problem.getSeverity()),
+ problem );
+ installMarkerAnnotationOverlays(position, annotation);
addAnnotation(annotation, position, false);
- this.problemAnnotations.add(annotation);
- reportedIssuesChanged= true;
+ this.editorAnnotations.add(annotation);
}
- } catch (final BadLocationException x) {
- // ignore invalid position
+ catch (final BadLocationException x) {
+ }
}
}
}
}
-// removeMarkerOverlays(isCanceled);
-// this.previouslyOverlaid= null;
+ if (prevControlledAnnotations != null && !prevControlledAnnotations.isEmpty()) {
+ prevControlledAnnotations.removeAll(this.overlaidMarkerAnnotations);
+ for (final var problemBatch : problemBatches) {
+ if (problemBatch.isEnabled()) {
+ removeMarkerAnnotationOverlays(prevControlledAnnotations,
+ problemBatch.getCategory() );
+ }
+ }
+ }
}
- if (reportedIssuesChanged) {
- fireModelChanged();
- }
+ 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();
@@ -244,62 +315,101 @@
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;
+
+ private void installMarkerAnnotationOverlays(final Position position,
+ final SourceIssueEditorAnnotation problemAnnotation) {
+ final var annotations= this.markerAnnotations.get(position);
+ if (annotations != null) {
+ final var issueCategory= problemAnnotation.getIssueCategory();
+ for (final var markerAnnotation : annotations) {
+ if (markerAnnotation.getIssueCategory() == issueCategory) {
+ markerAnnotation.setOverlay(problemAnnotation);
+ this.overlaidMarkerAnnotations.add(markerAnnotation);
+ }
+ }
}
}
-// @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);
-// }
+ private void removeMarkerAnnotationOverlays(final List<SourceIssueMarkerAnnotation<?>> annotations,
+ final IssueCategory<?> issueCategory) {
+ for (final var markerAnnotation : annotations) {
+ if (markerAnnotation.getIssueCategory() == issueCategory) {
+ markerAnnotation.setOverlay(null);
+ }
+ }
+ }
+
+ private void resetMarkerAnnotationsControl(final IssueCategory<?> issueCategory,
+ final boolean isControlled) {
+ final var modelEvent= getAnnotationModelEvent();
+ if (isControlled) {
+ for (final var entry : this.markerAnnotations) {
+ for (final var markerAnnotation : entry.annotations) {
+ if (markerAnnotation.getIssueCategory() == issueCategory
+ && !markerAnnotation.isControlled()) {
+ markerAnnotation.setOverlay(null);
+ modelEvent.annotationChanged(markerAnnotation);
+ }
+ }
+ }
+ }
+ else {
+ for (final var entry : this.markerAnnotations) {
+ for (final var markerAnnotation : entry.annotations) {
+ if (markerAnnotation.getIssueCategory() == issueCategory
+ && markerAnnotation.isControlled()) {
+ markerAnnotation.disableOverlay();
+ modelEvent.annotationChanged(markerAnnotation);
+ }
+ }
+ }
+ }
+ }
+
+
+ @Override
+ protected void addAnnotation(final Annotation annotation, final Position position,
+ final boolean fireModelChanged) throws BadLocationException {
+ if (annotation instanceof SourceIssueMarkerAnnotation) {
+ final var markerAnnotation= (SourceIssueMarkerAnnotation<?>)annotation;
+ synchronized (getLockObject()) {
+ final var config= this.reportedConfig;
+ if (config != null && config.contains(markerAnnotation.getIssueCategory())) {
+ markerAnnotation.setOverlay(null);
+ this.overlaidMarkerAnnotations.add(markerAnnotation); // force check
+ }
+ this.markerAnnotations.add(position, markerAnnotation);
+ }
+ }
+
+ super.addAnnotation(annotation, position, fireModelChanged);
+ }
+
+ @Override
+ protected void removeAnnotation(final Annotation annotation, final boolean fireModelChanged) {
+ if (annotation instanceof SourceIssueMarkerAnnotation) {
+ final var markerAnnotation= (SourceIssueMarkerAnnotation<?>)annotation;
+ final var position= getPosition(markerAnnotation);
+ if (position != null) {
+ synchronized (getLockObject()) {
+ if (markerAnnotation.isControlled()) {
+ markerAnnotation.disableOverlay();
+ }
+ this.markerAnnotations.remove(position, markerAnnotation);
+ }
+ }
+ }
+
+ super.removeAnnotation(annotation, fireModelChanged);
+ }
+
+ @Override
+ protected void removeAllAnnotations(final boolean fireModelChanged) {
+ super.removeAllAnnotations(fireModelChanged);
+
+ synchronized (getLockObject()) {
+ this.markerAnnotations.clear();
+ }
+ }
}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceEditor1.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceEditor1.java
index 03f479e..fce88bc 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceEditor1.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceEditor1.java
@@ -41,6 +41,7 @@
import org.eclipse.jface.text.ITextViewerExtension5;
import org.eclipse.jface.text.link.ILinkedModeListener;
import org.eclipse.jface.text.link.LinkedModeModel;
+import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.IAnnotationModel;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.text.source.IVerticalRuler;
@@ -70,6 +71,7 @@
import org.eclipse.ui.texteditor.ITextEditorActionConstants;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.eclipse.ui.texteditor.IUpdate;
+import org.eclipse.ui.texteditor.MarkerAnnotation;
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
import org.eclipse.ui.texteditor.templates.ITemplatesPage;
import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
@@ -1034,6 +1036,19 @@
return null;
}
+ @Override
+ protected void updateMarkerViews(Annotation annotation) {
+ if (annotation instanceof SourceIssueAnnotation<?>) {
+ for (final var overliad : ((SourceIssueAnnotation<?>)annotation).getOverlaidAnnotations()) {
+ if (overliad instanceof MarkerAnnotation) {
+ annotation= overliad;
+ break;
+ }
+ }
+ }
+ super.updateMarkerViews(annotation);
+ }
+
// inject annotation painter workaround
@Override
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceIssueAnnotation.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceIssueAnnotation.java
new file mode 100644
index 0000000..1f8e6d7
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceIssueAnnotation.java
@@ -0,0 +1,57 @@
+/*=============================================================================#
+ # Copyright (c) 2021 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.ltk.ui.sourceediting;
+
+import org.eclipse.jface.text.source.Annotation;
+
+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.issues.core.Issue;
+import org.eclipse.statet.ltk.issues.core.IssueTypeSet;
+
+
+@NonNullByDefault
+public interface SourceIssueAnnotation<TIssue extends Issue> {
+
+
+ /**
+ * Returns the category of the issue presented by this annotation.
+ *
+ * @return the issue category.
+ */
+ IssueTypeSet.IssueCategory<TIssue> getIssueCategory();
+
+ /**
+ * Returns the annotation type.
+ *
+ * @return the type.
+ */
+ String getType();
+
+ boolean isMarkedDeleted();
+
+
+ /**
+ * Returns the annotation overlaying this annotation.
+ *
+ * @return the overlay annotation if overlaid, otherwise {@code null}.
+ */
+ @Nullable SourceIssueAnnotation<TIssue> getOverlay();
+
+ ImList<Annotation> getOverlaidAnnotations();
+
+}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceIssueEditorAnnotation.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceIssueEditorAnnotation.java
new file mode 100644
index 0000000..8f0e331
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceIssueEditorAnnotation.java
@@ -0,0 +1,172 @@
+/*=============================================================================#
+ # Copyright (c) 2008, 2021 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.ltk.ui.sourceediting;
+
+import org.eclipse.jface.text.quickassist.IQuickFixableAnnotation;
+import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.jface.text.source.IAnnotationPresentation;
+import org.eclipse.jface.text.source.ImageUtilities;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+
+import org.eclipse.statet.jcommons.collections.ImCollections;
+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.internal.ltk.ui.sourceediting.AnnotationPresentationConfig;
+import org.eclipse.statet.ltk.core.Ltk;
+import org.eclipse.statet.ltk.issues.core.IssueTypeSet;
+import org.eclipse.statet.ltk.issues.core.IssueTypeSet.IssueCategory;
+import org.eclipse.statet.ltk.issues.core.IssueTypeSet.ProblemTypes;
+import org.eclipse.statet.ltk.issues.core.Problem;
+import org.eclipse.statet.ltk.ui.LtkUIResources;
+
+
+/**
+ * Annotation representing an {@link Problem}.
+ */
+@NonNullByDefault
+public class SourceIssueEditorAnnotation extends Annotation
+ implements SourceIssueAnnotation<Problem>, IAnnotationPresentation, IQuickFixableAnnotation {
+
+
+ static final AnnotationPresentationConfig ERROR_CONFIG= new AnnotationPresentationConfig(
+ "org.eclipse.ui.workbench.texteditor.error", +1, //$NON-NLS-1$
+ LtkUIResources.OBJ_ERROR_IMAGE_ID, LtkUIResources.OBJ_ERROR_AWAY_IMAGE_ID );
+ static final AnnotationPresentationConfig WARNING_CONFIG= new AnnotationPresentationConfig(
+ "org.eclipse.ui.workbench.texteditor.warning", +1, //$NON-NLS-1$
+ LtkUIResources.OBJ_WARNING_IMAGE_ID, LtkUIResources.OBJ_WARNING_AWAY_IMAGE_ID );
+ static final AnnotationPresentationConfig INFO_CONFIG= new AnnotationPresentationConfig(
+ "org.eclipse.ui.workbench.texteditor.info", +1, //$NON-NLS-1$
+ LtkUIResources.OBJ_INFO_IMAGE_ID, LtkUIResources.OBJ_INFO_AWAY_IMAGE_ID );
+ static final AnnotationPresentationConfig FALLBACK_CONFIG = new AnnotationPresentationConfig(
+ null, Integer.MIN_VALUE,
+ null, null );
+
+ static AnnotationPresentationConfig getProblemPresentationConfig(final int severity) {
+ switch (severity) {
+ case Problem.SEVERITY_ERROR:
+ return ERROR_CONFIG;
+ case Problem.SEVERITY_WARNING:
+ return WARNING_CONFIG;
+ case Problem.SEVERITY_INFO:
+ return INFO_CONFIG;
+ default:
+ return FALLBACK_CONFIG;
+ }
+ }
+
+ static AnnotationPresentationConfig getIssuePresentationConfig(
+ final IssueCategory<?> issueCategory, final String type) {
+ if (issueCategory instanceof IssueTypeSet.ProblemCategory) {
+ final ProblemTypes problemTypes= ((IssueTypeSet.ProblemCategory)issueCategory).getTypes(Ltk.EDITOR_CONTEXT);
+ if (problemTypes != null) {
+ return getProblemPresentationConfig(problemTypes.getSeverity(type));
+ }
+ }
+ return FALLBACK_CONFIG;
+ }
+
+
+ private final IssueTypeSet.IssueCategory<Problem> issueCategory;
+ private final Problem issue;
+
+ private boolean isQuickFixable= false;
+ private boolean isQuickFixableStateSet= false;
+
+ private final AnnotationPresentationConfig presentationConfig;
+
+
+ public SourceIssueEditorAnnotation(final IssueTypeSet.IssueCategory<Problem> issueCategory,
+ final String type, final Problem issue) {
+ super(type, false, null);
+ this.issueCategory= issueCategory;
+ this.issue= issue;
+
+ this.presentationConfig= getProblemPresentationConfig(issue.getSeverity());
+ }
+
+
+ @Override
+ public IssueCategory<Problem> getIssueCategory() {
+ return this.issueCategory;
+ }
+
+ @Override
+ public String getText() {
+ return this.issue.getMessage();
+ }
+
+ public Problem getIssue() {
+ return this.issue;
+ }
+
+
+ @Override
+ public int getLayer() {
+ return this.presentationConfig.getLevel();
+ }
+
+ @Override
+ public void paint(final GC gc, final Canvas canvas, final Rectangle bounds) {
+ final Image image= this.presentationConfig.getImage();
+ if (image != null) {
+ ImageUtilities.drawImage(image, gc, canvas, bounds, SWT.CENTER, SWT.TOP);
+ }
+ }
+
+
+ @Override
+ public void setQuickFixable(final boolean state) {
+ this.isQuickFixable= state;
+ this.isQuickFixableStateSet= true;
+ }
+
+ @Override
+ public boolean isQuickFixableStateSet() {
+ return this.isQuickFixableStateSet;
+ }
+
+ @Override
+ public boolean isQuickFixable() {
+ return this.isQuickFixable;
+ }
+
+
+ private ImList<Annotation> overlaidAnnotations= ImCollections.emptyList();
+
+ @Override
+ public @Nullable SourceIssueAnnotation<Problem> getOverlay() {
+ return null;
+ }
+
+ @Override
+ public ImList<Annotation> getOverlaidAnnotations() {
+ return this.overlaidAnnotations;
+ }
+
+ public void addOverlaidAnnotation(final Annotation annotation) {
+ this.overlaidAnnotations= ImCollections.addElement(this.overlaidAnnotations, annotation);
+ }
+
+ public void removeOverlaidAnnotation(final Annotation annotation) {
+ this.overlaidAnnotations= ImCollections.removeElement(this.overlaidAnnotations, annotation);
+ }
+
+}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceIssueMarkerAnnotation.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceIssueMarkerAnnotation.java
new file mode 100644
index 0000000..f19a12e
--- /dev/null
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceIssueMarkerAnnotation.java
@@ -0,0 +1,140 @@
+/*=============================================================================#
+ # Copyright (c) 2021 Stephan Wahlbrink 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, or the Apache License, Version 2.0
+ # which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ #
+ # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+ #
+ # Contributors:
+ # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
+ #=============================================================================*/
+
+package org.eclipse.statet.ltk.ui.sourceediting;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.jface.text.source.Annotation;
+import org.eclipse.jface.text.source.IAnnotationPresentation;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.Canvas;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.ui.texteditor.MarkerAnnotation;
+
+import org.eclipse.statet.jcommons.collections.ImCollections;
+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.internal.ltk.ui.sourceediting.AnnotationPresentationConfig;
+import org.eclipse.statet.ltk.issues.core.Issue;
+import org.eclipse.statet.ltk.issues.core.IssueTypeSet;
+
+
+@NonNullByDefault
+final class SourceIssueMarkerAnnotation<TIssue extends Issue> extends MarkerAnnotation
+ implements SourceIssueAnnotation<TIssue>, IAnnotationPresentation {
+
+
+ final IssueTypeSet.IssueCategory<TIssue> issueCategory;
+
+ private @Nullable SourceIssueEditorAnnotation overlay;
+
+ private boolean isControlled;
+
+ private final AnnotationPresentationConfig presentationConfig;
+
+
+ public SourceIssueMarkerAnnotation(final IssueTypeSet.IssueCategory<TIssue> issueCategory,
+ final String type, final IMarker marker) {
+ super(type, marker);
+ this.issueCategory= issueCategory;
+
+ this.presentationConfig= SourceIssueEditorAnnotation.getIssuePresentationConfig(
+ issueCategory, type );
+ }
+
+
+ @Override
+ public IssueTypeSet.IssueCategory<TIssue> getIssueCategory() {
+ return this.issueCategory;
+ }
+
+
+ boolean isControlled() {
+ return this.isControlled;
+ }
+
+ @Override
+ public boolean isMarkedDeleted() {
+ return (this.isControlled || super.isMarkedDeleted());
+ }
+
+ @Override
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public @Nullable SourceIssueAnnotation<TIssue> getOverlay() {
+ return (SourceIssueAnnotation)this.overlay;
+ }
+
+ @Override
+ public ImList<Annotation> getOverlaidAnnotations() {
+ return ImCollections.emptyList();
+ }
+
+ void disableOverlay() {
+ this.isControlled= false;
+ final var prev= this.overlay;
+ if (prev != null) {
+ prev.removeOverlaidAnnotation(this);
+ }
+ this.overlay= null;
+ }
+
+ void setOverlay(final @Nullable SourceIssueEditorAnnotation annotation) {
+ this.isControlled= true;
+ final var prev= this.overlay;
+ if (prev != null) {
+ prev.removeOverlaidAnnotation(this);
+ }
+ this.overlay= annotation;
+ if (annotation != null) {
+ annotation.addOverlaidAnnotation(this);
+ }
+ }
+
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public int getLayer() {
+ return super.getLayer();
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public void paint(final GC gc, final Canvas canvas, final Rectangle r) {
+ if (getOverlay() != null) {
+ return;
+ }
+ super.paint(gc, canvas, r);
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ protected @Nullable Image getImage(final Display display) {
+ Image image;
+ if (isMarkedDeleted()) {
+ image= this.presentationConfig.getAwayImage();
+ }
+ else {
+ image= this.presentationConfig.getImage();
+ }
+ if (image != null) {
+ return image;
+ }
+ return super.getImage(display);
+ }
+
+}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceProblemAnnotation.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceProblemAnnotation.java
deleted file mode 100644
index ebe629a..0000000
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/SourceProblemAnnotation.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*=============================================================================#
- # Copyright (c) 2008, 2021 Stephan Wahlbrink 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, or the Apache License, Version 2.0
- # which is available at https://www.apache.org/licenses/LICENSE-2.0.
- #
- # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
- #
- # Contributors:
- # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
- #=============================================================================*/
-
-package org.eclipse.statet.ltk.ui.sourceediting;
-
-import org.eclipse.jface.text.quickassist.IQuickFixableAnnotation;
-import org.eclipse.jface.text.source.Annotation;
-import org.eclipse.jface.text.source.IAnnotationAccessExtension;
-import org.eclipse.jface.text.source.IAnnotationPresentation;
-import org.eclipse.jface.text.source.ImageUtilities;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.GC;
-import org.eclipse.swt.graphics.Image;
-import org.eclipse.swt.graphics.Rectangle;
-import org.eclipse.swt.widgets.Canvas;
-import org.eclipse.ui.PlatformUI;
-import org.eclipse.ui.editors.text.EditorsUI;
-import org.eclipse.ui.texteditor.AnnotationPreference;
-import org.eclipse.ui.texteditor.DefaultMarkerAnnotationAccess;
-
-import org.eclipse.statet.jcommons.lang.NonNullByDefault;
-import org.eclipse.statet.jcommons.lang.Nullable;
-
-import org.eclipse.statet.ltk.issues.core.Problem;
-
-
-/**
- * Annotation representing an {@link Problem}.
- */
-@NonNullByDefault
-public class SourceProblemAnnotation extends Annotation
- implements IAnnotationPresentation, IQuickFixableAnnotation {
-
- public static final String TASK_ANNOTATION_TYPE= "org.eclipse.ui.workbench.texteditor.task"; //$NON-NLS-1$
- public static final String SPELLING_ANNOTATION_TYPE= "org.eclipse.ui.workbench.texteditor.spelling"; //$NON-NLS-1$
-
-
- public static class PresentationConfig {
-
- private final int level;
-
- private @Nullable String imageKey;
- private @Nullable Image image;
-
-
- private PresentationConfig(final String referenceType, final int levelDiff) {
- final AnnotationPreference preference= EditorsUI.getAnnotationPreferenceLookup().getAnnotationPreference(referenceType);
-
- if (levelDiff != Integer.MIN_VALUE) {
- this.level= ((preference != null) ?
- preference.getPresentationLayer() :
- IAnnotationAccessExtension.DEFAULT_LAYER ) +
- levelDiff;
- }
- else {
- this.level= 0;
- }
-
- if (preference != null) {
- final String symbolicImageName= preference.getSymbolicImageName();
- if (symbolicImageName != null) {
- this.imageKey= DefaultMarkerAnnotationAccess.getSharedImageName(preference.getSymbolicImageName());
- }
- }
- }
-
- public final int getLevel() {
- return this.level;
- }
-
- public final @Nullable Image getImage() {
- Image image= this.image;
- final String key;
- if (image == null && (key= this.imageKey) != null) {
- image= PlatformUI.getWorkbench().getSharedImages().getImage(key);
- this.image= image;
- }
- return image;
- }
-
- }
-
-
- public static final PresentationConfig ERROR_CONFIG= new PresentationConfig("org.eclipse.ui.workbench.texteditor.error", +1); //$NON-NLS-1$
- public static final PresentationConfig WARNING_CONFIG= new PresentationConfig("org.eclipse.ui.workbench.texteditor.warning", +1); //$NON-NLS-1$
- public static final PresentationConfig INFO_CONFIG= new PresentationConfig("org.eclipse.ui.workbench.texteditor.info", +1); //$NON-NLS-1$
-
-
- private final Problem problem;
-
- private boolean isQuickFixable= false;
- private boolean isQuickFixableStateSet= false;
-
- private final PresentationConfig config;
-
-
- public SourceProblemAnnotation(final String type, final Problem problem, final PresentationConfig config) {
- super(type, false, null);
- this.problem= problem;
- this.config= config;
- }
-
-
- @Override
- public String getText() {
- return this.problem.getMessage();
- }
-
- public Problem getProblem() {
- return this.problem;
- }
-
-
- @Override
- public int getLayer() {
- return this.config.getLevel();
- }
-
- @Override
- public void paint(final GC gc, final Canvas canvas, final Rectangle bounds) {
- final Image image= this.config.getImage();
- if (image != null) {
- ImageUtilities.drawImage(image, gc, canvas, bounds, SWT.CENTER, SWT.TOP);
- }
- }
-
-
- @Override
- public void setQuickFixable(final boolean state) {
- this.isQuickFixable= state;
- this.isQuickFixableStateSet= true;
- }
-
- @Override
- public boolean isQuickFixableStateSet() {
- return this.isQuickFixableStateSet;
- }
-
- @Override
- public boolean isQuickFixable() {
- return this.isQuickFixable;
- }
-
-}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/LinkedNamesAssistProposal.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/LinkedNamesAssistProposal.java
index 0909a87..eb6faba 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/LinkedNamesAssistProposal.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/LinkedNamesAssistProposal.java
@@ -41,6 +41,7 @@
import org.eclipse.statet.jcommons.text.core.TextRegion;
import org.eclipse.statet.ltk.ui.LtkUI;
+import org.eclipse.statet.ltk.ui.LtkUIResources;
import org.eclipse.statet.ltk.ui.sourceediting.SourceEditor;
import org.eclipse.statet.ltk.ui.sourceediting.TextEditToolSynchronizer;
@@ -100,7 +101,7 @@
@Override
public Image getImage() {
- return LtkUI.getUIResources().getImage(LtkUI.OBJ_TEXT_LINKEDRENAME_IMAGE_ID);
+ return LtkUI.getUIResources().getImage(LtkUIResources.OBJ_TEXT_LINKEDRENAME_IMAGE_ID);
}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/TemplateCompletionComputer.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/TemplateCompletionComputer.java
index 43c8c42..dd71a63 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/TemplateCompletionComputer.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/TemplateCompletionComputer.java
@@ -40,8 +40,8 @@
import org.eclipse.statet.jcommons.text.core.SearchPattern;
import org.eclipse.statet.jcommons.text.core.TextRegion;
-import org.eclipse.statet.internal.ltk.ui.LtkUIPlugin;
import org.eclipse.statet.ltk.ui.LtkUI;
+import org.eclipse.statet.ltk.ui.LtkUIResources;
import org.eclipse.statet.ltk.ui.sourceediting.SourceEditor;
import org.eclipse.statet.ltk.ui.sourceediting.assist.SourceProposal.ProposalParameters;
import org.eclipse.statet.ltk.ui.sourceediting.assist.TemplateProposal.TemplateProposalParameters;
@@ -288,7 +288,7 @@
}
protected @Nullable Image getImage(final Template template) {
- return LtkUIPlugin.getInstance().getImageRegistry().get(LtkUI.OBJ_TEXT_TEMPLATE_IMAGE_ID);
+ return LtkUI.getUIResources().getImage(LtkUIResources.OBJ_TEXT_TEMPLATE_IMAGE_ID);
}
}
diff --git a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/TemplateProposal.java b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/TemplateProposal.java
index c512933..5aec5d3 100644
--- a/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/TemplateProposal.java
+++ b/ltk/org.eclipse.statet.ltk.ui/src/org/eclipse/statet/ltk/ui/sourceediting/assist/TemplateProposal.java
@@ -59,8 +59,8 @@
import org.eclipse.statet.ecommons.text.ui.DefaultBrowserInformationInput;
import org.eclipse.statet.ecommons.text.ui.PositionBasedCompletionProposal;
-import org.eclipse.statet.internal.ltk.ui.LtkUIPlugin;
import org.eclipse.statet.ltk.ui.LtkUI;
+import org.eclipse.statet.ltk.ui.LtkUIResources;
import org.eclipse.statet.ltk.ui.sourceediting.TextEditToolSynchronizer;
import org.eclipse.statet.ltk.ui.templates.IWorkbenchTemplateContext;
import org.eclipse.statet.ltk.ui.util.LTKSelectionUtils;
@@ -155,7 +155,7 @@
public TemplateProposal(final TemplateProposalParameters<?> parameters) {
this(parameters,
- LtkUIPlugin.getInstance().getImageRegistry().get(LtkUI.OBJ_TEXT_TEMPLATE_IMAGE_ID) );
+ LtkUI.getUIResources().getImage(LtkUIResources.OBJ_TEXT_TEMPLATE_IMAGE_ID) );
}