/*******************************************************************************
* Copyright (c) 2000, 2005 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.gef.internal.ui.palette.editparts;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseEvent;
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.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.events.ShellListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.geometry.Dimension;
class EditPartTipHelper
extends org.eclipse.draw2d.PopUpHelper
{
private static EditPartTipHelper currentHelper;
private ShellListener shellListener;
private static void setHelper(EditPartTipHelper helper) {
if (currentHelper != null && currentHelper != helper && currentHelper.isShowing())
currentHelper.hide();
currentHelper = helper;
}
public EditPartTipHelper(Control c) {
super(c, SWT.ON_TOP | SWT.TOOL | SWT.NO_TRIM);
}
/**
* Sets the LightWeightSystem object's contents
* to the passed tooltip, and displays the tip at
* the coordianates specified by tipPosX and tipPosY. The given coordinates will be
* adjusted if the tip cannot be completely visible on the screen.
*
* @param tip The tool tip to be displayed.
* @param tipPosX X coordiante of tooltip to be displayed
* @param tipPosY Y coordinate of tooltip to be displayed
*/
public void displayToolTipAt(IFigure tip, int tipPosX, int tipPosY) {
if (tip != null) {
// Adjust the position if the tip will not be completely visible on the screen
int shiftX = 0;
int shiftY = 0;
Dimension tipSize = tip.getPreferredSize();
getShell();
tipSize = tipSize.getExpanded(getShellTrimSize());
org.eclipse.swt.graphics.Rectangle area = control.getDisplay().getClientArea();
org.eclipse.swt.graphics.Point end = new org.eclipse.swt.graphics.Point(
tipPosX + tipSize.width, tipPosY + tipSize.height);
if (!area.contains(end)) {
shiftX = end.x - (area.x + area.width);
shiftY = end.y - (area.y + area.height);
shiftX = shiftX < 0 ? 0 : shiftX;
shiftY = shiftY < 0 ? 0 : shiftY;
}
tipPosX -= shiftX;
tipPosY -= shiftY;
// Display the tip
EditPartTipHelper.setHelper(this);
getLightweightSystem().setContents(tip);
setShellBounds(tipPosX, tipPosY, tipSize.width, tipSize.height);
show();
getShell().setCapture(true);
}
}
public void dispose() {
if (shellListener != null) {
control.getShell().removeShellListener(shellListener);
shellListener = null;
}
super.dispose();
}
/**
* @see org.eclipse.draw2d.PopUpHelper#hide()
*/
protected void hide() {
super.hide();
currentHelper = null;
}
protected void hookShellListeners() {
/* If the cursor leaves the tip window, hide the tooltip and
dispose of its shell */
getShell().addMouseTrackListener(new MouseTrackAdapter() {
public void mouseExit(MouseEvent e) {
getShell().setCapture(false);
dispose();
}
});
/* If the mouseExit listener does not get called,
dispose of the shell if the cursor is no longer in the
tooltip. This occurs in the rare case that a mouseEnter
is not received on the tooltip when it appears.*/
getShell().addMouseMoveListener(new MouseMoveListener() {
public void mouseMove(MouseEvent e) {
Point eventPoint = getShell().toDisplay(new Point(e.x, e.y));
if (!getShell().getBounds().contains(eventPoint)) {
if (isShowing())
getShell().setCapture(false);
dispose();
}
}
});
//This is to dispose of the tooltip when the user ALT-TABs to another window.
if (shellListener == null) {
shellListener = new ShellAdapter() {
public void shellDeactivated(ShellEvent event) {
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
Shell active = Display.getCurrent().getActiveShell();
if (getShell() == active || control.getShell() == active || getShell().isDisposed())
return;
if (isShowing())
getShell().setCapture(false);
dispose();
}
});
}
};
control.getShell().addShellListener(shellListener);
getShell().addShellListener(shellListener);
}
/* Workaround for GTK Bug - Control.setCapture(boolean) not implemented:
If the cursor is not over the shell when it is first painted,
hide the tooltip and dispose of the shell. */
if (SWT.getPlatform().equals("gtk")) { //$NON-NLS-1$
getShell().addPaintListener(new PaintListener() {
public void paintControl(PaintEvent event) {
Point cursorLoc = Display.getCurrent().getCursorLocation();
if (!getShell().getBounds().contains(cursorLoc)) {
// This must be run asynchronously. If not, other paint
// listeners may attempt to paint on a disposed control.
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
if (isShowing())
getShell().setCapture(false);
dispose();
}
});
}
}
});
}
}
public static boolean isCurrent(EditPartTipHelper helper) {
return currentHelper != null && helper == currentHelper;
}
}