Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMickael Istria2017-05-18 08:47:18 -0400
committerMickael Istria2017-09-06 16:32:56 -0400
commit55c3acdef4f74ecddae3e3f6c89fdb691c2c64ad (patch)
tree42a38a3a5f0fc5c634a8797b753f4f380566569f
parentb3ee795c0b366f5254afb46c633640b78bb06a0a (diff)
downloadeclipse.platform.text-55c3acdef4f74ecddae3e3f6c89fdb691c2c64ad.tar.gz
eclipse.platform.text-55c3acdef4f74ecddae3e3f6c89fdb691c2c64ad.tar.xz
eclipse.platform.text-55c3acdef4f74ecddae3e3f6c89fdb691c2c64ad.zip
Bug 513321 - Aggregate mutliple hover sources
Change-Id: I3cc1fe523f1db9f55095e587ea05a88b1f89dfaa Signed-off-by: Mickael Istria <mistria@redhat.com>
-rw-r--r--org.eclipse.jface.text/src/org/eclipse/jface/text/AbstractInformationControl.java2
-rw-r--r--org.eclipse.jface.text/src/org/eclipse/jface/text/source/LineNumberRulerColumn.java2
-rw-r--r--org.eclipse.ui.genericeditor.tests/plugin.xml22
-rw-r--r--org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/AbstratGenericEditorTest.java41
-rw-r--r--org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/HoverTest.java39
-rw-r--r--org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/AlrightyHoverProvider.java (renamed from org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/MagicHoverProvider.java)2
-rw-r--r--org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/HelloHoverProvider.java38
-rw-r--r--org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/CompositeTextHover.java90
-rw-r--r--org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/ExtensionBasedTextViewerConfiguration.java11
-rw-r--r--org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericEditorPlugin.java1
-rw-r--r--org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/hover/CompositeInformationControl.java156
-rw-r--r--org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/hover/CompositeInformationControlCreator.java120
-rw-r--r--org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/hover/CompositeTextHover.java113
-rw-r--r--org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/hover/OrderedExtensionComparator.java (renamed from org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/OrderedExtensionComparator.java)6
-rw-r--r--org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/hover/TextHoverRegistry.java (renamed from org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/TextHoverRegistry.java)12
-rw-r--r--org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/markers/MarkerHoverControlCreator.java16
-rw-r--r--org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/markers/MarkerInformationControl.java20
17 files changed, 550 insertions, 141 deletions
diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/AbstractInformationControl.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/AbstractInformationControl.java
index 374ad6108..41195aac6 100644
--- a/org.eclipse.jface.text/src/org/eclipse/jface/text/AbstractInformationControl.java
+++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/AbstractInformationControl.java
@@ -435,7 +435,7 @@ public abstract class AbstractInformationControl implements IInformationControl,
*
* @return the shell used for the popup window
*/
- protected final Shell getShell() {
+ public final Shell getShell() {
return fShell;
}
diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/LineNumberRulerColumn.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/LineNumberRulerColumn.java
index 81002167f..ff4cf215e 100644
--- a/org.eclipse.jface.text/src/org/eclipse/jface/text/source/LineNumberRulerColumn.java
+++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/source/LineNumberRulerColumn.java
@@ -762,7 +762,7 @@ public class LineNumberRulerColumn implements IVerticalRulerColumn {
fZoom= 100;
}
- ImageData imageData= gcImage.getImageData(100);
+ ImageData imageData= gcImage.getImageData();
gcImage.dispose();
return imageData;
});
diff --git a/org.eclipse.ui.genericeditor.tests/plugin.xml b/org.eclipse.ui.genericeditor.tests/plugin.xml
index d2c3f4580..c7ce8e9b8 100644
--- a/org.eclipse.ui.genericeditor.tests/plugin.xml
+++ b/org.eclipse.ui.genericeditor.tests/plugin.xml
@@ -26,9 +26,13 @@
<extension
point="org.eclipse.ui.genericeditor.hoverProviders">
<hoverProvider
- class="org.eclipse.ui.genericeditor.tests.contributions.MagicHoverProvider"
+ class="org.eclipse.ui.genericeditor.tests.contributions.AlrightyHoverProvider"
contentType="org.eclipse.ui.genericeditor.tests.content-type">
</hoverProvider>
+ <hoverProvider
+ class="org.eclipse.ui.genericeditor.tests.contributions.HelloHoverProvider"
+ contentType="org.eclipse.ui.genericeditor.tests.specialized-content-type-bartxt">
+ </hoverProvider>
</extension>
<extension
point="org.eclipse.ui.genericeditor.reconcilers">
@@ -36,11 +40,11 @@
class="org.eclipse.ui.genericeditor.tests.contributions.TheReconcilerFirst"
contentType="org.eclipse.core.runtime.text">
</reconciler>
- <reconciler
- class="org.eclipse.ui.genericeditor.tests.contributions.TheReconcilerSecond"
- contentType="org.eclipse.ui.genericeditor.tests.reconciled-content-type">
- </reconciler>
- </extension>
+ <reconciler
+ class="org.eclipse.ui.genericeditor.tests.contributions.TheReconcilerSecond"
+ contentType="org.eclipse.ui.genericeditor.tests.specialized-content-type-bartxt">
+ </reconciler>
+ </extension>
<extension
point="org.eclipse.ui.genericeditor.presentationReconcilers">
<presentationReconciler
@@ -80,10 +84,10 @@
priority="normal">
</content-type>
<content-type
- base-type="org.eclipse.core.runtime.text"
+ base-type="org.eclipse.ui.genericeditor.tests.content-type"
file-names="bar.txt"
- id="org.eclipse.ui.genericeditor.tests.reconciled-content-type"
- name="Generic Editor Reconciler Test content-type"
+ id="org.eclipse.ui.genericeditor.tests.specialized-content-type-bartxt"
+ name="Specialized Generic Editor content-type for &apos;bar.txt&apos;"
priority="normal">
</content-type>
</extension>
diff --git a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/AbstratGenericEditorTest.java b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/AbstratGenericEditorTest.java
index 6d12a6f54..2d31f0ad0 100644
--- a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/AbstratGenericEditorTest.java
+++ b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/AbstratGenericEditorTest.java
@@ -17,6 +17,8 @@ import org.junit.Before;
import org.eclipse.swt.widgets.Display;
+import org.eclipse.core.runtime.NullProgressMonitor;
+
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
@@ -47,17 +49,42 @@ public class AbstratGenericEditorTest {
project = ResourcesPlugin.getWorkspace().getRoot().getProject(getClass().getName() + System.currentTimeMillis());
project.create(null);
project.open(null);
- file = project.getFile("foo.txt");
- file.create(new ByteArrayInputStream("bar 'bar'".getBytes()), true, null);
- editor = (ExtensionBasedTextEditor) PlatformUI.getWorkbench().getActiveWorkbenchWindow()
- .getActivePage().openEditor(new FileEditorInput(this.file), "org.eclipse.ui.genericeditor.GenericEditor");
+ createAndOpenFile("foo.txt", "bar 'bar'");
}
+
+ /**
+ * Creates a new file in the project, opens it, and associate that file with the test state
+ * @param name name of the file in the project
+ * @param contents content of the file
+ * @throws Exception ex
+ * @since 1.1
+ */
+ protected void createAndOpenFile(String name, String contents) throws Exception {
+ this.file = project.getFile(name);
+ this.file.create(new ByteArrayInputStream(contents.getBytes()), true, null);
+ this.editor = (ExtensionBasedTextEditor) PlatformUI.getWorkbench().getActiveWorkbenchWindow()
+ .getActivePage().openEditor(new FileEditorInput(this.file), "org.eclipse.ui.genericeditor.GenericEditor");
+ }
- @After
- public void tearDown() throws Exception {
+ /**
+ * Closes editor and delete file. Keeps project open.
+ * @throws Exception ex
+ * @since 1.1
+ */
+ protected void cleanFileAndEditor() throws Exception {
+ if (editor != null) {
+ editor.close(false);
+ editor = null;
+ }
if (file != null) {
- file.delete(true, null);
+ file.delete(true, new NullProgressMonitor());
+ file = null;
}
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ cleanFileAndEditor();
if (project != null) {
project.delete(true, null);
}
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 a92fea669..e234e340a 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
@@ -10,13 +10,14 @@
*******************************************************************************/
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.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Collections;
+import java.util.Map;
import org.junit.Assume;
import org.junit.Before;
@@ -46,7 +47,8 @@ import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.TextViewer;
import org.eclipse.jface.text.tests.util.DisplayHelper;
-import org.eclipse.ui.genericeditor.tests.contributions.MagicHoverProvider;
+import org.eclipse.ui.genericeditor.tests.contributions.AlrightyHoverProvider;
+import org.eclipse.ui.genericeditor.tests.contributions.HelloHoverProvider;
import org.eclipse.ui.genericeditor.tests.contributions.MarkerResolutionGenerator;
import org.eclipse.ui.workbench.texteditor.tests.ScreenshotTest;
@@ -67,9 +69,23 @@ public class HoverTest extends AbstratGenericEditorTest {
}
@Test
- public void testHover() throws Exception {
+ public void testSingleHover() throws Exception {
Shell shell = getHoverShell(triggerCompletionAndRetrieveInformationControlManager());
- assertNotNull(findControl(shell, StyledText.class, MagicHoverProvider.LABEL));
+ assertNotNull(findControl(shell, StyledText.class, AlrightyHoverProvider.LABEL));
+ assertNull(findControl(shell, StyledText.class, HelloHoverProvider.LABEL));
+ }
+
+ /**
+ * @throws Exception ex
+ * @since 1.1
+ */
+ @Test
+ public void testMultipleHover() throws Exception {
+ cleanFileAndEditor();
+ createAndOpenFile("bar.txt", "Hi");
+ Shell shell = getHoverShell(triggerCompletionAndRetrieveInformationControlManager());
+ assertNotNull(findControl(shell, StyledText.class, AlrightyHoverProvider.LABEL));
+ assertNotNull(findControl(shell, StyledText.class, HelloHoverProvider.LABEL));
}
@Test
@@ -85,10 +101,17 @@ public class HoverTest extends AbstratGenericEditorTest {
marker.setAttribute(IMarker.MESSAGE, problemMessage);
marker.setAttribute(MarkerResolutionGenerator.FIXME, true);
AbstractInformationControlManager manager = triggerCompletionAndRetrieveInformationControlManager();
- assertEquals(Collections.singletonList(marker), getHoverData(manager));
+ Object hoverData = getHoverData(manager);
+ assertTrue(hoverData instanceof Map);
+ assertTrue(((Map<?,?>)hoverData).containsValue(Collections.singletonList(marker)));
+ assertTrue(((Map<?,?>)hoverData).containsValue(AlrightyHoverProvider.LABEL));
+ assertFalse(((Map<?,?>)hoverData).containsValue(HelloHoverProvider.LABEL));
// check dialog content
Shell shell= getHoverShell(manager);
assertNotNull(findControl(shell, Label.class, marker.getAttribute(IMarker.MESSAGE, "NONE")));
+ assertNotNull(findControl(shell, StyledText.class, AlrightyHoverProvider.LABEL));
+ assertNull(findControl(shell, StyledText.class, HelloHoverProvider.LABEL));
+ // check quick-fix works
Link link = findControl(shell, Link.class, MarkerResolutionGenerator.FIXME);
assertNotNull(link);
Event event = new Event();
@@ -126,6 +149,12 @@ public class HoverTest extends AbstratGenericEditorTest {
fail();
}
Shell shell = (Shell)new Accessor(control[0], AbstractInformationControl.class).get("fShell");
+ new DisplayHelper() {
+ @Override
+ protected boolean condition() {
+ return shell.isVisible();
+ }
+ }.waitForCondition(this.editor.getSite().getShell().getDisplay(), 2000);
assertTrue(shell.isVisible());
return shell;
}
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/AlrightyHoverProvider.java
index 0bba76cf9..726036e6d 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/AlrightyHoverProvider.java
@@ -16,7 +16,7 @@ import org.eclipse.jface.text.ITextHoverExtension2;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Region;
-public class MagicHoverProvider implements ITextHover,ITextHoverExtension2 {
+public class AlrightyHoverProvider implements ITextHover,ITextHoverExtension2 {
public static final String LABEL= "Alrighty!";
diff --git a/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/HelloHoverProvider.java b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/HelloHoverProvider.java
new file mode 100644
index 000000000..12f53196e
--- /dev/null
+++ b/org.eclipse.ui.genericeditor.tests/src/org/eclipse/ui/genericeditor/tests/contributions/HelloHoverProvider.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * 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.jface.text.IRegion;
+import org.eclipse.jface.text.ITextHover;
+import org.eclipse.jface.text.ITextHoverExtension2;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.Region;
+
+public class HelloHoverProvider implements ITextHover, ITextHoverExtension2 {
+
+ public static final String LABEL= "Hello!";
+
+ @Deprecated
+ @Override
+ public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
+ return null;
+ }
+
+ @Override
+ public IRegion getHoverRegion(ITextViewer textViewer, int offset) {
+ return new Region(0, textViewer.getTextWidget().getText().length());
+ }
+
+ @Override
+ public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) {
+ return LABEL;
+ }
+}
diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/CompositeTextHover.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/CompositeTextHover.java
deleted file mode 100644
index 89944fb78..000000000
--- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/CompositeTextHover.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*******************************************************************************
- * 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
- * http://www.eclipse.org/legal/epl-v10.html
- *
- * Contributors:
- * - Mickael Istria (Red Hat Inc.)
- *******************************************************************************/
-package org.eclipse.ui.internal.genericeditor;
-
-import java.util.List;
-
-import org.eclipse.core.runtime.Assert;
-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;
-
-/**
- * A text hover that delegates its operations to children
- * provided in constructor and returns the first interesting result.
- *
- * @since 1.0
- */
-public class CompositeTextHover implements ITextHover, ITextHoverExtension, ITextHoverExtension2 {
-
- private List<ITextHover> hoversToConsider;
- private ITextHover currentHover = null;
-
- public CompositeTextHover(List<ITextHover> hoversToConsider) {
- Assert.isNotNull(hoversToConsider);
- this.hoversToConsider = hoversToConsider;
- }
-
- @Override
- public Object getHoverInfo2(ITextViewer textViewer, IRegion hoverRegion) {
- for (ITextHover hover : this.hoversToConsider) {
- Object res = null;
- if (hover instanceof ITextHoverExtension2) {
- res = ((ITextHoverExtension2)hover).getHoverInfo2(textViewer, hoverRegion);
- } else {
- res = hover.getHoverInfo(textViewer, hoverRegion);
- }
- if (res != null) {
- currentHover = hover;
- return res;
- }
- }
- return null;
- }
-
- @Override
- public IInformationControlCreator getHoverControlCreator() {
- ITextHover hover = this.currentHover;
- if (hover != null) {
- if (hover instanceof ITextHoverExtension) {
- return ((ITextHoverExtension)hover).getHoverControlCreator();
- }
- }
- return null;
- }
-
- @Override
- public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
- for (ITextHover hover : this.hoversToConsider) {
- String res = hover.getHoverInfo(textViewer, hoverRegion);
- if (res != null) {
- currentHover = hover;
- return res;
- }
- }
- return null;
- }
-
- @Override
- public IRegion getHoverRegion(ITextViewer textViewer, int offset) {
- for (ITextHover hover : this.hoversToConsider) {
- IRegion res = hover.getHoverRegion(textViewer, offset);
- if (res != null) {
- return res;
- }
- }
- return null;
- }
-
-}
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 ab43608f5..4e0461fe0 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
@@ -42,6 +42,7 @@ import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IPropertyListener;
import org.eclipse.ui.editors.text.TextSourceViewerConfiguration;
import org.eclipse.ui.internal.editors.text.EditorsPlugin;
+import org.eclipse.ui.internal.genericeditor.hover.CompositeTextHover;
import org.eclipse.ui.internal.genericeditor.markers.MarkerResoltionQuickAssistProcessor;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.texteditor.spelling.SpellingCorrectionProcessor;
@@ -99,8 +100,14 @@ public final class ExtensionBasedTextViewerConfiguration extends TextSourceViewe
@Override
public ITextHover getTextHover(ISourceViewer sourceViewer, String contentType) {
- TextHoverRegistry registry= GenericEditorPlugin.getDefault().getHoverRegistry();
- return registry.getAvailableHover(sourceViewer, getContentTypes());
+ List<ITextHover> hovers = GenericEditorPlugin.getDefault().getHoverRegistry().getAvailableHovers(sourceViewer, getContentTypes());
+ if (hovers == null || hovers.isEmpty()) {
+ return null;
+ } else if (hovers.size() == 1) {
+ return hovers.get(0);
+ } else {
+ return new CompositeTextHover(hovers);
+ }
}
@Override
diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericEditorPlugin.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericEditorPlugin.java
index 8bdf7a4cf..cbceac42b 100644
--- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericEditorPlugin.java
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/GenericEditorPlugin.java
@@ -14,6 +14,7 @@ package org.eclipse.ui.internal.genericeditor;
import org.eclipse.jface.text.ITextHover;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.presentation.IPresentationReconciler;
+import org.eclipse.ui.internal.genericeditor.hover.TextHoverRegistry;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/hover/CompositeInformationControl.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/hover/CompositeInformationControl.java
new file mode 100644
index 000000000..a63088f2f
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/hover/CompositeInformationControl.java
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * 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.internal.genericeditor.hover;
+
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.text.AbstractInformationControl;
+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.jface.text.IInformationControlExtension5;
+import org.eclipse.jface.text.ITextHover;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.internal.genericeditor.GenericEditorPlugin;
+
+public class CompositeInformationControl extends AbstractInformationControl implements IInformationControlExtension2 {
+
+ final LinkedHashMap<ITextHover, IInformationControlCreator> creators;
+ LinkedHashMap<ITextHover, IInformationControl> controls;
+
+ public CompositeInformationControl(Shell parentShell, LinkedHashMap<ITextHover, IInformationControlCreator> creators) {
+ super(parentShell, true); // TODO check best constructor
+ Assert.isLegal(creators.size() > 1, "Do not compose a unique hover"); //$NON-NLS-1$
+ this.creators = creators;
+ create();
+ }
+
+ @Override
+ public boolean hasContents() {
+ for (IInformationControl control : controls.values()) {
+ if (control instanceof IInformationControlExtension) {
+ if (((IInformationControlExtension)control).hasContents()) {
+ return true;
+ }
+ } else {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void setInput(Object input) {
+ @SuppressWarnings("unchecked")
+ Map<ITextHover, Object> inputs = (Map<ITextHover, Object>)input;
+ for (Entry<ITextHover, Object> entry : inputs.entrySet()) {
+ IInformationControl informationControl = controls.get(entry.getKey());
+ if (informationControl != null) {
+ if (informationControl instanceof IInformationControlExtension2) {
+ ((IInformationControlExtension2)informationControl).setInput(entry.getValue());
+ } else {
+ informationControl.setInformation(entry.getValue().toString());
+ }
+ }
+ }
+ }
+
+ @Override
+ public void createContent(Composite parent) {
+ this.controls = new LinkedHashMap<>(); // TODO maybe use canReuse or canReplace
+ GridLayout layout = new GridLayout(1, false);
+ parent.setLayout(layout);
+ boolean firstControl = true;
+ for (Entry<ITextHover, IInformationControlCreator> hoverControlCreator : this.creators.entrySet()) {
+ IInformationControl informationControl = hoverControlCreator.getValue().createInformationControl(parent.getShell());
+ if (informationControl instanceof AbstractInformationControl) {
+ List<Control> children = Arrays.asList(((AbstractInformationControl)informationControl).getShell().getChildren());
+ children.remove(parent);
+ if (children.size() == 0 ) {
+ continue;
+ }
+ for (Control control : children) {
+ control.setParent(parent);
+ control.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+ }
+ if (!firstControl) {
+ ((GridData)children.get(0).getLayoutData()).verticalIndent = 15;
+ }
+ controls.put(hoverControlCreator.getKey(), informationControl);
+ firstControl = false;
+ } else {
+ GenericEditorPlugin.getDefault().getLog().log(new Status(IStatus.WARNING, GenericEditorPlugin.BUNDLE_ID,
+ "Only text hovers producing an AbstractInformationControl can be aggregated; got a " + informationControl.getClass().getSimpleName())); //$NON-NLS-1$
+ informationControl.dispose();
+ }
+ }
+ }
+
+ @Override
+ public void dispose() {
+ controls.values().forEach(IInformationControl::dispose);
+ controls.clear();
+ super.dispose();
+ }
+
+ @Override
+ public IInformationControlCreator getInformationPresenterControlCreator() {
+ if (controls.isEmpty()) {
+ return null;
+ } else if (controls.size() == 1) {
+ IInformationControl control = controls.values().iterator().next();
+ if (control instanceof IInformationControlExtension5) {
+ return ((IInformationControlExtension5)control).getInformationPresenterControlCreator();
+ }
+ } else {
+ LinkedHashMap<ITextHover, IInformationControlCreator> presenterCreators = new LinkedHashMap<>();
+ boolean allNull = true;
+ for (Entry<ITextHover, IInformationControl> hover : this.controls.entrySet()) {
+ IInformationControlCreator creator = null;
+ if (hover.getValue() instanceof IInformationControlExtension5)
+ creator = ((IInformationControlExtension5)hover.getValue()).getInformationPresenterControlCreator();
+ if (creator == null) {
+ creator = this.creators.get(hover.getKey());
+ } else {
+ allNull = false;
+ }
+ if (creator != null) {
+ presenterCreators.put(hover.getKey(), creator);
+ }
+ }
+ if (allNull) {
+ return null;
+ }
+ return new CompositeInformationControlCreator(presenterCreators);
+ }
+ return null;
+ }
+
+ @Override
+ public Point computeSizeHint() {
+ return getShell().computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
+ }
+
+}
diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/hover/CompositeInformationControlCreator.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/hover/CompositeInformationControlCreator.java
new file mode 100644
index 000000000..ddeee6705
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/hover/CompositeInformationControlCreator.java
@@ -0,0 +1,120 @@
+/*******************************************************************************
+ * 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.internal.genericeditor.hover;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map.Entry;
+
+import org.eclipse.jface.text.AbstractReusableInformationControlCreator;
+import org.eclipse.jface.text.DefaultInformationControl;
+import org.eclipse.jface.text.IInformationControl;
+import org.eclipse.jface.text.IInformationControlCreator;
+import org.eclipse.jface.text.IInformationControlCreatorExtension;
+import org.eclipse.jface.text.ITextHover;
+import org.eclipse.jface.text.ITextHoverExtension;
+import org.eclipse.swt.widgets.Shell;
+
+public class CompositeInformationControlCreator
+ implements IInformationControlCreator, IInformationControlCreatorExtension {
+
+ private final LinkedHashMap<ITextHover, IInformationControlCreator> creators;
+
+ public CompositeInformationControlCreator(List<ITextHover> hovers) {
+ this.creators = new LinkedHashMap<>();
+ for (ITextHover hover : hovers) {
+ creators.put(hover, getInformationControlCreator(hover));
+ }
+ }
+
+ public CompositeInformationControlCreator(LinkedHashMap<ITextHover, IInformationControlCreator> creators) {
+ this.creators = creators;
+ }
+
+ private static IInformationControlCreator getInformationControlCreator(ITextHover hover) {
+ IInformationControlCreator controlCreator = null;
+ if (hover instanceof ITextHoverExtension) {
+ controlCreator = ((ITextHoverExtension)hover).getHoverControlCreator();
+ }
+ if (controlCreator == null) {
+ controlCreator = new AbstractReusableInformationControlCreator() {
+ @Override
+ protected IInformationControl doCreateInformationControl(Shell parent) {
+ return new DefaultInformationControl(parent, true);
+ }
+ };
+ }
+ return controlCreator;
+ }
+
+
+ @Override
+ public boolean canReuse(IInformationControl control) {
+ if (control.getClass() != CompositeInformationControl.class) {
+ return false;
+ }
+ CompositeInformationControl other = (CompositeInformationControl)control;
+ if (!other.creators.equals(this.creators)) {
+ return false;
+ }
+ Iterator<Entry<ITextHover, IInformationControlCreator>> thisIterator = this.creators.entrySet().iterator();
+ Iterator<Entry<ITextHover, IInformationControl>> otherIterator = other.controls.entrySet().iterator();
+ do {
+ Entry<ITextHover, IInformationControlCreator> thisEntry = thisIterator.next();
+ Entry<ITextHover, IInformationControl> otherEntry = otherIterator.next();
+ if (!thisEntry.getKey().equals(otherEntry.getKey())) {
+ return false;
+ }
+ if (!(thisEntry.getValue() instanceof IInformationControlCreatorExtension)) {
+ return false;
+ }
+ if (!((IInformationControlCreatorExtension)thisEntry.getValue()).canReuse(otherEntry.getValue())) {
+ return false;
+ }
+ } while (thisIterator.hasNext());
+ return true;
+ }
+
+ @Override
+ public boolean canReplace(IInformationControlCreator creator) {
+ if (creator.getClass() != this.getClass()) {
+ return false;
+ }
+ CompositeInformationControlCreator other = (CompositeInformationControlCreator)creator;
+ if (other.creators.size() != this.creators.size()) {
+ return false;
+ }
+ Iterator<Entry<ITextHover, IInformationControlCreator>> thisIterator = this.creators.entrySet().iterator();
+ Iterator<Entry<ITextHover, IInformationControlCreator>> otherIterator = other.creators.entrySet().iterator();
+ do {
+ Entry<ITextHover, IInformationControlCreator> thisEntry = thisIterator.next();
+ Entry<ITextHover, IInformationControlCreator> otherEntry = otherIterator.next();
+ if (!thisEntry.getKey().equals(otherEntry.getKey())) {
+ return false;
+ }
+ if (!(thisEntry.getValue() instanceof IInformationControlCreatorExtension)) {
+ return false;
+ }
+ if (!((IInformationControlCreatorExtension)thisEntry.getValue()).canReplace(otherEntry.getValue())) {
+ return false;
+ }
+ } while (thisIterator.hasNext());
+ return true;
+ }
+
+
+ @Override
+ public IInformationControl createInformationControl(Shell parent) {
+ return new CompositeInformationControl(parent, this.creators);
+ }
+
+}
diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/hover/CompositeTextHover.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/hover/CompositeTextHover.java
new file mode 100644
index 000000000..82e2cb271
--- /dev/null
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/hover/CompositeTextHover.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * - Mickael Istria (Red Hat Inc.)
+ *******************************************************************************/
+package org.eclipse.ui.internal.genericeditor.hover;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import org.eclipse.core.runtime.Assert;
+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;
+
+/**
+ * A text hover that delegates its operations to children
+ * provided in constructor and returns the first interesting result.
+ *
+ * @since 1.0
+ */
+public class CompositeTextHover implements ITextHover, ITextHoverExtension, ITextHoverExtension2 {
+
+ private final List<ITextHover> allHovers;
+ private LinkedHashMap<ITextHover, IRegion> regions = null;
+ private LinkedHashMap<ITextHover, Object> currentHovers = null;
+
+ public CompositeTextHover(List<ITextHover> hoversToConsider) {
+ Assert.isNotNull(hoversToConsider);
+ Assert.isLegal(hoversToConsider.size() > 1, "Do not compose a single hover."); //$NON-NLS-1$
+ this.allHovers = Collections.unmodifiableList(hoversToConsider);
+ }
+
+ @Override
+ public Object getHoverInfo2(ITextViewer textViewer, IRegion requestRegion) {
+ this.currentHovers = new LinkedHashMap<>();
+ for (ITextHover hover : this.allHovers) {
+ IRegion currentRegion = this.regions.get(hover);
+ if (currentRegion == null) {
+ continue;
+ }
+ Object res = hover instanceof ITextHoverExtension2 ?
+ ((ITextHoverExtension2)hover).getHoverInfo2(textViewer, currentRegion) :
+ hover.getHoverInfo(textViewer, currentRegion);
+ if (res != null) {
+ this.currentHovers.put(hover, res);
+ }
+ }
+ if (this.currentHovers.isEmpty()) {
+ return null;
+ } else if (this.currentHovers.size() == 1) {
+ return this.currentHovers.values().iterator().next();
+ } else {
+ return this.currentHovers;
+ }
+ }
+
+ @Override
+ public IInformationControlCreator getHoverControlCreator() {
+ 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():
+ null;
+ } else {
+ return new CompositeInformationControlCreator(new ArrayList<>(this.currentHovers.keySet()));
+ }
+ }
+
+ @Override
+ public String getHoverInfo(ITextViewer textViewer, IRegion hoverRegion) {
+ return this.allHovers.stream()
+ .map(hover -> hover.getHoverInfo(textViewer, this.regions.get(hover)))
+ .filter(Objects::nonNull)
+ .collect(Collectors.joining("\n")); //$NON-NLS-1$
+ }
+
+ @Override
+ public IRegion getHoverRegion(ITextViewer textViewer, int offset) {
+ this.regions = new LinkedHashMap<>();
+ IRegion res = null;
+ for (ITextHover hover : this.allHovers) {
+ IRegion region = hover.getHoverRegion(textViewer, offset);
+ if (region != null) {
+ this.regions.put(hover, region);
+ 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;
+ }
+
+}
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/hover/OrderedExtensionComparator.java
index 0ae0bbaca..9cf322229 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/hover/OrderedExtensionComparator.java
@@ -8,7 +8,7 @@
* Contributors:
* Mickael Istria (Red Hat Inc.) - initial implementation
*******************************************************************************/
-package org.eclipse.ui.internal.genericeditor;
+package org.eclipse.ui.internal.genericeditor.hover;
import java.util.Collection;
import java.util.Comparator;
@@ -17,12 +17,12 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import org.eclipse.core.runtime.Assert;
-import org.eclipse.ui.internal.genericeditor.TextHoverRegistry.TextHoverExtension;
+import org.eclipse.ui.internal.genericeditor.hover.TextHoverRegistry.TextHoverExtension;
/**
* A comparator that allows to sort elements according to their relative
* placement (isBefore and isAfter)
- *
+ *TODO: generalizing to any kind of extension supporting isBefore and isAfter
*/
class OrderedExtensionComparator implements Comparator<TextHoverExtension> {
diff --git a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/TextHoverRegistry.java b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/hover/TextHoverRegistry.java
index 374c066ec..f68bbf74d 100644
--- a/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/TextHoverRegistry.java
+++ b/org.eclipse.ui.genericeditor/src/org/eclipse/ui/internal/genericeditor/hover/TextHoverRegistry.java
@@ -8,7 +8,7 @@
* Contributors:
* - Mickael Istria (Red Hat Inc.)
*******************************************************************************/
-package org.eclipse.ui.internal.genericeditor;
+package org.eclipse.ui.internal.genericeditor.hover;
import java.util.HashMap;
import java.util.HashSet;
@@ -30,6 +30,8 @@ import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.ITextHover;
import org.eclipse.jface.text.source.ISourceViewer;
+import org.eclipse.ui.internal.genericeditor.GenericContentTypeRelatedExtension;
+import org.eclipse.ui.internal.genericeditor.GenericEditorPlugin;
/**
* Text hover registry that manages the detectors
@@ -90,19 +92,15 @@ public final class TextHoverRegistry {
}, EXTENSION_POINT_ID);
}
- public ITextHover getAvailableHover(ISourceViewer sourceViewer, Set<IContentType> contentTypes) {
+ public List<ITextHover> getAvailableHovers(ISourceViewer sourceViewer, Set<IContentType> contentTypes) {
if (this.outOfSync) {
sync();
}
- List<ITextHover> hoversToConsider = this.extensions.stream()
+ return this.extensions.stream()
.filter(ext -> contentTypes.contains(ext.targetContentType))
// don't sort in the stream as the initial structure is already sorted by isAfter/isBefore
.map(GenericContentTypeRelatedExtension<ITextHover>::createDelegate)
.collect(Collectors.toList());
- if (!hoversToConsider.isEmpty()) {
- return new CompositeTextHover(hoversToConsider);
- }
- return null;
}
private void sync() {
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
index 8d81994f0..55e9d0bf6 100644
--- 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
@@ -17,19 +17,29 @@ import org.eclipse.swt.widgets.Shell;
public class MarkerHoverControlCreator implements IInformationControlCreator, IInformationControlCreatorExtension {
+ private final boolean showAffordanceString;
+
+ public MarkerHoverControlCreator() {
+ this(true);
+ }
+
+ public MarkerHoverControlCreator(boolean showAffordanceString) {
+ this.showAffordanceString = showAffordanceString;
+ }
+
@Override
public boolean canReuse(IInformationControl control) {
- return false;
+ return control instanceof MarkerInformationControl;
}
@Override
public boolean canReplace(IInformationControlCreator creator) {
- return false;
+ return creator instanceof MarkerHoverControlCreator;
}
@Override
public IInformationControl createInformationControl(Shell parent) {
- return new MarkerInformationControl(parent,this);
+ return new MarkerInformationControl(parent, showAffordanceString);
}
}
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
index 98bf713d9..db93b4a96 100644
--- 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
@@ -11,6 +11,7 @@
package org.eclipse.ui.internal.genericeditor.markers;
import java.util.Collection;
+import java.util.LinkedHashMap;
import java.util.List;
import org.eclipse.core.resources.IMarker;
@@ -19,7 +20,6 @@ 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;
@@ -46,11 +46,10 @@ import org.eclipse.ui.ide.IDE.SharedImages;
public class MarkerInformationControl extends AbstractInformationControl implements IInformationControl, IInformationControlExtension, IInformationControlExtension2 {
- private IInformationControlCreator creator;
+ private final LinkedHashMap<IMarker, Composite> composites = new LinkedHashMap<>();
- public MarkerInformationControl(Shell parentShell, IInformationControlCreator creator) {
- super(parentShell, EditorsUI.getTooltipAffordanceString());
- this.creator = creator;
+ public MarkerInformationControl(Shell parentShell, boolean showAffordanceString) {
+ super(parentShell, showAffordanceString ? EditorsUI.getTooltipAffordanceString() : null);
create();
}
@@ -84,9 +83,11 @@ public class MarkerInformationControl extends AbstractInformationControl impleme
@SuppressWarnings("unchecked")
@Override
public void setInput(Object input) {
+ this.composites.values().forEach(Composite::dispose);
this.markers = (List<IMarker>)input;
for (IMarker marker : this.markers) {
Composite markerComposite = new Composite(parent, SWT.NONE);
+ this.composites.put(marker, markerComposite);
GridLayout gridLayout = new GridLayout(1, false);
gridLayout.verticalSpacing = 0;
markerComposite.setLayout(gridLayout);
@@ -135,17 +136,12 @@ public class MarkerInformationControl extends AbstractInformationControl impleme
});
}
}
- parent.pack(true);
+ parent.layout(true);
}
@Override
public IInformationControlCreator getInformationPresenterControlCreator() {
- return new AbstractReusableInformationControlCreator() {
- @Override
- protected IInformationControl doCreateInformationControl(Shell parent) {
- return creator.createInformationControl(parent);
- }
- };
+ return new MarkerHoverControlCreator(false);
}
@Override

Back to the top