diff options
author | Mickael Istria | 2017-02-06 04:34:31 +0000 |
---|---|---|
committer | Mickael Istria | 2017-02-21 15:12:12 +0000 |
commit | 92a0d5c389d95693544840b4f1c25f670ea4b0f7 (patch) | |
tree | aecf04585fbf817d58a3e77b2b9b07824a1d77ee | |
parent | 5c874dc5531058dfb6d99ed1dda438e1fda3563c (diff) | |
download | eclipse.platform.text-92a0d5c389d95693544840b4f1c25f670ea4b0f7.tar.gz eclipse.platform.text-92a0d5c389d95693544840b4f1c25f670ea4b0f7.tar.xz eclipse.platform.text-92a0d5c389d95693544840b4f1c25f670ea4b0f7.zip |
Bug 511101 - Enable quick fix on generic editorI20170221-2000
* Available for Quick-Fix command (Ctrl+1)
* Hover on text editor
Change-Id: I6576f109d6f2a1fdc6020ed6510b645e12dcf3f6
Signed-off-by: Mickael Istria <mistria@redhat.com>
15 files changed, 641 insertions, 27 deletions
diff --git a/org.eclipse.ui.genericeditor.tests/META-INF/MANIFEST.MF b/org.eclipse.ui.genericeditor.tests/META-INF/MANIFEST.MF index d01e76297c8..cf5e719441c 100644 --- a/org.eclipse.ui.genericeditor.tests/META-INF/MANIFEST.MF +++ b/org.eclipse.ui.genericeditor.tests/META-INF/MANIFEST.MF @@ -16,7 +16,9 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.6.0,4.0.0)", org.eclipse.jface.text;bundle-version="3.11.0", org.eclipse.ui;bundle-version="3.108.0", org.eclipse.ui.workbench.texteditor;bundle-version="3.10.0", - org.eclipse.ui.ide;bundle-version="3.11.0" + org.eclipse.ui.ide;bundle-version="3.11.0", + org.eclipse.text.tests;bundle-version="3.11.0", + org.eclipse.ui.tests.harness Bundle-RequiredExecutionEnvironment: JavaSE-1.8 Eclipse-BundleShape: dir Bundle-ActivationPolicy: lazy diff --git a/org.eclipse.ui.genericeditor.tests/plugin.xml b/org.eclipse.ui.genericeditor.tests/plugin.xml index 192e1be825c..c798ba3e3b0 100644 --- a/org.eclipse.ui.genericeditor.tests/plugin.xml +++ b/org.eclipse.ui.genericeditor.tests/plugin.xml @@ -36,5 +36,12 @@ contentType="org.eclipse.core.runtime.text"> </presentationReconciler> </extension> + <extension + point="org.eclipse.ui.ide.markerResolution"> + <markerResolutionGenerator + class="org.eclipse.ui.genericeditor.tests.contributions.MarkerResolutionGenerator" + markerType="org.eclipse.core.resources.problemmarker"> + </markerResolutionGenerator> + </extension> </plugin> diff --git a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/HoverTest.java b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/HoverTest.java index f8fbd32da57..4a6a394b4af 100644 --- a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/HoverTest.java +++ b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/HoverTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2016 Red Hat Inc. and others + * Copyright (c) 2016, 2017 Red Hat Inc. 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 @@ -11,9 +11,11 @@ package org.eclipse.ui.genericeditor.tests; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; -import java.lang.reflect.Field; -import java.lang.reflect.Method; +import java.util.Collections; import org.junit.After; import org.junit.AfterClass; @@ -23,18 +25,28 @@ import org.junit.Test; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Link; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; import org.eclipse.core.resources.IMarker; -import org.eclipse.jface.text.AbstractHoverInformationControlManager; +import org.eclipse.text.tests.Accessor; + +import org.eclipse.jface.text.AbstractInformationControl; import org.eclipse.jface.text.AbstractInformationControlManager; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.TextViewer; import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.genericeditor.tests.contributions.MagicHoverProvider; +import org.eclipse.ui.genericeditor.tests.contributions.MarkerResolutionGenerator; import org.eclipse.ui.part.FileEditorInput; +import org.eclipse.ui.tests.harness.util.DisplayHelper; import org.eclipse.ui.texteditor.AbstractTextEditor; @@ -71,7 +83,8 @@ public class HoverTest { @Test public void testHover() throws Exception { - assertEquals("Alrighty!", getHoverData()); + Shell shell = getHoverShell(triggerCompletionAndRetrieveInformationControlManager()); + assertNotNull(findControl(shell, StyledText.class, MagicHoverProvider.LABEL)); } @Test @@ -85,19 +98,84 @@ public class HoverTest { marker.setAttribute(IMarker.CHAR_START, 0); marker.setAttribute(IMarker.CHAR_END, 5); marker.setAttribute(IMarker.MESSAGE, problemMessage); - assertEquals(problemMessage, getHoverData()); + marker.setAttribute(MarkerResolutionGenerator.FIXME, true); + AbstractInformationControlManager manager = triggerCompletionAndRetrieveInformationControlManager(); + assertEquals(Collections.singletonList(marker), getHoverData(manager)); + // check dialog content + Shell shell= getHoverShell(manager); + assertNotNull(findControl(shell, Label.class, marker.getAttribute(IMarker.MESSAGE, "NONE"))); + Link link = findControl(shell, Link.class, MarkerResolutionGenerator.FIXME); + assertNotNull(link); + Event event = new Event(); + event.widget = link; + event.display = link.getDisplay(); + event.doit = true; + event.type = SWT.Selection; + link.notifyListeners(SWT.Selection, event); + assertFalse(marker.exists()); } finally { - if (marker != null) { + if (marker != null && marker.exists()) { marker.delete(); } } } - private Object getHoverData() throws Exception { + private Shell getHoverShell(AbstractInformationControlManager manager) { + AbstractInformationControl control = null; + do { + DisplayHelper.runEventLoop(this.editor.getSite().getShell().getDisplay(), 100); + control = (AbstractInformationControl)new Accessor(manager, AbstractInformationControlManager.class).get("fInformationControl"); + } while (control == null); + Shell shell = (Shell)new Accessor(control, AbstractInformationControl.class).get("fShell"); + assertTrue(shell.isVisible()); + return shell; + } + + private <T extends Control> T findControl(Control control, Class<T> controlType, String label) { + if (control.getClass() == controlType) { + T res = (T)control; + if (label == null) { + return res; + } + String controlLabel = null; + if (control instanceof Label) { + controlLabel = ((Label)control).getText(); + } else if (control instanceof Link) { + controlLabel = ((Link) control).getText(); + } else if (control instanceof Text) { + controlLabel = ((Text) control).getText(); + } else if (control instanceof StyledText) { + controlLabel = ((StyledText) control).getText(); + } + if (controlLabel != null && controlLabel.contains(label)) { + return res; + } + } else if (control instanceof Composite) { + for (Control child : ((Composite) control).getChildren()) { + T res = findControl(child, controlType, label); + if (res != null) { + return res; + } + } + } + return null; + } + + private Object getHoverData(AbstractInformationControlManager manager) throws Exception { + Object hoverData = new Accessor(manager, AbstractInformationControlManager.class).get("fInformation"); + return hoverData; + } + + private AbstractInformationControlManager triggerCompletionAndRetrieveInformationControlManager() { this.editor.selectAndReveal(2, 0); - GenericEditorTestUtils.waitAndDispatch(1000); + final StyledText editorTextWidget = (StyledText) this.editor.getAdapter(Control.class); + new DisplayHelper() { + @Override + protected boolean condition() { + return editorTextWidget.isFocusControl() && editorTextWidget.getSelection().x == 2; + } + }.waitForCondition(editorTextWidget.getDisplay(), 1000); // sending event to trigger hover computation - StyledText editorTextWidget = (StyledText) this.editor.getAdapter(Control.class); editorTextWidget.getShell().forceActive(); editorTextWidget.getShell().setActive(); editorTextWidget.getShell().setFocus(); @@ -109,21 +187,14 @@ public class HoverTest { hoverEvent.y = editorTextWidget.getClientArea().y + 5; hoverEvent.display = editorTextWidget.getDisplay(); hoverEvent.doit = true; + editorTextWidget.getDisplay().setCursorLocation(editorTextWidget.toDisplay(hoverEvent.x, hoverEvent.y)); editorTextWidget.notifyListeners(SWT.MouseHover, hoverEvent); // Events need to be processed for hover listener to work correctly - GenericEditorTestUtils.waitAndDispatch(1000); + DisplayHelper.runEventLoop(editorTextWidget.getDisplay(), 1000); // retrieving hover content - Method getSourceViewerMethod= AbstractTextEditor.class.getDeclaredMethod("getSourceViewer"); - getSourceViewerMethod.setAccessible(true); - ITextViewer viewer = (ITextViewer) getSourceViewerMethod.invoke(editor); - Field textHoverManagerField= TextViewer.class.getDeclaredField("fTextHoverManager"); - textHoverManagerField.setAccessible(true); - AbstractHoverInformationControlManager hover = (AbstractHoverInformationControlManager) textHoverManagerField.get(viewer); - Field informationField = AbstractInformationControlManager.class.getDeclaredField("fInformation"); - informationField.setAccessible(true); - Object hoverData = informationField.get(hover); - GenericEditorTestUtils.waitAndDispatch(1000); - return hoverData; + ITextViewer viewer = (ITextViewer)new Accessor(editor, AbstractTextEditor.class).invoke("getSourceViewer", new Object[0]); + AbstractInformationControlManager textHoverManager = (AbstractInformationControlManager)new Accessor(viewer, TextViewer.class).get("fTextHoverManager"); + return textHoverManager; } } diff --git a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/MagicHoverProvider.java b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/MagicHoverProvider.java index d8f83117ea0..0bba76cf9d4 100644 --- a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/MagicHoverProvider.java +++ b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/MagicHoverProvider.java @@ -18,6 +18,8 @@ import org.eclipse.jface.text.Region; public class MagicHoverProvider implements ITextHover,ITextHoverExtension2 { + public static final String LABEL= "Alrighty!"; + @Deprecated @Override public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { @@ -31,7 +33,7 @@ public class MagicHoverProvider implements ITextHover,ITextHoverExtension2 { @Override public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) { - return "Alrighty!"; + return LABEL; } } diff --git a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/MarkerResolutionGenerator.java b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/MarkerResolutionGenerator.java new file mode 100644 index 00000000000..ae4c20d1791 --- /dev/null +++ b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/MarkerResolutionGenerator.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2017 Red Hat Inc. 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: + * Mickael Istria (Red Hat Inc.) + *******************************************************************************/ +package org.eclipse.ui.genericeditor.tests.contributions; + +import org.eclipse.swt.graphics.Image; + +import org.eclipse.core.runtime.CoreException; + +import org.eclipse.core.resources.IMarker; + +import org.eclipse.ui.IMarkerResolution; +import org.eclipse.ui.IMarkerResolution2; +import org.eclipse.ui.IMarkerResolutionGenerator; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.ide.IDE; + +public class MarkerResolutionGenerator implements IMarkerResolutionGenerator { + + public static final String FIXME= MarkerResolutionGenerator.class.getName() + ".fixme"; + + private static class MarkerResolution implements IMarkerResolution2 { + @Override + public String getDescription() { + return "resolution.description"; + } + @Override + public Image getImage() { + return PlatformUI.getWorkbench().getSharedImages().getImage(IDE.SharedImages.IMG_OBJ_PROJECT); + } + @Override + public String getLabel() { + return FIXME; + } + + @Override + public void run(IMarker marker) { + try { + marker.delete(); + } catch (CoreException e) { + e.printStackTrace(); + } + } + + } + + @Override + public IMarkerResolution[] getResolutions(IMarker marker) { + if (marker.getAttribute(FIXME, false)) { + return new IMarkerResolution[] { + new MarkerResolution() + }; + } + return new IMarkerResolution[0]; + } + +} diff --git a/org.eclipse.ui.genericeditor/META-INF/MANIFEST.MF b/org.eclipse.ui.genericeditor/META-INF/MANIFEST.MF index 64ae8679ffc..1b3ce360f38 100644 --- a/org.eclipse.ui.genericeditor/META-INF/MANIFEST.MF +++ b/org.eclipse.ui.genericeditor/META-INF/MANIFEST.MF @@ -11,7 +11,9 @@ Require-Bundle: org.eclipse.ui.workbench.texteditor;bundle-version="3.10.0", org.eclipse.jface.text;bundle-version="3.11.0", org.eclipse.core.runtime;bundle-version="3.12.0", org.eclipse.ui.workbench;bundle-version="3.109.0", - org.eclipse.jface;bundle-version="3.13.0" + org.eclipse.jface;bundle-version="3.12.0", + org.eclipse.ui.ide;bundle-version="3.12.0", + org.eclipse.core.resources;bundle-version="3.11.0" Export-Package: org.eclipse.ui.internal.genericeditor;x-internal:=true Bundle-Activator: org.eclipse.ui.internal.genericeditor.GenericEditorPlugin Bundle-Localization: plugin diff --git a/org.eclipse.ui.genericeditor/plugin.xml b/org.eclipse.ui.genericeditor/plugin.xml index 060b9a6d418..06b6de70d1c 100644 --- a/org.eclipse.ui.genericeditor/plugin.xml +++ b/org.eclipse.ui.genericeditor/plugin.xml @@ -74,7 +74,14 @@ <extension point="org.eclipse.ui.genericeditor.hoverProviders"> <hoverProvider + isBefore="*" + class="org.eclipse.ui.internal.genericeditor.markers.MarkerAnnotationHover" + contentType="org.eclipse.core.runtime.text" + id="org.eclipse.ui.genericeditor.markers.annotationsHoverProvider"> + </hoverProvider> + <hoverProvider isBefore="*" + isAfter="org.eclipse.ui.genericeditor.markers.annotationsHoverProvider" class="org.eclipse.ui.internal.genericeditor.AnnotationHoverDelegate" contentType="org.eclipse.core.runtime.text" id="org.eclipse.ui.genericeditor.annotationsHoverProvider"> diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/AnnotationHoverDelegate.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/AnnotationHoverDelegate.java index ba9f0e5f9a6..bcbf86af48a 100644 --- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/AnnotationHoverDelegate.java +++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/AnnotationHoverDelegate.java @@ -18,6 +18,7 @@ import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.ui.editors.text.EditorsUI; import org.eclipse.ui.texteditor.AnnotationPreference; +import org.eclipse.ui.texteditor.MarkerAnnotation; /** * Delegate to {@link DefaultTextHover}, since we need a parameter-less @@ -33,6 +34,10 @@ public class AnnotationHoverDelegate implements ITextHover { this.delegate = new DefaultTextHover(sourceViewer) { @Override protected boolean isIncluded(Annotation annotation) { + if (annotation instanceof MarkerAnnotation) { + // this is handled by MarkerAnnotationHover + return false; + } AnnotationPreference preference= EditorsUI.getAnnotationPreferenceLookup().getAnnotationPreference(annotation); if (preference == null) return false; diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextViewerConfiguration.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextViewerConfiguration.java index 0b5aa832f27..9d96612f26b 100644 --- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextViewerConfiguration.java +++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextViewerConfiguration.java @@ -29,11 +29,14 @@ import org.eclipse.jface.text.DefaultInformationControl; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentPartitioningListener; import org.eclipse.jface.text.IInformationControl; +import org.eclipse.jface.text.IInformationControlCreator; import org.eclipse.jface.text.ITextHover; import org.eclipse.jface.text.contentassist.ContentAssistant; import org.eclipse.jface.text.contentassist.IContentAssistProcessor; import org.eclipse.jface.text.contentassist.IContentAssistant; import org.eclipse.jface.text.presentation.IPresentationReconciler; +import org.eclipse.jface.text.quickassist.IQuickAssistAssistant; +import org.eclipse.jface.text.quickassist.QuickAssistAssistant; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.ui.IEditorPart; @@ -42,6 +45,8 @@ import org.eclipse.ui.IPropertyListener; import org.eclipse.ui.texteditor.ITextEditor; import org.eclipse.ui.editors.text.TextSourceViewerConfiguration; +import org.eclipse.ui.internal.editors.text.EditorsPlugin; +import org.eclipse.ui.internal.genericeditor.markers.MarkerResoltionQuickAssistProcessor; /** * The configuration of the {@link ExtensionBasedTextEditor}. It registers the proxy composite @@ -161,4 +166,17 @@ public final class ExtensionBasedTextViewerConfiguration extends TextSourceViewe } } + @Override + public IQuickAssistAssistant getQuickAssistAssistant(ISourceViewer sourceViewer) { + QuickAssistAssistant quickAssistAssistant = new QuickAssistAssistant(); + quickAssistAssistant.setQuickAssistProcessor(new MarkerResoltionQuickAssistProcessor()); + quickAssistAssistant.setRestoreCompletionProposalSize(EditorsPlugin.getDefault().getDialogSettingsSection("quick_assist_proposal_size")); //$NON-NLS-1$ + quickAssistAssistant.setInformationControlCreator(new IInformationControlCreator() { + @Override + public IInformationControl createInformationControl(Shell parent) { + return new DefaultInformationControl(parent, EditorsPlugin.getAdditionalInfoAffordanceString()); + } + }); + return quickAssistAssistant; + } } diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/OrderedExtensionComparator.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/OrderedExtensionComparator.java index 9d51ef0c0b5..0ae0bbaca75 100644 --- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/OrderedExtensionComparator.java +++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/OrderedExtensionComparator.java @@ -49,7 +49,7 @@ class OrderedExtensionComparator implements Comparator<TextHoverExtension> { if (before0 == null) { return false; } - if ("*".equals(before0)) { //$NON-NLS-1$ + if ("*".equals(before0) && !"*".equals(arg1.getIsBefore())) { //$NON-NLS-1$ //$NON-NLS-2$ return true; } String id1 = arg1.getId(); @@ -71,7 +71,7 @@ class OrderedExtensionComparator implements Comparator<TextHoverExtension> { if (after0 == null) { return false; } - if ("*".equals(after0)) { //$NON-NLS-1$ + if ("*".equals(after0) && !"*".equals(arg1.getIsAfter())) { //$NON-NLS-1$ //$NON-NLS-2$ return true; } String id1 = arg1.getId(); diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/markers/MarkerAnnotationHover.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/markers/MarkerAnnotationHover.java new file mode 100644 index 00000000000..d496ebe5e12 --- /dev/null +++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/markers/MarkerAnnotationHover.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * Copyright (c) 2017 Red Hat Inc. 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: + * Mickael Istria (Red Hat Inc.) - initial implementation + *******************************************************************************/ +package org.eclipse.ui.internal.genericeditor.markers; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.jface.text.IInformationControlCreator; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextHover; +import org.eclipse.jface.text.ITextHoverExtension; +import org.eclipse.jface.text.ITextHoverExtension2; +import org.eclipse.jface.text.ITextViewer; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.Region; +import org.eclipse.jface.text.source.Annotation; +import org.eclipse.jface.text.source.IAnnotationModel; +import org.eclipse.jface.text.source.ISourceViewerExtension2; +import org.eclipse.ui.editors.text.EditorsUI; +import org.eclipse.ui.texteditor.AnnotationPreference; +import org.eclipse.ui.texteditor.MarkerAnnotation; + +public class MarkerAnnotationHover implements ITextHoverExtension, ITextHoverExtension2, ITextHover { + + protected static boolean isIncluded(Annotation annotation) { + if (!(annotation instanceof MarkerAnnotation)) { + return false; + } + AnnotationPreference preference= EditorsUI.getAnnotationPreferenceLookup().getAnnotationPreference(annotation); + if (preference == null) { + return false; + } + String key= preference.getTextPreferenceKey(); + if (key != null) { + if (!EditorsUI.getPreferenceStore().getBoolean(key)) + return false; + } else { + key= preference.getHighlightPreferenceKey(); + if (key == null || !EditorsUI.getPreferenceStore().getBoolean(key)) + return false; + } + return true; + } + + + @Override + public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) { + Object hoverInfo = getHoverInfo2(textViewer, hoverRegion); + if (hoverInfo == null) { + return null; + } + return hoverInfo.toString(); + } + + @Override + public IRegion getHoverRegion(ITextViewer textViewer, int offset) { + if (!(textViewer instanceof ISourceViewerExtension2)) { + return null; + } + ISourceViewerExtension2 viewer = (ISourceViewerExtension2)textViewer; + List<MarkerAnnotation> annotations = findMarkerAnnotations(viewer, new Region(offset, 0)); + if (annotations.isEmpty()) { + return null; + } + // find intersection of regions + int highestOffsetStart = 0; + int lowestOffsetEnd = Integer.MAX_VALUE; + IAnnotationModel annotationModel = viewer.getVisualAnnotationModel(); + for (Annotation annotation : annotations) { + Position position = annotationModel.getPosition(annotation); + highestOffsetStart = Math.max(highestOffsetStart, position.getOffset()); + lowestOffsetEnd = Math.min(lowestOffsetEnd, position.getOffset() + position.getLength()); + } + return new Region(highestOffsetStart, Math.max(0, lowestOffsetEnd - highestOffsetStart)); + } + + @Override + public List<IMarker> getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) { + if (!(textViewer instanceof ISourceViewerExtension2)) { + return null; + } + List<MarkerAnnotation> annotations = findMarkerAnnotations((ISourceViewerExtension2)textViewer, hoverRegion); + if (annotations.isEmpty()) { + return null; + } + List<IMarker> markers = new ArrayList<>(annotations.size()); + for (MarkerAnnotation annotation : annotations) { + markers.add(annotation.getMarker()); + } + return markers; + } + + private static List<MarkerAnnotation> findMarkerAnnotations(ISourceViewerExtension2 viewer, IRegion region) { + List<MarkerAnnotation> res = new ArrayList<>(); + IAnnotationModel annotationModel = viewer.getVisualAnnotationModel(); + annotationModel.getAnnotationIterator().forEachRemaining(annotation -> { + if (isIncluded(annotation)) { + Position position = annotationModel.getPosition(annotation); + if (region.getOffset() >= position.getOffset() && region.getOffset() + region.getLength() <= position.getOffset() + position.getLength()) { + res.add((MarkerAnnotation)annotation); + } + } + }); + return res; + } + + @Override + public IInformationControlCreator getHoverControlCreator() { + return new MarkerHoverControlCreator(); + } + +} diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/markers/MarkerHoverControlCreator.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/markers/MarkerHoverControlCreator.java new file mode 100644 index 00000000000..8d81994f070 --- /dev/null +++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/markers/MarkerHoverControlCreator.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2017 Red Hat Inc. 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: + * Mickael Istria (Red Hat Inc.) - initial implementation + *******************************************************************************/ +package org.eclipse.ui.internal.genericeditor.markers; + +import org.eclipse.jface.text.IInformationControl; +import org.eclipse.jface.text.IInformationControlCreator; +import org.eclipse.jface.text.IInformationControlCreatorExtension; +import org.eclipse.swt.widgets.Shell; + +public class MarkerHoverControlCreator implements IInformationControlCreator, IInformationControlCreatorExtension { + + @Override + public boolean canReuse(IInformationControl control) { + return false; + } + + @Override + public boolean canReplace(IInformationControlCreator creator) { + return false; + } + + @Override + public IInformationControl createInformationControl(Shell parent) { + return new MarkerInformationControl(parent,this); + } + +} diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/markers/MarkerInformationControl.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/markers/MarkerInformationControl.java new file mode 100644 index 00000000000..5a1cd3e0228 --- /dev/null +++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/markers/MarkerInformationControl.java @@ -0,0 +1,155 @@ +/******************************************************************************* + * Copyright (c) 2017 Red Hat Inc. 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: + * Mickael Istria (Red Hat Inc.) - initial implementation + *******************************************************************************/ +package org.eclipse.ui.internal.genericeditor.markers; + +import java.util.List; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.text.AbstractInformationControl; +import org.eclipse.jface.text.AbstractReusableInformationControlCreator; +import org.eclipse.jface.text.IInformationControl; +import org.eclipse.jface.text.IInformationControlCreator; +import org.eclipse.jface.text.IInformationControlExtension; +import org.eclipse.jface.text.IInformationControlExtension2; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Link; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.ui.IMarkerResolution; +import org.eclipse.ui.IMarkerResolution2; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.editors.text.EditorsUI; +import org.eclipse.ui.ide.IDE; +import org.eclipse.ui.ide.IDE.SharedImages; + +public class MarkerInformationControl extends AbstractInformationControl implements IInformationControl, IInformationControlExtension, IInformationControlExtension2 { + + private IInformationControlCreator creator; + + public MarkerInformationControl(Shell parentShell, IInformationControlCreator creator) { + super(parentShell, EditorsUI.getTooltipAffordanceString()); + this.creator = creator; + create(); + } + + private List<IMarker> markers; + private Composite parent; + + @Override + public boolean hasContents() { + return this.markers != null && !this.markers.isEmpty(); + } + + @Override + protected void createContent(Composite parent) { + parent.setLayout(new RowLayout(SWT.VERTICAL)); + parent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); + parent.setBackgroundMode(SWT.INHERIT_DEFAULT); + this.parent = parent; + } + + private static Image getImage(IMarker marker) { + switch (marker.getAttribute(IMarker.SEVERITY, -1)) { + case IMarker.SEVERITY_ERROR: return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_ERROR_TSK); + case IMarker.SEVERITY_WARNING: return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_WARN_TSK); + case IMarker.SEVERITY_INFO: return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_INFO_TSK); + default: + break; + } + return null; + } + + @Override + public void setInput(Object input) { + this.markers = (List<IMarker>)input; + for (IMarker marker : this.markers) { + Composite markerComposite = new Composite(parent, SWT.NONE); + GridLayout gridLayout = new GridLayout(1, false); + gridLayout.verticalSpacing = 0; + markerComposite.setLayout(gridLayout); + Composite markerLine = new Composite(markerComposite, SWT.NONE); + markerLine.setLayout(new RowLayout()); + Label markerImage = new Label(markerLine, SWT.NONE); + markerImage.setImage(getImage(marker)); + Label markerLabel = new Label(markerLine, SWT.NONE); + markerLabel.setText(marker.getAttribute(IMarker.MESSAGE, "missing message")); //$NON-NLS-1$ + for (IMarkerResolution resolution : IDE.getMarkerHelpRegistry().getResolutions(marker)) { + Composite resolutionComposite = new Composite(markerComposite, SWT.NONE); + GridData layoutData = new GridData(); + layoutData.horizontalIndent = 10; + resolutionComposite.setLayoutData(layoutData); + RowLayout rowLayout = new RowLayout(); + rowLayout.marginBottom = 0; + resolutionComposite.setLayout(rowLayout); + Label resolutionImage = new Label(resolutionComposite, SWT.NONE); + // TODO: try to retrieve icon from QuickFix command + Image resolutionPic = null; + if (resolution instanceof IMarkerResolution2) { + resolutionPic = ((IMarkerResolution2) resolution).getImage(); + } + if (resolutionPic == null) { + resolutionPic = PlatformUI.getWorkbench().getSharedImages().getImage(SharedImages.IMG_OPEN_MARKER); + } + resolutionImage.setImage(resolutionPic); + Link resolutionLink = new Link(resolutionComposite, SWT.NONE); + resolutionLink.setText("<A>" + resolution.getLabel() + "</a>"); //$NON-NLS-1$ //$NON-NLS-2$ + resolutionLink.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + Job resolutionJob = new Job("apply resolution - " + resolution.getLabel()) { //$NON-NLS-1$ + @Override + protected IStatus run(IProgressMonitor monitor) { + resolution.run(marker); + return Status.OK_STATUS; + } + }; + resolutionJob.setUser(true); + resolutionJob.setSystem(true); + resolutionJob.setPriority(Job.INTERACTIVE); + resolutionJob.schedule(); + getShell().dispose(); + } + }); + } + } + parent.pack(true); + } + + @Override + public IInformationControlCreator getInformationPresenterControlCreator() { + return new AbstractReusableInformationControlCreator() { + @Override + protected IInformationControl doCreateInformationControl(Shell parent) { + return creator.createInformationControl(parent); + } + }; + } + + @Override + public Point computeSizeHint() { + getShell().pack(); + return getShell().getSize(); + } + +}
\ No newline at end of file diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/markers/MarkerResoltionQuickAssistProcessor.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/markers/MarkerResoltionQuickAssistProcessor.java new file mode 100644 index 00000000000..d3d49dd5586 --- /dev/null +++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/markers/MarkerResoltionQuickAssistProcessor.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2017 Red Hat Inc. 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: + * Mickael Istria (Red Hat Inc.) - initial implementation + *******************************************************************************/ +package org.eclipse.ui.internal.genericeditor.markers; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.jface.text.Position; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.jface.text.quickassist.IQuickAssistInvocationContext; +import org.eclipse.jface.text.quickassist.IQuickAssistProcessor; +import org.eclipse.jface.text.source.Annotation; +import org.eclipse.jface.text.source.IAnnotationModel; +import org.eclipse.ui.IMarkerResolution; +import org.eclipse.ui.ide.IDE; +import org.eclipse.ui.texteditor.MarkerAnnotation; + +public class MarkerResoltionQuickAssistProcessor implements IQuickAssistProcessor { + + @Override + public String getErrorMessage() { + return null; + } + + @Override + public boolean canFix(Annotation annotation) { + return annotation instanceof MarkerAnnotation; + } + + @Override + public boolean canAssist(IQuickAssistInvocationContext invocationContext) { + return false; + } + + @Override + public ICompletionProposal[] computeQuickAssistProposals(IQuickAssistInvocationContext invocationContext) { + IAnnotationModel annotationModel = invocationContext.getSourceViewer().getAnnotationModel(); + Collection<MarkerAnnotation> annotations = new HashSet<>(); + annotationModel.getAnnotationIterator().forEachRemaining(annotation -> { + Position position = annotationModel.getPosition(annotation); + if (invocationContext.getOffset() >= position.getOffset() && + invocationContext.getOffset() + Math.max(0, invocationContext.getLength()) <= position.getOffset() + position.getLength() && + annotation instanceof MarkerAnnotation) { + annotations.add((MarkerAnnotation)annotation); + } + }); + Collection<MarkerResolutionCompletionProposal> resolutions = new ArrayList<>(); + for (MarkerAnnotation annotation : annotations) { + IMarker marker = annotation.getMarker(); + for (IMarkerResolution resolution : IDE.getMarkerHelpRegistry().getResolutions(marker)) { + resolutions.add(new MarkerResolutionCompletionProposal(marker, resolution)); + } + } + return resolutions.toArray(new ICompletionProposal[resolutions.size()]); + } + +} diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/markers/MarkerResolutionCompletionProposal.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/markers/MarkerResolutionCompletionProposal.java new file mode 100644 index 00000000000..bdaa16a3da2 --- /dev/null +++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/markers/MarkerResolutionCompletionProposal.java @@ -0,0 +1,58 @@ +package org.eclipse.ui.internal.genericeditor.markers; + +import org.eclipse.core.resources.IMarker; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.contentassist.ICompletionProposal; +import org.eclipse.jface.text.contentassist.IContextInformation; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.ui.IMarkerResolution; +import org.eclipse.ui.IMarkerResolution2; + +public class MarkerResolutionCompletionProposal implements ICompletionProposal { + + private IMarkerResolution markerResolution; + private IMarker marker; + + public MarkerResolutionCompletionProposal(IMarker marker, IMarkerResolution markerResolution) { + this.marker = marker; + this.markerResolution = markerResolution; + } + + @Override + public void apply(IDocument document) { + this.markerResolution.run(this.marker); + } + + @Override + public Point getSelection(IDocument document) { + return null; + } + + @Override + public String getAdditionalProposalInfo() { + if (this.markerResolution instanceof IMarkerResolution2) { + return ((IMarkerResolution2)this.markerResolution).getDescription(); + } + return null; + } + + @Override + public String getDisplayString() { + return this.markerResolution.getLabel(); + } + + @Override + public Image getImage() { + if (this.markerResolution instanceof IMarkerResolution2) { + return ((IMarkerResolution2)this.markerResolution).getImage(); + } + return null; + } + + @Override + public IContextInformation getContextInformation() { + return null; + } + +} |