/*
* Copyright 2008 Eckhart Arnold (eckhart_arnold@hotmail.com).
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package de.eckhartarnold.client;
import com.google.gwt.event.dom.client.HasMouseDownHandlers;
import com.google.gwt.event.dom.client.HasMouseMoveHandlers;
import com.google.gwt.event.dom.client.HasMouseOutHandlers;
import com.google.gwt.event.dom.client.HasMouseOverHandlers;
import com.google.gwt.event.dom.client.HasMouseUpHandlers;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.event.dom.client.MouseMoveEvent;
import com.google.gwt.event.dom.client.MouseMoveHandler;
import com.google.gwt.event.dom.client.MouseOutEvent;
import com.google.gwt.event.dom.client.MouseOutHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.google.gwt.event.dom.client.MouseUpEvent;
import com.google.gwt.event.dom.client.MouseUpHandler;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.safehtml.shared.SafeHtml;
/**
* A "tool tip" widget.
*
* <p>A tool tip widget pops up a small yellow tool tip window
* if the user leaves the mouse still over a widget to which the
* tool tip is attached. This works only with widgets that source
* mouse events.
*
* <p>Optionally, a limit can be set to how many times the tool
* tip may appear. The purpose is to avoid menacing the user
* with constant re-appearances of the tool tip.
*/
public class Tooltip extends PopupPanel implements MouseDownHandler,
MouseOverHandler, MouseOutHandler, MouseMoveHandler, MouseUpHandler {
private class PopupTimer extends Timer {
int posX, posY;
final PositionCallback callback = new PositionCallback() {
public void setPosition(int offsetWidth, int offsetHeight) {
int width = Window.getClientWidth();
int height = Window.getClientHeight();
if (posX + offsetWidth > width) posX = width-offsetWidth;
if (posY + offsetHeight > height) posY = height-offsetHeight;
setPopupPosition(posX, posY);
}
};
public void run() {
timerExpired = true;
if (limit > 0) limit--;
setPopupPositionAndShow(callback);
}
}
private static final int X_OFFSET = 10;
private static final int Y_OFFSET = 10;
private static final int DEFAULT_DELAY = 1000;
private static Tooltip visible = null;
/**
* Adds a tool-tip to a widget. The widget must have
* <code>MouseOut</code> and <code>MouseOver</code> handlers. It is
* recommended that it also has <code>MouseMove, -Up</code> and
* <code>-Down</code> handlers.
*
* <p>Typical coding pattern:
* <p><code>Tooltip.addToWidget(new Tooltip("tip"), anyWidget)</code>
*
* @param t the tool-tip that shall be added
* @param w the widget to which the tool-tip shall be added
*/
public static void addToWidget(Tooltip t, Widget w) {
assert w instanceof HasMouseOutHandlers;
assert w instanceof HasMouseOverHandlers;
((HasMouseOutHandlers) w).addMouseOutHandler(t);
((HasMouseOverHandlers) w).addMouseOverHandler(t);
if (w instanceof HasMouseDownHandlers) {
((HasMouseDownHandlers) w).addMouseDownHandler(t);
}
if (w instanceof HasMouseUpHandlers) {
((HasMouseUpHandlers) w).addMouseUpHandler(t);
}
if (w instanceof HasMouseMoveHandlers) {
((HasMouseMoveHandlers) w).addMouseMoveHandler(t);
}
}
private int delay;
private final HTML tooltipText;
private final PopupTimer timer = new PopupTimer();
private boolean timerExpired = false;
private int limit = -1; // < 0 means no limit on the number of appearances!
/**
* Constructor of class <code>Tooltip</code>.
* @param htmlText the text of the tool tip.
*/
public Tooltip(String htmlText) {
super(true);
tooltipText = new HTML(htmlText);
this.setWidget(tooltipText);
addStyleName("tooltip");
delay = DEFAULT_DELAY;
}
/**
* Constructor of class <code>Tooltip</code>.
* @param htmlText the text of the tool tip.
*/
public Tooltip(SafeHtml htmlText) {
this(htmlText.asString());
}
/**
* Alternative constructor that allows also determining the delay after which
* the tool tip appears.
*
* @param htmlText the text of the tool tip
* @param delay the delay in milliseconds
*/
public Tooltip(String htmlText, int delay) {
this(htmlText);
this.delay = delay;
}
/**
* Alternative constructor that allows also determining the delay after which
* the tool tip appears.
*
* @param htmlText the text of the tool tip
* @param delay the delay in milliseconds
*/
public Tooltip(SafeHtml htmlText, int delay) {
this(htmlText.asString(), delay);
}
/* (non-Javadoc)
* @see com.google.gwt.user.client.ui.PopupPanel#hide()
*/
@Override
public void hide() {
super.hide();
visible = null;
}
/* (non-Javadoc)
* @see com.google.gwt.event.dom.client.MouseDownHandler#onMouseDown(com.google.gwt.event.dom.client.MouseDownEvent)
*/
public void onMouseDown(MouseDownEvent event) {
timer.cancel();
hide();
}
/* (non-Javadoc)
* @see com.google.gwt.event.dom.client.MouseOverHandler#onMouseOver(com.google.gwt.event.dom.client.MouseOverEvent)
*/
public void onMouseOver(MouseOverEvent event) {
Widget sender = (Widget) event.getSource();
timer.posX = sender.getAbsoluteLeft() + sender.getOffsetWidth() - X_OFFSET;
timer.posY = sender.getAbsoluteTop() + Toolbox.getOffsetHeight(sender) - Y_OFFSET;
timerExpired = false;
if (limit != 0) timer.schedule(delay);
}
/* (non-Javadoc)
* @see com.google.gwt.event.dom.client.MouseOutHandler#onMouseOut(com.google.gwt.event.dom.client.MouseOutEvent)
*/
public void onMouseOut(MouseOutEvent event) {
timer.cancel();
hide();
timerExpired = false;
}
/* (non-Javadoc)
* @see com.google.gwt.event.dom.client.MouseMoveHandler#onMouseMove(com.google.gwt.event.dom.client.MouseMoveEvent)
*/
public void onMouseMove(MouseMoveEvent event) {
if (visible != null) {
visible.hide();
} else if (!timerExpired) {
timer.posX = event.getClientX() + X_OFFSET;
timer.posY = event.getClientY() + Y_OFFSET;
if (limit != 0) timer.schedule(delay);
}
}
/* (non-Javadoc)
* @see com.google.gwt.event.dom.client.MouseUpHandler#onMouseUp(com.google.gwt.event.dom.client.MouseUpEvent)
*/
public void onMouseUp(MouseUpEvent event) {
timer.cancel();
hide();
}
/**
* Set the maximum number of re-appearances for the tool tip.
* @param limit the maximum number of re-appearances
*/
public void setMaxAppearances(int limit) {
this.limit = limit;
}
/* (non-Javadoc)
* @see com.google.gwt.user.client.ui.PopupPanel#show()
*/
@Override
public void show() {
if (visible != null && visible != this) {
visible.hide();
}
visible = this;
super.show();
}
}