Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkus Keller2009-06-11 17:29:54 +0000
committerMarkus Keller2009-06-11 17:29:54 +0000
commitcef6230e04a6f55f8bb087bfd0ca0d40e1fdfacd (patch)
treee5489b0aa3b20458343df82da2491ddccf96a2f3
parent40752f4743b0589caeb572ede78b448b19e270e2 (diff)
downloadeclipse.platform.text-cef6230e04a6f55f8bb087bfd0ca0d40e1fdfacd.tar.gz
eclipse.platform.text-cef6230e04a6f55f8bb087bfd0ca0d40e1fdfacd.tar.xz
eclipse.platform.text-cef6230e04a6f55f8bb087bfd0ca0d40e1fdfacd.zip
Bug 62652: [hovering] Unable to resize javadoc popups on linux
workaround for SWT bug 23980.
-rw-r--r--org.eclipse.jface.text/src/org/eclipse/jface/internal/text/ResizableShellSupport.java306
-rw-r--r--org.eclipse.jface.text/src/org/eclipse/jface/text/AbstractInformationControl.java13
-rw-r--r--org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/CompletionProposalPopup.java4
3 files changed, 321 insertions, 2 deletions
diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/ResizableShellSupport.java b/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/ResizableShellSupport.java
new file mode 100644
index 00000000000..74cf6e2de68
--- /dev/null
+++ b/org.eclipse.jface.text/src/org/eclipse/jface/internal/text/ResizableShellSupport.java
@@ -0,0 +1,306 @@
+/*******************************************************************************
+ * Copyright (c) 2009 IBM Corporation 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:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jface.internal.text;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.MouseMoveListener;
+import org.eclipse.swt.events.MouseTrackAdapter;
+import org.eclipse.swt.events.PaintEvent;
+import org.eclipse.swt.events.PaintListener;
+import org.eclipse.swt.graphics.Cursor;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Shell;
+
+import org.eclipse.jface.util.Geometry;
+
+/**
+ * Workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=23980 : Shells without borders are
+ * not resizable on GTK.
+ *
+ * @since 3.6
+ */
+public class ResizableShellSupport {
+
+ /**
+ * Listeners installed on the shell.
+ */
+ private static class MouseListenerMix extends MouseTrackAdapter implements MouseListener, MouseMoveListener {
+ /**
+ * The shell.
+ */
+ private final Shell fShell;
+ /**
+ * The minimal shell width.
+ */
+ private final int fMinShellWidth;
+ /**
+ * The minimal shell height.
+ */
+ private final int fMinShellHeight;
+
+ /**
+ * The last detected edges.
+ */
+ private int fCurrentEdges;
+ /**
+ * The shell's original cursor.
+ */
+ private Cursor fOriginalCursor;
+
+ /**
+ * The location of the mouseDown event (display coordinates).
+ */
+ private Point fOriginalMouseLoc;
+ /**
+ * The bounds of the shell on mouseDown (display coordinates).
+ */
+ private Rectangle fOriginalShellBounds;
+
+ /**
+ * Creates a mouse listener mix
+ * @param shell the shell
+ */
+ public MouseListenerMix(Shell shell) {
+ fShell= shell;
+ Rectangle trim= shell.computeTrim(0, 0, 0, 0);
+ fMinShellWidth= trim.width + 2 * TRIM_SIZE;
+ fMinShellHeight= trim.height + 2 * TRIM_SIZE;
+ }
+
+ /*
+ * @see org.eclipse.swt.events.MouseMoveListener#mouseMove(org.eclipse.swt.events.MouseEvent)
+ */
+ public void mouseMove(MouseEvent e) {
+ if (fOriginalMouseLoc != null) {
+ Point mouse= fShell.toDisplay(e.x, e.y);
+ int dx= mouse.x - fOriginalMouseLoc.x;
+ int dy= mouse.y - fOriginalMouseLoc.y;
+
+ Rectangle sb= Geometry.copy(fOriginalShellBounds);
+ if ((fCurrentEdges & SWT.LEFT) != 0) {
+ int w= Math.max(sb.width - dx, fMinShellWidth);
+ sb.x+= sb.width - w;
+ sb.width= w;
+ }
+ if ((fCurrentEdges & SWT.RIGHT) != 0) {
+ sb.width= Math.max(sb.width + dx, fMinShellWidth);
+ }
+ if ((fCurrentEdges & SWT.TOP) != 0) {
+ int h= Math.max(sb.height - dy, fMinShellHeight);
+ sb.y+= sb.height - h;
+ sb.height= h;
+ }
+ if ((fCurrentEdges & SWT.BOTTOM) != 0) {
+ sb.height= Math.max(sb.height + dy, fMinShellHeight);
+ }
+ fShell.setBounds(sb);
+
+ } else {
+ int edges= computeEdges(e);
+ setEdgesAndCursor(edges);
+ }
+ }
+
+ /*
+ * @see org.eclipse.swt.events.MouseTrackAdapter#mouseExit(org.eclipse.swt.events.MouseEvent)
+ */
+ public void mouseExit(MouseEvent e) {
+ setEdgesAndCursor(0);
+ }
+
+ /*
+ * @see org.eclipse.swt.events.MouseAdapter#mouseDown(org.eclipse.swt.events.MouseEvent)
+ */
+ public void mouseDown(MouseEvent e) {
+ if (fCurrentEdges != 0) {
+ fOriginalMouseLoc= fShell.toDisplay(e.x, e.y);
+ fOriginalShellBounds= fShell.getBounds();
+ }
+ }
+
+ /*
+ * @see org.eclipse.swt.events.MouseAdapter#mouseUp(org.eclipse.swt.events.MouseEvent)
+ */
+ public void mouseUp(MouseEvent e) {
+ fOriginalMouseLoc= null;
+ fOriginalShellBounds= null;
+ }
+
+ /*
+ * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent)
+ */
+ public void mouseDoubleClick(MouseEvent e) {
+ // not interesting
+ }
+
+ /**
+ * Returns the edges at which the mouse is pointing. The result is one of
+ * {@link SWT#TOP}, {@link SWT#BOTTOM}, {@link SWT#LEFT}, or {@link SWT#RIGHT}, or a
+ * sensible combination thereof.
+ *
+ * @param e the mouse event
+ * @return the edges or 0 if the mouse is not over an edge
+ */
+ private int computeEdges(MouseEvent e) {
+ Rectangle sb= fShell.getClientArea();
+
+ int edges= 0;
+ if (sb.contains(e.x, e.y)) {
+ int bottom= sb.y + sb.height - e.y;
+ int top= e.y - sb.y;
+ int right= sb.x + sb.width - e.x;
+ int left= e.x - sb.x;
+
+ // prioritize bottom-right:
+ if (bottom <= TRIM_SIZE) {
+ edges|= SWT.BOTTOM;
+ } else if (top <= TRIM_SIZE) {
+ edges|= SWT.TOP;
+ }
+ if (right <= TRIM_SIZE) {
+ edges|= SWT.RIGHT;
+ } else if (left <= TRIM_SIZE) {
+ edges|= SWT.LEFT;
+ }
+
+ // enlarge corners, prioritizing bottom-right:
+ if ((edges & SWT.BOTTOM) != 0) {
+ edges= enlargeCorner(SWT.BOTTOM, right, SWT.RIGHT, left, SWT.LEFT);
+ } else if ((edges & SWT.RIGHT) != 0) {
+ edges= enlargeCorner(SWT.RIGHT, bottom, SWT.BOTTOM, top, SWT.TOP);
+ } else if ((edges & SWT.LEFT) != 0) {
+ edges= enlargeCorner(SWT.LEFT, bottom, SWT.BOTTOM, top, SWT.TOP);
+ } else if ((edges & SWT.TOP) != 0) {
+ edges= enlargeCorner(SWT.TOP, right, SWT.RIGHT, left, SWT.LEFT);
+ }
+ }
+ return edges;
+ }
+
+ /**
+ * Adds an adjacent edge if the distance to a corner is small enough. First corner gets
+ * priority.
+ *
+ * @param edge the base edge
+ * @param distance1 distance to first corner
+ * @param edge1 adjacent edge of first corner
+ * @param distance2 distance to second corner
+ * @param edge2 adjacent edge of second corner
+ * @return the new edges
+ */
+ private static int enlargeCorner(int edge, int distance1, int edge1, int distance2, int edge2) {
+ int edges= edge;
+ if (distance1 <= CORNER_SIZE) {
+ edges|= edge1;
+ } else if (distance2 <= CORNER_SIZE) {
+ edges|= edge2;
+ }
+ return edges;
+ }
+
+ /**
+ * Sets the cursor for the given edges or resets the original if 0.
+ *
+ * @param edges the edges or 0
+ */
+ private void setEdgesAndCursor(int edges) {
+ if (edges == fCurrentEdges)
+ return;
+
+ if (edges == 0) {
+ fShell.setCursor(fOriginalCursor);
+ fOriginalCursor= null;
+ fCurrentEdges= edges;
+ fOriginalMouseLoc= null;
+ fOriginalShellBounds= null;
+ return;
+ }
+
+ if (fCurrentEdges == 0) {
+ fOriginalCursor= fShell.getCursor();
+ }
+ fCurrentEdges= edges;
+
+ int style= 0;
+ if ((edges & SWT.TOP) != 0) {
+ if ((edges & SWT.LEFT) != 0) {
+ style= SWT.CURSOR_SIZENW;
+ } else if ((edges & SWT.RIGHT) != 0) {
+ style= SWT.CURSOR_SIZENE;
+ } else {
+ style= SWT.CURSOR_SIZEN;
+ }
+ } else if ((edges & SWT.BOTTOM) != 0) {
+ if ((edges & SWT.LEFT) != 0) {
+ style= SWT.CURSOR_SIZESW;
+ } else if ((edges & SWT.RIGHT) != 0) {
+ style= SWT.CURSOR_SIZESE;
+ } else {
+ style= SWT.CURSOR_SIZES;
+ }
+ } else if ((edges & SWT.LEFT) != 0) {
+ style= SWT.CURSOR_SIZEW;
+ } else if ((edges & SWT.RIGHT) != 0) {
+ style= SWT.CURSOR_SIZEE;
+ }
+
+ Cursor cursor= fShell.getDisplay().getSystemCursor(style);
+ fShell.setCursor(cursor);
+ }
+ }
+
+
+ /**
+ * Width of resize trim.
+ */
+ private static final int TRIM_SIZE= 4;
+ /**
+ * Enlarged area around corners in which dual-direction is active when mouse is in border.
+ */
+ private static final int CORNER_SIZE= 22;
+
+ /**
+ * Makes the given shell resizable on all platforms. The shell must have a {@link GridLayout}.
+ * If the shell is not resizable, this method enlarges the {@link GridLayout#marginWidth
+ * marginWidth} and {@link GridLayout#marginHeight marginHeight} and expects that the added area
+ * is not being shrunken or used in any way by other parties.
+ *
+ * @param shell the shell
+ */
+ public static void makeResizable(final Shell shell) {
+ if ((shell.getStyle() & SWT.RESIZE) != 0)
+ return;
+
+ GridLayout layout= ((GridLayout) shell.getLayout());
+ layout.marginWidth+= TRIM_SIZE;
+ layout.marginHeight+= TRIM_SIZE;
+
+ MouseListenerMix listenerMix= new MouseListenerMix(shell);
+ shell.addMouseMoveListener(listenerMix);
+ shell.addMouseTrackListener(listenerMix);
+ shell.addMouseListener(listenerMix);
+
+ shell.addPaintListener(new PaintListener() {
+ public void paintControl(PaintEvent e) {
+ Rectangle clientArea= shell.getClientArea();
+ int gap= - TRIM_SIZE / 2;
+ Geometry.expand(clientArea, gap, gap - 1, gap, gap - 1);
+ e.gc.setLineWidth(TRIM_SIZE);
+ e.gc.setForeground(e.display.getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW));
+ e.gc.drawRectangle(clientArea);
+ }
+ });
+ }
+}
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 a64b1cbd39a..4a66db2bc74 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
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008 IBM Corporation and others.
+ * Copyright (c) 2008, 2009 IBM Corporation 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
@@ -43,6 +43,7 @@ import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.jface.action.ToolBarManager;
+import org.eclipse.jface.internal.text.ResizableShellSupport;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.util.Geometry;
@@ -188,6 +189,10 @@ public abstract class AbstractInformationControl implements IInformationControl,
setColor(fContentComposite, foreground, background);
createStatusComposite(statusFieldText, toolBarManager, foreground, background);
+
+ if (fResizable) {
+ ResizableShellSupport.makeResizable(fShell);
+ }
}
private void createStatusComposite(final String statusFieldText, final ToolBarManager toolBarManager, Color foreground, Color background) {
@@ -555,6 +560,12 @@ public abstract class AbstractInformationControl implements IInformationControl,
if (fStatusComposite != null)
trim.height+= fStatusComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
+ if (fResizable) {
+ GridLayout shellLayout= (GridLayout) fShell.getLayout();
+ int w= shellLayout.marginWidth;
+ int h= shellLayout.marginHeight;
+ Geometry.expand(trim, w, w, h, h);
+ }
return trim;
}
diff --git a/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/CompletionProposalPopup.java b/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/CompletionProposalPopup.java
index 9b0f4622285..833f5dbb92b 100644
--- a/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/CompletionProposalPopup.java
+++ b/org.eclipse.jface.text/src/org/eclipse/jface/text/contentassist/CompletionProposalPopup.java
@@ -63,6 +63,7 @@ import org.eclipse.jface.bindings.keys.KeySequence;
import org.eclipse.jface.bindings.keys.SWTKeySupport;
import org.eclipse.jface.contentassist.IContentAssistSubjectControl;
import org.eclipse.jface.internal.text.InformationControlReplacer;
+import org.eclipse.jface.internal.text.ResizableShellSupport;
import org.eclipse.jface.internal.text.TableOwnerDrawSupport;
import org.eclipse.jface.preference.JFacePreferences;
import org.eclipse.jface.resource.JFaceResources;
@@ -601,6 +602,7 @@ class CompletionProposalPopup implements IContentAssistListener {
layout.marginHeight= 0;
layout.verticalSpacing= 1;
fProposalShell.setLayout(layout);
+ ResizableShellSupport.makeResizable(fProposalShell);
if (fContentAssistant.isStatusLineVisible()) {
createMessageText();
@@ -974,7 +976,7 @@ class CompletionProposalPopup implements IContentAssistListener {
*/
public boolean hasFocus() {
if (Helper.okToUse(fProposalShell)) {
- if ((fProposalShell.isFocusControl() || fProposalTable.isFocusControl()))
+ if ((fProposalShell.getDisplay().getActiveShell() == fProposalShell))
return true;
/*
* We have to delegate this query to the additional info controller

Back to the top