Java tutorial
/* * Copyright 2008 Isaac Truett. * * 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 com.googlecode.simplegwt.contextualpopup.client.ui; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.HasClickHandlers; 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.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.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.DecoratedPopupPanel; import com.google.gwt.user.client.ui.FocusPanel; import com.google.gwt.user.client.ui.HasValue; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.user.client.ui.PopupPanel.PositionCallback; import com.googlecode.simplegwt.initialization.client.ui.InitializableComposite; /** * A context-sensitive popup that appears when the user mouses over a {@link Widget}. The popup * disappears if the user's mouse leaves the popup or if the user clicks on the {@link Widget}. * * @param <T> the type of value contained in this popup * @since 1.0 */ public abstract class ContextualPopup<T> extends InitializableComposite implements HasValue<T>, HasMouseOverHandlers, HasMouseOutHandlers { /** * Handles hiding the popup when the mouse leaves. */ private class PopupMouseHandler implements MouseOverHandler, MouseOutHandler { /** * @see com.google.gwt.event.dom.client.MouseOutHandler#onMouseOut(com.google.gwt.event.dom.client.MouseOutEvent) */ public void onMouseOut(MouseOutEvent event) { hide(); } /** * @see com.google.gwt.event.dom.client.MouseOverHandler#onMouseOver(com.google.gwt.event.dom.client.MouseOverEvent) */ public void onMouseOver(MouseOverEvent event) { hideTimer.cancel(); } } /** * Handles showing the popup when the user mouses over the contextual <code>Widget</code> and * hiding the popup if the user clicks on the <code>Widget</code>. */ private final class WidgetContextMouseHandler implements MouseOverHandler, MouseOutHandler, MouseMoveHandler, ClickHandler { private int currentX; private int currentY; private final ContextualPopup<?> contextualPopup; private final Timer showTimer = new Timer() { @Override public void run() { contextualPopup.show(currentX, currentY); contextualPopup.hideTimer.cancel(); } }; public WidgetContextMouseHandler(final ContextualPopup<?> contextualPopup) { super(); this.contextualPopup = contextualPopup; } public void onClick(final ClickEvent event) { contextualPopup.hide(); showTimer.cancel(); } public void onMouseMove(final MouseMoveEvent event) { currentX = event.getClientX(); currentY = event.getClientY(); } public void onMouseOut(final MouseOutEvent event) { showTimer.cancel(); contextualPopup.hide(); } public void onMouseOver(final MouseOverEvent event) { showTimer.schedule(contextualPopup.getShowDelay()); } } private static final int DEFAULT_HIDE_DELAY = 500; private static final int DEFAULT_SHOW_DELAY = 250; private T value; private int showDelay = DEFAULT_SHOW_DELAY; private int hideDelay = DEFAULT_HIDE_DELAY; private final Timer hideTimer = new Timer() { @Override public void run() { getPopupPanel().hide(); } }; private PopupPanel popupPanel; private FocusPanel focusPanel; /** * Creates a new <code>ContextualPopup</code>. * * @param value the value contained in this popup */ public ContextualPopup(final T value) { super(); assert value != null : "Cannot create a ContextualPopup with a null value"; setValue(value); } /** * @see com.google.gwt.event.dom.client.HasMouseOutHandlers#addMouseOutHandler(com.google.gwt.event.dom.client.MouseOutHandler) */ public HandlerRegistration addMouseOutHandler(final MouseOutHandler handler) { return addHandler(handler, MouseOutEvent.getType()); } /** * @see com.google.gwt.event.dom.client.HasMouseOverHandlers#addMouseOverHandler(com.google.gwt.event.dom.client.MouseOverHandler) */ public HandlerRegistration addMouseOverHandler(final MouseOverHandler handler) { return addHandler(handler, MouseOverEvent.getType()); } /** * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler) */ public HandlerRegistration addValueChangeHandler(final ValueChangeHandler<T> handler) { return addHandler(handler, ValueChangeEvent.getType()); } /** * @see com.google.gwt.user.client.ui.HasValue#getValue() */ public T getValue() { return value; } /** * Registers this <code>ContextualPopup</code> as a {@link MouseOverHandler}, a * {@link MouseOutHandler}, a {@link MouseMoveHandler}, and a {@link ClickHandler} on the * specified {@link Widget}. * * @param <H> artificial type comprising the required event hooks * @param widget the <code>Widget</code> context for the popup */ public <H extends HasMouseOutHandlers & HasMouseOverHandlers & HasMouseMoveHandlers & HasClickHandlers> void registerOn( final H widget) { final WidgetContextMouseHandler handler = new WidgetContextMouseHandler(ContextualPopup.this); widget.addMouseOverHandler(handler); widget.addMouseOutHandler(handler); widget.addMouseMoveHandler(handler); widget.addClickHandler(handler); } /** * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object) */ public void setValue(final T value) { this.value = value; } /** * @see com.google.gwt.user.client.ui.HasValue#setValue(java.lang.Object, boolean) */ public void setValue(final T value, boolean fireEvents) { final T oldValue = getValue(); setValue(value); if (fireEvents) { ValueChangeEvent.fireIfNotEqual(this, oldValue, value); } } /** * Called when the popup is initialized. Subclasses can add content to the * <code>FocusPanel</code>. * * @param panel */ protected abstract void buildPopup(final FocusPanel panel); /** * Creates and configures a new {@link PopupPanel}. Override to change {@link PopupPanel} * implementation, disable animation, etc. * * @return the contextual {@link PopupPanel} */ protected PopupPanel createPopupPanel() { final DecoratedPopupPanel newPopupPanel = new DecoratedPopupPanel(); newPopupPanel.setAnimationEnabled(true); return newPopupPanel; } /** * @see com.googlecode.simplegwt.initialization.client.ui.InitializableComposite#onInitialize() */ @Override protected void onInitialize() { popupPanel = createPopupPanel(); focusPanel = new FocusPanel(); popupPanel.add(focusPanel); buildPopup(focusPanel); focusPanel.addMouseOverHandler(new PopupMouseHandler()); focusPanel.addMouseOutHandler(new PopupMouseHandler()); } /** * Show the popup. * * @param y the y coordinate relative to which the popup is shown * @param x the x coordinate relative to which the popup is shown */ protected void show(final int x, final int y) { getPopupPanel().setPopupPositionAndShow(new PositionCallback() { public void setPosition(final int offsetWidth, final int offsetHeight) { getPopupPanel().setPopupPosition(x + 5, Math.max(y - offsetHeight, 0)); } }); } private PopupPanel getPopupPanel() { if (!isInitialized()) { initialize(); } return popupPanel; } private void hide() { hideTimer.schedule(getHideDelay()); } /** * @return the showDelay */ public int getShowDelay() { return showDelay; } /** * @param showDelay the showDelay to set */ public void setShowDelay(final int showDelay) { this.showDelay = showDelay; } /** * @return the hideDelay */ public int getHideDelay() { return hideDelay; } /** * @param hideDelay the hideDelay to set */ public void setHideDelay(final int hideDelay) { this.hideDelay = hideDelay; } }