/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package com.eas.window; import com.eas.core.XElement; import com.eas.window.events.ActivateEvent; import com.eas.window.events.ActivateHandler; import com.eas.window.events.BeforeCloseEvent; import com.eas.window.events.BeforeCloseHandler; import com.eas.window.events.ClosedEvent; import com.eas.window.events.ClosedHandler; import com.eas.window.events.DeactivateEvent; import com.eas.window.events.DeactivateHandler; import com.eas.window.events.MaximizeEvent; import com.eas.window.events.MaximizeHandler; import com.eas.window.events.MinimizeEvent; import com.eas.window.events.MinimizeHandler; import com.eas.window.events.MoveEvent; import com.eas.window.events.MoveHandler; import com.eas.window.events.RestoreEvent; import com.eas.window.events.RestoreHandler; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Node; import com.google.gwt.dom.client.Style; 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.MouseUpEvent; import com.google.gwt.event.dom.client.MouseUpHandler; import com.google.gwt.event.logical.shared.OpenEvent; import com.google.gwt.event.logical.shared.OpenHandler; import com.google.gwt.event.logical.shared.ResizeEvent; import com.google.gwt.event.logical.shared.ResizeHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HasAnimation; import com.google.gwt.user.client.ui.HasHTML; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.dom.client.Document; /** * * @author mg */ public class WindowPanel extends DraggablePanel implements WindowUI, HasAnimation { protected static final String ACTIVE_SUFFIX_NAMNE = "active"; public static class Caption extends HTML { public Caption(String aHtml) { super(); setHTML(aHtml); setStyleName("window-caption"); } } protected Widget captionWidget; protected VerticalPanel verticalPanel; protected JavaScriptObject transitionOnResizer; protected Widget verticalPanelContent; protected boolean animationEnabled = true; protected boolean movable = true; protected boolean maximized; protected boolean minimized; protected boolean active; protected boolean maximizable = true; protected boolean minimizable = true; protected boolean closable = true; public WindowPanel() { super(true); addDomHandler(new MouseDownHandler() { @Override public void onMouseDown(MouseDownEvent event) { focus(); } }, MouseDownEvent.getType()); verticalPanel = new VerticalPanel(); super.setWidget(verticalPanel); setCaptionWidget(new Caption("")); setUndecorated(false); getElement().addClassName("window-panel"); getElement().<XElement> cast().addResizingTransitionEnd(this); getMovableTarget().getElement().<XElement> cast().addResizingTransitionEnd(this); } @Override public HasHTML getCaptionWidget() { if (captionWidget instanceof HasHTML) { return (HasHTML) captionWidget; } else { return null; } } protected HandlerRegistration mdHandler; protected HandlerRegistration muHandler; protected HandlerRegistration mmHandler; protected int mouseScreenX; protected int mouseScreenY; protected int targetScrollLeft; protected int targetScrollTop; protected boolean dragged; @Override public final void setCaptionWidget(HasHTML aCaptionWidget) { if (captionWidget != aCaptionWidget) { if (captionWidget != null) { captionWidget.removeFromParent(); } if (mdHandler != null) { mdHandler.removeHandler(); } if (muHandler != null) { muHandler.removeHandler(); } if (mmHandler != null) { mmHandler.removeHandler(); } if (aCaptionWidget instanceof Widget) { captionWidget = (Widget) aCaptionWidget; } else { captionWidget = new Caption(aCaptionWidget.getHTML()); } if (captionWidget != null) { mdHandler = captionWidget.addDomHandler(new MouseDownHandler() { @Override public void onMouseDown(MouseDownEvent event) { event.preventDefault(); event.stopPropagation(); focus(); if (movable && !maximized) { DOM.setCapture(captionWidget.getElement()); mouseScreenX = event.getScreenX(); mouseScreenY = event.getScreenY(); String tLeft = getMovableTarget().getElement().getStyle().getLeft(); targetScrollLeft = Integer.parseInt(tLeft.substring(0, tLeft.length() - 2)); String tTop = getMovableTarget().getElement().getStyle().getTop(); targetScrollTop = Integer.parseInt(tTop.substring(0, tTop.length() - 2)); } } }, MouseDownEvent.getType()); muHandler = captionWidget.addDomHandler(new MouseUpHandler() { @Override public void onMouseUp(MouseUpEvent event) { dragged = false; event.preventDefault(); event.stopPropagation(); if (movable && !maximized) { DOM.releaseCapture(captionWidget.getElement()); endMoving(); } } }, MouseUpEvent.getType()); mmHandler = captionWidget.addDomHandler(new MouseMoveHandler() { @Override public void onMouseMove(MouseMoveEvent event) { if (movable && !maximized) { if (DOM.getCaptureElement() == captionWidget.getElement()) { event.preventDefault(); event.stopPropagation(); int dx = event.getScreenX() - mouseScreenX; int dy = event.getScreenY() - mouseScreenY; if (!dragged && (dx != 0 || dy != 0)) { dragged = true; beginMoving(); } setPosition(targetScrollLeft + dx >= 0 ? targetScrollLeft + dx : 0, targetScrollTop + dy >= 0 ? targetScrollTop + dy : 0); } } } }, MouseMoveEvent.getType()); verticalPanel.insert(captionWidget, 0); } } } @Override protected void decorate() { super.decorate(); content.setStyleName("content-decor"); if (isActive()) { content.addStyleDependentName(ACTIVE_SUFFIX_NAMNE); } else { content.removeStyleDependentName(ACTIVE_SUFFIX_NAMNE); } if (captionWidget != null) { captionWidget.getElement().getStyle().clearDisplay(); } } @Override protected void undecorate() { super.undecorate(); content.getElement().removeClassName("content-decor"); content.getElement().removeClassName("content-decor-active"); if (captionWidget != null) { captionWidget.getElement().getStyle().setDisplay(Style.Display.NONE); } } @Override public void setWidget(Widget w) { if (verticalPanelContent != null) { verticalPanelContent.getElement().<XElement> cast().removeTransitionEndListener(transitionOnResizer); verticalPanelContent.getElement().removeClassName("window-content"); verticalPanelContent.removeFromParent(); } verticalPanelContent = w; if (verticalPanelContent != null) { transitionOnResizer = verticalPanelContent.getElement().<XElement> cast().addResizingTransitionEnd(this); verticalPanel.add(verticalPanelContent); verticalPanelContent.getElement().addClassName("window-content"); } if (isAttached()) { onResize(); } } @Override public Widget getWidget() { return verticalPanelContent; } @Override protected boolean isNresizable() { return resizable && !maximized && !minimized; } @Override protected boolean isSresizable() { return resizable && !maximized && !minimized; } @Override protected boolean isWresizable() { return resizable && !maximized; } @Override protected boolean isEresizable() { return resizable && !maximized; } @Override public boolean isMinimized() { return minimized; } @Override public boolean isMaximized() { return maximized; } @Override public boolean isMinimizable() { return minimizable; } @Override public void setMinimizable(boolean minimizable) { this.minimizable = minimizable; } @Override public void setClosable(boolean closable) { this.closable = closable; } @Override public boolean isClosable() { return closable; } @Override public boolean isMaximizable() { return maximizable; } @Override public void setMaximizable(boolean maximizable) { this.maximizable = maximizable; } @Override public void maximize() { if (!maximized) { restoreSnapshot(); maximized = true; updateDecorCursors(); snapshotMetrics(); // editing Element movableElement = getMovableTarget().getElement(); Style targetStyle = getWidget().getElement().getStyle(); // content int leftInset = getWidget().getElement().getAbsoluteLeft() - movableElement.getAbsoluteLeft(); int rightInset = movableElement.getAbsoluteRight() - getWidget().getElement().getAbsoluteRight(); int hInsets = leftInset + rightInset; int topInset = getWidget().getElement().getAbsoluteTop() - movableElement.getAbsoluteTop(); int bottomInset = movableElement.getAbsoluteBottom() - getWidget().getElement().getAbsoluteBottom(); int vInsets = topInset + bottomInset; Element parentElement = getMovableTarget().getParent().getElement(); int parentScrollWidth = parentElement.getScrollWidth(); int parentScrollHeight; if (parentElement == Document.get().getBody())// Some browsers // return incorrect // height for body // element { parentScrollHeight = Document.get().getClientHeight(); } else { parentScrollHeight = parentElement.getScrollHeight(); } targetStyle.setWidth(parentScrollWidth - hInsets, Style.Unit.PX); targetStyle.setHeight(parentScrollHeight - vInsets, Style.Unit.PX); // editing targetStyle = movableElement.getStyle(); // window targetStyle.setLeft(0, Style.Unit.PX); targetStyle.setTop(0, Style.Unit.PX); onResize(); MaximizeEvent.<WindowUI> fire(this, this); } } @Override public void setPosition(double aLeft, double aTop) { super.setPosition(aLeft, aTop); MoveEvent.fire(this, this, aLeft, aTop); } @Override public void setSize(double aWidth, double aHeight) { super.setSize(aWidth, aHeight); ResizeEvent.<WindowPanel> fire(this, (int) aWidth, (int) aHeight); } private void snapshotMetrics() throws NumberFormatException { // measurement Style targetStyle = getWidget().getElement().getStyle(); // content String sHeight = targetStyle.getHeight(); contentHeightToRestore = Double.parseDouble(sHeight.substring(0, sHeight.length() - 2)); String sWidth = targetStyle.getWidth(); contentWidthToRestore = Double.parseDouble(sWidth.substring(0, sWidth.length() - 2)); targetStyle = getMovableTarget().getElement().getStyle(); // window String sLeft = targetStyle.getLeft(); leftToRestore = Double.parseDouble(sLeft.substring(0, sLeft.length() - 2)); String sTop = targetStyle.getTop(); topToRestore = Double.parseDouble(sTop.substring(0, sTop.length() - 2)); } protected boolean preMinimizedStateMaximized; protected boolean preMinimzedStateNormal; /** * Minimizes the window. Minimize here is setting zero as height. * Descendants may decide to do something else. minimize does a snapshot of * all window's metrics. So subsequent restore or restoreSnapshot calls will * lead to correct restoration of the window. */ @Override public void minimize() { if (!minimized) { preMinimizedStateMaximized = maximized; preMinimzedStateNormal = !maximized && !minimized; restoreSnapshot(); minimized = true; updateDecorCursors(); // measure snapshotMetrics(); // edit Style targetStyle = getWidget().getElement().getStyle(); // content targetStyle.setHeight(0, Style.Unit.PX); onResize(); MinimizeEvent.<WindowUI> fire(this, this); } } protected Double leftToRestore; protected Double topToRestore; protected Double contentWidthToRestore; protected Double contentHeightToRestore; @Override public void restoreSnapshot() { if (minimized || maximized) { minimized = false; maximized = false; if (leftToRestore != null) { getMovableTarget().getElement().getStyle().setLeft(leftToRestore, Style.Unit.PX); } leftToRestore = null; if (topToRestore != null) { getMovableTarget().getElement().getStyle().setTop(topToRestore, Style.Unit.PX); } topToRestore = null; if (contentWidthToRestore != null) { getWidget().getElement().getStyle().setWidth(contentWidthToRestore, Style.Unit.PX); } contentWidthToRestore = null; if (contentHeightToRestore != null) { getWidget().getElement().getStyle().setHeight(contentHeightToRestore, Style.Unit.PX); } contentHeightToRestore = null; onResize(); RestoreEvent.<WindowUI> fire(this, this); } } @Override public void restore() { if (minimized || maximized) { if (maximized || preMinimzedStateNormal) { restoreSnapshot(); updateDecorCursors(); } else if (preMinimizedStateMaximized) { maximize(); } } } @Override public boolean isActive() { return active; } @Override public void activate() { if (!active) { active = true; if (captionWidget != null) { captionWidget.addStyleDependentName(ACTIVE_SUFFIX_NAMNE); } Widget[] widgets = new Widget[] { n, s, w, e, ne, nw, se, sw, content }; for (Widget _w : widgets) { _w.addStyleDependentName(ACTIVE_SUFFIX_NAMNE); } ActivateEvent.<WindowUI> fire(this, this); } } @Override public void deactivate() { if (active) { active = false; if (captionWidget != null) { captionWidget.removeStyleDependentName(ACTIVE_SUFFIX_NAMNE); } Widget[] widgets = new Widget[] { n, s, w, e, ne, nw, se, sw, content }; for (Widget _w : widgets) { _w.removeStyleDependentName(ACTIVE_SUFFIX_NAMNE); } DeactivateEvent.<WindowUI> fire(this, this); } } public void toFront() { Element selfEl = getMovableTarget().getElement(); Element parentEl = selfEl.getParentElement(); if (parentEl != null) { Node lastChildNode = parentEl.getLastChild(); if (lastChildNode instanceof Element && lastChildNode != selfEl) { parentEl.insertAfter(selfEl, lastChildNode); } } } /** * Activates and brings the window to front. Descandants may focus default * widget in this method. */ @Override public void focus() { activate(); toFront(); } @Override protected void onAttach() { super.onAttach(); onResize(); OpenEvent.<WindowUI> fire(this, this); } protected void fireCloseEvent() { ClosedEvent.<WindowUI> fire(this, this); } @Override public void close() { if (!BeforeCloseEvent.<WindowUI> fire(this, this)) { getMovableTarget().removeFromParent(); fireCloseEvent(); } } @Override public boolean isMovable() { return movable; } @Override public void setMovable(boolean aValue) { movable = aValue; updateCaptionCursor(); } @Override public boolean isAnimationEnabled() { return animationEnabled; } @Override public void setAnimationEnabled(boolean aValue) { if (animationEnabled != aValue) { animationEnabled = aValue; verticalPanelContent.getElement().getStyle().clearProperty("transition"); if (!animationEnabled) { verticalPanelContent.getElement().getStyle().setProperty("transition", "none"); } } } @Override protected void beginResizing() { super.beginResizing(); verticalPanelContent.getElement().getStyle().setProperty("transition", "none"); getMovableTarget().getElement().getStyle().setProperty("transition", "none"); getWidget().getElement().getStyle().setVisibility(Style.Visibility.HIDDEN); } @Override protected void endResizing() { super.endResizing(); getWidget().getElement().getStyle().clearVisibility(); if (animationEnabled) { verticalPanelContent.getElement().getStyle().clearProperty("transition"); getMovableTarget().getElement().getStyle().clearProperty("transition"); } } protected void beginMoving() { getMovableTarget().getElement().getStyle().setProperty("transition", "none"); getWidget().getElement().getStyle().setVisibility(Style.Visibility.HIDDEN); } protected void endMoving() { getWidget().getElement().getStyle().clearVisibility(); if (animationEnabled) { getMovableTarget().getElement().getStyle().clearProperty("transition"); } } protected void updateCaptionCursor() { if (captionWidget != null) { if (movable) { captionWidget.getElement().getStyle().clearCursor(); } else { captionWidget.getElement().getStyle().setCursor(Style.Cursor.DEFAULT); } } } @Override public HandlerRegistration addOpenHandler(OpenHandler<WindowUI> handler) { return addHandler(handler, OpenEvent.getType()); } @Override public HandlerRegistration addClosedHandler(ClosedHandler<WindowUI> handler) { return addHandler(handler, ClosedEvent.getType()); } @Override public HandlerRegistration addBeforeCloseHandler(BeforeCloseHandler<WindowUI> handler) { return addHandler(handler, BeforeCloseEvent.getType()); } @Override public HandlerRegistration addActivateHandler(ActivateHandler<WindowUI> handler) { return addHandler(handler, ActivateEvent.getType()); } @Override public HandlerRegistration addDeactivateHandler(DeactivateHandler<WindowUI> handler) { return addHandler(handler, DeactivateEvent.getType()); } @Override public HandlerRegistration addMinimizeHandler(MinimizeHandler<WindowUI> handler) { return addHandler(handler, MinimizeEvent.getType()); } @Override public HandlerRegistration addMaximizeHandler(MaximizeHandler<WindowUI> handler) { return addHandler(handler, MaximizeEvent.getType()); } @Override public HandlerRegistration addRestoreHandler(RestoreHandler<WindowUI> handler) { return addHandler(handler, RestoreEvent.getType()); } @Override public HandlerRegistration addMoveHandler(MoveHandler<WindowUI> handler) { return addHandler(handler, MoveEvent.getType()); } @Override public HandlerRegistration addResizeHandler(ResizeHandler handler) { return addHandler(handler, ResizeEvent.getType()); } }