Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVictor Rubezhny2021-10-29 21:58:02 +0000
committerMickael Istria2021-11-29 10:28:50 +0000
commit34cc626c0956f31f4ba2821e957dc2645e83df8b (patch)
treefcdc456cc0796470e1778d62b718149e964b2c43
parente0da71e663d6a6df458f2a60d11ef9a31e7027cd (diff)
downloadeclipse.platform.text-34cc626c0956f31f4ba2821e957dc2645e83df8b.tar.gz
eclipse.platform.text-34cc626c0956f31f4ba2821e957dc2645e83df8b.tar.xz
eclipse.platform.text-34cc626c0956f31f4ba2821e957dc2645e83df8b.zip
Bug 546106 - "Show Tooltip description"/F2 seems non functional
Change-Id: I973cd0814440ce0d657f1a0ff80774e5a5c76785 Signed-off-by: Victor Rubezhny <vrubezhny@redhat.com> Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.text/+/187184 Tested-by: Platform Bot <platform-bot@eclipse.org> Reviewed-by: Mickael Istria <mistria@redhat.com>
-rw-r--r--org.eclipse.ui.genericeditor.tests/META-INF/MANIFEST.MF2
-rw-r--r--org.eclipse.ui.genericeditor.tests/pom.xml2
-rw-r--r--org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/GenericEditorTestSuite.java1
-rw-r--r--org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/ShowInformationTest.java170
-rw-r--r--org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextViewerConfiguration.java123
5 files changed, 295 insertions, 3 deletions
diff --git a/org.eclipse.ui.genericeditor.tests/META-INF/MANIFEST.MF b/org.eclipse.ui.genericeditor.tests/META-INF/MANIFEST.MF
index 36d6a46df63..ecdf8d56732 100644
--- a/org.eclipse.ui.genericeditor.tests/META-INF/MANIFEST.MF
+++ b/org.eclipse.ui.genericeditor.tests/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Plugin.name
Bundle-SymbolicName: org.eclipse.ui.genericeditor.tests;singleton:=true
-Bundle-Version: 1.2.0.qualifier
+Bundle-Version: 1.2.100.qualifier
Bundle-Vendor: %Plugin.providerName
Bundle-Localization: plugin
Export-Package: org.eclipse.ui.genericeditor.tests,
diff --git a/org.eclipse.ui.genericeditor.tests/pom.xml b/org.eclipse.ui.genericeditor.tests/pom.xml
index fcff61027bb..735c35c4ccd 100644
--- a/org.eclipse.ui.genericeditor.tests/pom.xml
+++ b/org.eclipse.ui.genericeditor.tests/pom.xml
@@ -19,7 +19,7 @@
</parent>
<groupId>org.eclipse.ui</groupId>
<artifactId>org.eclipse.ui.genericeditor.tests</artifactId>
- <version>1.2.0-SNAPSHOT</version>
+ <version>1.2.100-SNAPSHOT</version>
<packaging>eclipse-test-plugin</packaging>
<properties>
<testSuite>${project.artifactId}</testSuite>
diff --git a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/GenericEditorTestSuite.java b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/GenericEditorTestSuite.java
index b1d9b97cb81..12958417f56 100644
--- a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/GenericEditorTestSuite.java
+++ b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/GenericEditorTestSuite.java
@@ -25,6 +25,7 @@ import org.junit.runners.Suite.SuiteClasses;
ContextInfoTest.class,
StylingTest.class,
HoverTest.class,
+ ShowInformationTest.class,
EditorTest.class,
FoldingTest.class,
AutoEditTest.class,
diff --git a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/ShowInformationTest.java b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/ShowInformationTest.java
new file mode 100644
index 00000000000..4d5da0783d1
--- /dev/null
+++ b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/ShowInformationTest.java
@@ -0,0 +1,170 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Red Hat Inc. and others
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+// *
+ * Contributors:
+ * Red Hat Inc.
+ *******************************************************************************/
+package org.eclipse.ui.genericeditor.tests;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+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.runtime.Platform;
+
+import org.eclipse.text.tests.Accessor;
+
+import org.eclipse.jface.text.AbstractInformationControl;
+import org.eclipse.jface.text.AbstractInformationControlManager;
+import org.eclipse.jface.text.ITextOperationTarget;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.jface.text.source.SourceViewer;
+import org.eclipse.jface.text.tests.util.DisplayHelper;
+
+import org.eclipse.ui.genericeditor.tests.contributions.AlrightyHoverProvider;
+
+import org.eclipse.ui.workbench.texteditor.tests.ScreenshotTest;
+
+import org.eclipse.ui.texteditor.AbstractTextEditor;
+
+/**
+ * @since 1.2
+ */
+public class ShowInformationTest extends AbstratGenericEditorTest {
+
+ @Rule
+ public TestName testName= new TestName();
+
+ @Before
+ public void skipOnNonLinux() {
+ Assume.assumeFalse("This test currently always fail on Windows (bug 505842), skipping", Platform.OS_WIN32.equals(Platform.getOS()));
+ Assume.assumeFalse("This test currently always fail on macOS (bug 505842), skipping", Platform.OS_MACOSX.equals(Platform.getOS()));
+ }
+
+ @Test
+ public void testInformationControl() throws Exception {
+ Shell shell= getHoverShell(triggerCompletionAndRetrieveInformationControlManager(), true);
+ assertNotNull(findControl(shell, StyledText.class, AlrightyHoverProvider.LABEL));
+ }
+
+ private Shell getHoverShell(AbstractInformationControlManager manager, boolean failOnError) {
+ AbstractInformationControl[] control= { null };
+ new DisplayHelper() {
+ @Override
+ protected boolean condition() {
+ control[0]= (AbstractInformationControl) new Accessor(manager, AbstractInformationControlManager.class).get("fInformationControl");
+ return control[0] != null;
+ }
+ }.waitForCondition(this.editor.getSite().getShell().getDisplay(), 5000);
+ if (control[0] == null) {
+ if (failOnError) {
+ ScreenshotTest.takeScreenshot(getClass(), testName.getMethodName(), System.out);
+ fail();
+ } else {
+ return null;
+ }
+ }
+ boolean[] result = {false};
+ Shell shell= (Shell) new Accessor(control[0], AbstractInformationControl.class).get("fShell");
+ new DisplayHelper() {
+ @Override
+ protected boolean condition() {
+ return (result[0] = shell.isVisible());
+ }
+ }.waitForCondition(control[0].getShell().getDisplay(), 2000);
+ if (failOnError) {
+ assertTrue(shell.isVisible());
+ }
+ return shell;
+ }
+
+ private <T extends Control> T findControl(Control control, Class<T> controlType, String label) {
+ if (control.getClass() == controlType) {
+ @SuppressWarnings("unchecked")
+ 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 getShowInformationData(AbstractInformationControlManager manager) {
+ return new Accessor(manager, AbstractInformationControlManager.class).get("fInformation");
+ }
+
+ private AbstractInformationControlManager triggerCompletionAndRetrieveInformationControlManager() {
+ final int caretLocation= 2;
+ this.editor.selectAndReveal(caretLocation, 0);
+ final StyledText editorTextWidget= (StyledText) this.editor.getAdapter(Control.class);
+ new DisplayHelper() {
+ @Override
+ protected boolean condition() {
+ return editorTextWidget.isFocusControl() && editorTextWidget.getSelection().x == caretLocation;
+ }
+ }.waitForCondition(editorTextWidget.getDisplay(), 3000);
+ // sending event to trigger hover computation
+ editorTextWidget.getShell().forceActive();
+ editorTextWidget.getShell().setActive();
+ editorTextWidget.getShell().setFocus();
+ editorTextWidget.getShell().getDisplay().wake();
+
+ ITextViewer viewer= (ITextViewer) new Accessor(editor, AbstractTextEditor.class).invoke("getSourceViewer", new Object[0]);
+
+ ITextOperationTarget textOperationTarget = (ITextOperationTarget)viewer;
+ assertTrue(textOperationTarget.canDoOperation(ISourceViewer.INFORMATION));
+ textOperationTarget.doOperation(ISourceViewer.INFORMATION);
+
+ AbstractInformationControlManager informationControlManager= (AbstractInformationControlManager) new Accessor(viewer, SourceViewer.class).get("fInformationPresenter");
+ // retrieving hover content
+ new DisplayHelper() {
+ @Override
+ protected boolean condition() {
+ return getShowInformationData(informationControlManager) != null;
+ }
+ }.waitForCondition(editorTextWidget.getDisplay(), 6000);
+ return informationControlManager;
+ }
+}
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 3ac10296e24..2c14aa78c01 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2016, 2017 Red Hat Inc. and others.
+ * Copyright (c) 2016, 2021 Red Hat Inc. and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
@@ -20,12 +20,15 @@ package org.eclipse.ui.internal.genericeditor;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Queue;
import java.util.Set;
+import java.util.stream.Collectors;
import org.eclipse.core.filebuffers.FileBuffers;
import org.eclipse.core.filebuffers.ITextFileBuffer;
@@ -37,22 +40,37 @@ import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.jface.text.AbstractReusableInformationControlCreator;
import org.eclipse.jface.text.DefaultInformationControl;
import org.eclipse.jface.text.IAutoEditStrategy;
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.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.Region;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.contentassist.IContentAssistant;
+import org.eclipse.jface.text.information.IInformationPresenter;
+import org.eclipse.jface.text.information.IInformationProvider;
+import org.eclipse.jface.text.information.IInformationProviderExtension;
+import org.eclipse.jface.text.information.IInformationProviderExtension2;
+import org.eclipse.jface.text.information.InformationPresenter;
import org.eclipse.jface.text.presentation.IPresentationReconciler;
import org.eclipse.jface.text.quickassist.IQuickAssistAssistant;
import org.eclipse.jface.text.quickassist.IQuickAssistProcessor;
import org.eclipse.jface.text.quickassist.QuickAssistAssistant;
import org.eclipse.jface.text.reconciler.IReconciler;
import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.editors.text.TextSourceViewerConfiguration;
import org.eclipse.ui.internal.editors.text.EditorsPlugin;
import org.eclipse.ui.internal.genericeditor.folding.DefaultFoldingReconciler;
+import org.eclipse.ui.internal.genericeditor.hover.CompositeInformationControlCreator;
import org.eclipse.ui.internal.genericeditor.hover.CompositeTextHover;
import org.eclipse.ui.internal.genericeditor.markers.MarkerResoltionQuickAssistProcessor;
import org.eclipse.ui.texteditor.ITextEditor;
@@ -271,6 +289,109 @@ public final class ExtensionBasedTextViewerConfiguration extends TextSourceViewe
return targets;
}
+ @Override
+ public IInformationPresenter getInformationPresenter(ISourceViewer sourceViewer) {
+ // Register information provider
+ List<ITextHover> hovers = GenericEditorPlugin.getDefault().getHoverRegistry().getAvailableHovers(sourceViewer,
+ editor, getContentTypes(sourceViewer.getDocument()));
+
+ InformationPresenter presenter = new InformationPresenter(new CompositeInformationControlCreator(hovers));
+ // By default the InformationPresented is set to take the focus when visible,
+ // which makes the Browser to overtake all the focus/mouse etc. control over the
+ // 'org.eclipse.jface.text.information.InformationPresenter.Closer`.
+ // As we want to make t possible to close the information presenter by clicking
+ // outside of the information control or resizing the editor etc. - we need to
+ // disable such focus overtake by calling `takesFocusWhenVisible(false)` on the
+ // presenter.
+ //
+ presenter.takesFocusWhenVisible(false);
+ presenter.setDocumentPartitioning(getConfiguredDocumentPartitioning(sourceViewer));
+
+ IInformationProvider provider = new ExtensionBaseInformationProvider(hovers);
+ // Register information provider
+ if (hovers != null && !hovers.isEmpty()) {
+ for (String contentType : getConfiguredContentTypes(sourceViewer)) {
+ presenter.setInformationProvider(provider, contentType);
+ }
+ }
+
+ // sizes: see org.eclipse.jface.text.TextViewer.TEXT_HOVER_*_CHARS
+ presenter.setSizeConstraints(100, 12, false, true);
+ return presenter;
+ }
+
+ class ExtensionBaseInformationProvider
+ implements IInformationProvider, IInformationProviderExtension, IInformationProviderExtension2 {
+ List<ITextHover> fHovers;
+ private LinkedHashMap<ITextHover, Object> currentHovers;
+
+ ExtensionBaseInformationProvider(List<ITextHover> hovers) {
+ this.fHovers = hovers;
+ }
+
+ @Override
+ public Object getInformation2(ITextViewer textViewer, IRegion subject) {
+ currentHovers = new LinkedHashMap<>();
+ for (ITextHover hover : this.fHovers) {
+ Object res = hover instanceof ITextHoverExtension2
+ ? ((ITextHoverExtension2) hover).getHoverInfo2(textViewer, subject)
+ : hover.getHoverInfo(textViewer, subject);
+ if (res != null) {
+ currentHovers.put(hover, res);
+ }
+ }
+ if (currentHovers.isEmpty()) {
+ return null;
+ } else if (currentHovers.size() == 1) {
+ return currentHovers.values().iterator().next();
+ }
+ return currentHovers;
+ }
+
+ @Override
+ public IRegion getSubject(ITextViewer textViewer, int offset) {
+ IRegion res = null;
+ for (ITextHover hover : this.fHovers) {
+ IRegion region = hover.getHoverRegion(textViewer, offset);
+ if (region != null) {
+ if (res == null) {
+ res = region;
+ } else {
+ int startOffset = Math.max(res.getOffset(), region.getOffset());
+ int endOffset = Math.min(res.getOffset() + res.getLength(),
+ region.getOffset() + region.getLength());
+ res = new Region(startOffset, endOffset - startOffset);
+ }
+ }
+ }
+ return res;
+ }
+
+ @Override
+ public String getInformation(ITextViewer textViewer, IRegion subject) {
+ return this.fHovers.stream().map(hover -> hover.getHoverInfo(textViewer, subject)).filter(Objects::nonNull)
+ .collect(Collectors.joining("\n")); //$NON-NLS-1$
+ }
+
+ @Override
+ public IInformationControlCreator getInformationPresenterControlCreator() {
+ if (this.currentHovers == null || this.currentHovers.isEmpty()) {
+ return null;
+ } else if (currentHovers.size() == 1) {
+ ITextHover hover = this.currentHovers.keySet().iterator().next();
+ return hover instanceof ITextHoverExtension ? ((ITextHoverExtension) hover).getHoverControlCreator()
+ : new AbstractReusableInformationControlCreator() {
+ @Override
+ protected IInformationControl doCreateInformationControl(Shell parent) {
+ return new DefaultInformationControl(parent);
+ };
+ };
+ } else {
+ return new CompositeInformationControlCreator(new ArrayList<>(this.currentHovers.keySet()));
+ }
+ }
+ }
+
/**
* Set content-types that will be considered is no content-type can be deduced
* from the document (eg document is not backed by a FileBuffer)

Back to the top