Java tutorial
/* Copyright (c) The m-m-m Team, Licensed under the Apache License, Version 2.0 * http://www.apache.org/licenses/LICENSE-2.0 */ package net.sf.mmm.client.ui.gwt.widgets; import net.sf.mmm.client.ui.api.attribute.AttributeReadLengthProperty; import net.sf.mmm.client.ui.api.attribute.AttributeWriteClosable; import net.sf.mmm.client.ui.api.attribute.AttributeWriteMaximizable; import net.sf.mmm.client.ui.api.attribute.AttributeWriteMaximized; import net.sf.mmm.client.ui.api.attribute.AttributeWriteMovable; import net.sf.mmm.client.ui.api.attribute.AttributeWriteResizable; import net.sf.mmm.client.ui.api.common.CssStyles; import net.sf.mmm.client.ui.api.common.Length; import net.sf.mmm.client.ui.api.common.LengthProperty; import net.sf.mmm.client.ui.gwt.widgets.handler.HandlerRegistrationCollector; import net.sf.mmm.util.gwt.api.JavaScriptUtil; import net.sf.mmm.util.lang.api.Direction; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.EventTarget; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.Style.Position; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.safehtml.shared.SafeHtml; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Event.NativePreviewEvent; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.InlineLabel; import com.google.gwt.user.client.ui.IsWidget; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.Widget; /** * This class is a {@link com.google.gwt.user.client.ui.Widget} that represents a <em>popup</em>. It extends * {@link PopupPanel} with additional features such as being resizable. It is an alternative to * {@link com.google.gwt.user.client.ui.DialogBox}. * * @author Joerg Hohwiller (hohwille at users.sourceforge.net) * @since 1.0.0 */ public class PopupWindow extends PopupPanel implements AttributeWriteResizable, AttributeWriteMovable, AttributeWriteClosable, AttributeWriteMaximized, AttributeWriteMaximizable, AttributeReadLengthProperty { /** The {@link HandlerRegistrationCollector} or <code>null</code> to ignore {@link HandlerRegistration}s. */ private final HandlerRegistrationCollector registrationCollector; /** The main panel. */ private final VerticalFlowPanel mainPanel; /** The content panel. */ private final VerticalFlowPanel contentPanel; /** The title panel. */ private final HorizontalFlowPanel titleBar; /** The title label. */ private final InlineLabel title; /** The button to close the window. */ private final Button closeButton; /** The button to {@link #setMaximized(boolean) (un)maximize} the window. */ private final SimpleToggleButton maximizeButton; /** @see #getButtonPanel() */ private final ButtonPanel buttonPanel; // /** The footer panel. */ // private final HorizontalFlowPanel footerBar; /** The left border of the window */ private final Widget borderWest; /** The right border of the window */ private final Widget borderEast; /** The bottom border of the window */ private final Widget borderSouth; /** The bottom left corner of the window */ private final Widget borderSouthWest; /** The bottom right corner of the window */ private final Widget borderSouthEast; /** The top border of the window */ private final Widget borderNorth; /** The top left corner of the window */ private final Widget borderNorthWest; /** The top right corner of the window */ private final Widget borderNorthEast; /** @see #isResizable() */ private boolean resizable; /** @see #isMovable() */ private boolean movable; /** @see #isClosable() */ private boolean closable; /** @see #isMaximizable() */ private boolean maximizable; /** @see #isMaximized() */ private boolean maximized; /** * The saved X-{@link #setPopupPosition(int, int) position} to restore after e.g. * {@link #setMaximized(boolean)}. */ private int savedX; /** * The saved Y-{@link #setPopupPosition(int, int) position} to restore after e.g. * {@link #setMaximized(boolean)}. */ private int savedY; /** The saved {@link #getOffsetWidth() width} to restore after e.g. {@link #setMaximized(boolean)}. */ private int savedWidth; /** The saved {@link #getOffsetHeight() height} to restore after e.g. {@link #setMaximized(boolean)}. */ private int savedHeight; /** * The {@link Element} outside the {@link PopupWindow} that had the focus before the {@link PopupWindow} was * {@link #show() shown}. */ private Element focusedElement; /** @see #getGlassPanel() */ private Element glassPanel; /** * The constructor. */ public PopupWindow() { this(false); } /** * The constructor. * * @param autoHide - see {@link #setAutoHideEnabled(boolean)}. */ public PopupWindow(boolean autoHide) { this(autoHide, true); } /** * The constructor. * * @param autoHide - see {@link #setAutoHideEnabled(boolean)}. * @param modal - see {@link #setModal(boolean)}. */ public PopupWindow(boolean autoHide, boolean modal) { this(autoHide, modal, null); } /** * The constructor. * * @param autoHide - see {@link #setAutoHideEnabled(boolean)}. * @param modal - see {@link #setModal(boolean)}. * @param registrationCollector the {@link HandlerRegistrationCollector} used to collect * {@link HandlerRegistration}s. */ public PopupWindow(boolean autoHide, boolean modal, HandlerRegistrationCollector registrationCollector) { super(autoHide, modal); this.registrationCollector = registrationCollector; if (modal) { setGlassStyleName(CssStyles.GLASS_PANEL); setGlassEnabled(true); getGlassElement().getStyle().setPosition(Position.FIXED); } this.resizable = true; this.maximized = false; this.maximizable = true; setStyleName(CssStyles.WINDOW); this.title = new InlineLabel(); this.title.setStyleName(CssStyles.WINDOW_TITLE); SafeHtml iconMarkup = HtmlTemplates.INSTANCE.iconMarkup(CssStyles.CLOSE); this.closeButton = new Button(iconMarkup); this.closeButton.setStyleName(CssStyles.BUTTON); ClickHandler closeHandler = new ClickHandler() { @Override public void onClick(ClickEvent event) { hide(); } }; this.closeButton.addClickHandler(closeHandler); iconMarkup = HtmlTemplates.INSTANCE.iconMarkup(CssStyles.MAXIMIZE); this.maximizeButton = new SimpleToggleButton(); this.maximizeButton.setHTML(iconMarkup); this.maximizeButton.setStyleName(CssStyles.BUTTON); this.maximizeButton.addStyleName(CssStyles.TOGGLE_BUTTON); ClickHandler maximizeHandler = new ClickHandler() { @Override public void onClick(ClickEvent event) { setMaximized(!PopupWindow.this.maximized); } }; this.maximizeButton.addClickHandler(maximizeHandler); this.titleBar = new HorizontalFlowPanel(); this.titleBar.addStyleName(CssStyles.WINDOW_TITLE_BAR); this.titleBar.addStyleName(CssStyles.MOVABLE); this.movable = true; this.titleBar.add(this.title); this.titleBar.add(this.maximizeButton); this.titleBar.add(this.closeButton); this.contentPanel = new VerticalFlowPanel(); this.contentPanel.addStyleName(CssStyles.WINDOW_CONTENT); // borders for resizing... this.borderWest = new CssDivWidget(CssStyles.BORDER_WEST); this.borderEast = new CssDivWidget(CssStyles.BORDER_EAST); this.borderSouth = new CssDivWidget(CssStyles.BORDER_SOUTH); this.borderSouthWest = new CssDivWidget(CssStyles.BORDER_SOUTH_WEST); this.borderSouthEast = new CssDivWidget(CssStyles.BORDER_SOUTH_EAST); this.borderNorth = new CssDivWidget(CssStyles.BORDER_NORTH); this.borderNorthWest = new CssDivWidget(CssStyles.BORDER_NORTH_WEST); this.borderNorthEast = new CssDivWidget(CssStyles.BORDER_NORTH_EAST); this.mainPanel = new VerticalFlowPanel(); this.mainPanel.add(this.titleBar); this.mainPanel.add(this.contentPanel); this.buttonPanel = new ButtonPanel(); this.mainPanel.add(this.buttonPanel); // this.footerBar = new HorizontalFlowPanel(); // this.footerBar.addStyleName(CssStyles.WINDOW_FOOTER_BAR); // this.mainPanel.add(this.footerBar); this.mainPanel.add(this.borderWest); this.mainPanel.add(this.borderEast); this.mainPanel.add(this.borderSouth); this.mainPanel.add(this.borderSouthWest); this.mainPanel.add(this.borderSouthEast); this.mainPanel.add(this.borderNorth); this.mainPanel.add(this.borderNorthWest); this.mainPanel.add(this.borderNorthEast); super.add(this.mainPanel); // setStyleName(getContainerElement(), "popupContent"); addMouseHandler(this.title, null); addMouseHandler(this.borderEast, Direction.EAST); addMouseHandler(this.borderSouth, Direction.SOUTH); addMouseHandler(this.borderSouthEast, Direction.SOUTH_EAST); addMouseHandler(this.borderSouthWest, Direction.SOUTH_WEST); addMouseHandler(this.borderWest, Direction.WEST); addMouseHandler(this.borderNorth, Direction.NORTH); addMouseHandler(this.borderNorthEast, Direction.NORTH_EAST); addMouseHandler(this.borderNorthWest, Direction.NORTH_WEST); } /** * {@inheritDoc} */ @Override public boolean isResizable() { return this.resizable; } /** * {@inheritDoc} */ @Override public void setResizable(boolean resizable) { if (this.resizable == resizable) { return; } if (!this.maximized) { doSetResizable(resizable); } this.resizable = resizable; } /** * @param newResizable - see {@link #setResizable(boolean)}. */ private void doSetResizable(boolean newResizable) { this.borderEast.setVisible(newResizable); this.borderNorth.setVisible(newResizable); this.borderNorthEast.setVisible(newResizable); this.borderNorthWest.setVisible(newResizable); this.borderSouth.setVisible(newResizable); this.borderSouthEast.setVisible(newResizable); this.borderSouthWest.setVisible(newResizable); this.borderWest.setVisible(newResizable); } /** * {@inheritDoc} */ @Override public boolean isMovable() { return this.movable; } /** * {@inheritDoc} */ @Override public void setMovable(boolean movable) { if (this.movable == movable) { return; } if (movable) { if (!this.maximized) { this.titleBar.addStyleName(CssStyles.MOVABLE); } } else { this.titleBar.removeStyleName(CssStyles.MOVABLE); } this.movable = movable; } /** * {@inheritDoc} */ @Override public boolean isClosable() { return this.closable; } /** * {@inheritDoc} */ @Override public void setClosable(boolean closable) { if (this.closable == closable) { return; } this.closable = closable; this.closeButton.setVisible(closable); } /** * {@inheritDoc} */ @Override public boolean isMaximized() { return this.maximized; } /** * {@inheritDoc} */ @Override public void setMaximized(boolean maximized) { if (this.maximized == maximized) { return; } if (maximized) { this.savedX = getAbsoluteLeft(); this.savedY = getAbsoluteTop(); this.savedWidth = getOffsetWidth(); this.savedHeight = getOffsetHeight(); setPopupPosition(Window.getScrollLeft(), Window.getScrollTop()); setPixelSize(Window.getClientWidth(), Window.getClientHeight()); if (this.movable) { this.titleBar.removeStyleName(CssStyles.MOVABLE); } if (this.resizable) { doSetResizable(false); } } else { setPopupPosition(this.savedX, this.savedY); setPixelSize(this.savedWidth, this.savedHeight); if (this.movable) { this.titleBar.addStyleName(CssStyles.MOVABLE); } if (this.resizable) { doSetResizable(true); } } this.maximized = maximized; this.maximizeButton.setValue(Boolean.valueOf(maximized), false); } /** * {@inheritDoc} */ @Override public boolean isMaximizable() { return this.maximizable; } /** * {@inheritDoc} */ @Override public void setMaximizable(boolean maximizable) { if (this.maximizable == maximizable) { return; } this.maximizeButton.setVisible(maximizable); this.maximizable = maximizable; } /** * {@inheritDoc} */ @Override public Length getLength(LengthProperty property) { String value = getElement().getStyle().getProperty(property.getMemberName()); if ((value == null) || (value.length() == 0)) { return property.getDefaultValue(); } return new Length(value); } /** * Adds a {@link PopupMouseHandler} to the given {@link Widget} based on the given {@link Direction}. * * @param widget is the {@link Widget} where to add the {@link PopupMouseHandler} to. * @param resizeDirection is the resize {@link Direction} or <code>null</code> for move. */ private void addMouseHandler(Widget widget, Direction resizeDirection) { PopupMouseHandler handler = new PopupMouseHandler(this, resizeDirection); handler.register(widget, this.registrationCollector); } /** * {@inheritDoc} */ @Override public void add(Widget w) { this.contentPanel.add(w); } /** * {@inheritDoc} */ @Override public void add(IsWidget child) { this.contentPanel.add(child); } /** * {@inheritDoc} */ @Override public boolean remove(IsWidget child) { return this.contentPanel.remove(child); } /** * {@inheritDoc} */ @Override public boolean remove(Widget w) { return this.contentPanel.remove(w); } /** * @param titleText is the text to be displayed in the title bar of the popup window. */ public void setTitleText(String titleText) { this.title.setText(titleText); } /** * {@inheritDoc} */ @Override protected void onPreviewNativeEvent(NativePreviewEvent event) { int eventType = event.getTypeInt(); if (eventType == Event.ONKEYPRESS) { NativeEvent nativeEvent = event.getNativeEvent(); int keyCode = nativeEvent.getKeyCode(); if ((keyCode == KeyCodes.KEY_ESCAPE) && (this.closable)) { hide(); } if (keyCode == KeyCodes.KEY_TAB) { if (nativeEvent.getShiftKey()) { EventTarget target = nativeEvent.getEventTarget(); if (Element.is(target)) { Element targetElement = Element.as(target); if ((targetElement == getFirstFocusElement()) || !getElement().isOrHasChild(targetElement)) { event.cancel(); getLastFocusElement().focus(); } } } else { EventTarget target = nativeEvent.getEventTarget(); if (Element.is(target)) { Element targetElement = Element.as(target); if ((targetElement == getLastFocusElement()) || !getElement().isOrHasChild(targetElement)) { event.cancel(); getFirstFocusElement().focus(); } } } } } } /** * @return the first {@link Element} of this popup that is tab-able to get the focus. */ private Element getFirstFocusElement() { return JavaScriptUtil.getInstance().getFocusable(getElement(), true, false); } /** * @return the last {@link Element} of this popup that is tab-able to get the focus. */ private Element getLastFocusElement() { return JavaScriptUtil.getInstance().getFocusable(getElement(), true, true); } /** * @return the main panel of this {@link PopupWindow}. This panel contains the borders, the title-bar and * the {@link #getContentPanel() content-panel}. */ VerticalFlowPanel getMainPanel() { return this.mainPanel; } /** * @return the {@link ButtonPanel} located at the bottom of the {@link PopupWindow} where buttons shall be * added. */ public ButtonPanel getButtonPanel() { return this.buttonPanel; } /** * @return the content panel where the content of the popup window should be added to. */ public VerticalFlowPanel getContentPanel() { return this.contentPanel; } /** * @return the glassPanel */ protected Element getGlassPanel() { if (this.glassPanel == null) { this.glassPanel = Document.get().createDivElement(); this.glassPanel.setClassName(CssStyles.GLASS_PANEL); } return this.glassPanel; } /** * {@inheritDoc} */ @Override public void show() { if (isShowing()) { return; } super.show(); // if (isModal()) { // Document.get().getBody().appendChild(getGlassPanel()); // } this.focusedElement = JavaScriptUtil.getInstance().getFocusedElement(); Scheduler.get().scheduleDeferred(new ScheduledCommand() { @Override public void execute() { Element focusable = JavaScriptUtil.getInstance() .getFocusable(PopupWindow.this.contentPanel.getElement(), true, false); if (focusable == null) { focusable = getFirstFocusElement(); } if (focusable != null) { focusable.focus(); } } }); } /** * {@inheritDoc} */ @Override public void hide() { if (!isShowing()) { return; } super.hide(); // if (isModal()) { // Document.get().getBody().removeChild(getGlassPanel()); // } if (this.focusedElement != null) { this.focusedElement.focus(); this.focusedElement = null; } } }