diff options
author | Pekka Hyvönen <pekka@vaadin.com> | 2013-02-21 17:04:48 +0200 |
---|---|---|
committer | Vaadin Code Review <review@vaadin.com> | 2013-04-04 12:52:55 +0000 |
commit | d937722318c47831775d2f0e6c67b0f0f1d57688 (patch) | |
tree | 92d643f4faa5a13dd86ac175d31e2484ef36cf7a /client | |
parent | 69def694d5d98f518ad08c039195fd2ac8781d2f (diff) | |
download | vaadin-framework-d937722318c47831775d2f0e6c67b0f0f1d57688.tar.gz vaadin-framework-d937722318c47831775d2f0e6c67b0f0f1d57688.zip |
Maximize Restore for Window #3400
Change-Id: I164ae83bd6cf98f7a3d7e76d8e717a56e8cb5183
Diffstat (limited to 'client')
3 files changed, 247 insertions, 146 deletions
diff --git a/client/src/com/vaadin/client/ui/AbstractComponentConnector.java b/client/src/com/vaadin/client/ui/AbstractComponentConnector.java index ecd6abae08..e7f7379994 100644 --- a/client/src/com/vaadin/client/ui/AbstractComponentConnector.java +++ b/client/src/com/vaadin/client/ui/AbstractComponentConnector.java @@ -36,6 +36,8 @@ import com.vaadin.client.metadata.NoDataException; import com.vaadin.client.metadata.Type; import com.vaadin.client.metadata.TypeData; import com.vaadin.client.metadata.TypeDataStore; +import com.vaadin.client.ui.AbstractFieldConnector; +import com.vaadin.client.ui.ManagedLayout; import com.vaadin.client.ui.datefield.PopupDateFieldConnector; import com.vaadin.client.ui.ui.UIConnector; import com.vaadin.shared.AbstractComponentState; @@ -205,12 +207,12 @@ public abstract class AbstractComponentConnector extends AbstractConnector } } - private void updateComponentSize() { - Profiler.enter("AbstractComponentConnector.updateComponentSize"); - - String newWidth = getState().width == null ? "" : getState().width; - String newHeight = getState().height == null ? "" : getState().height; + protected void updateComponentSize() { + updateComponentSize(getState().width == null ? "" : getState().width, + getState().height == null ? "" : getState().height); + } + protected void updateComponentSize(String newWidth, String newHeight) { // Parent should be updated if either dimension changed between relative // and non-relative if (newWidth.endsWith("%") != lastKnownWidth.endsWith("%")) { diff --git a/client/src/com/vaadin/client/ui/VWindow.java b/client/src/com/vaadin/client/ui/VWindow.java index fd2a701334..bd9a0ed07c 100644 --- a/client/src/com/vaadin/client/ui/VWindow.java +++ b/client/src/com/vaadin/client/ui/VWindow.java @@ -49,6 +49,7 @@ import com.vaadin.client.LayoutManager; import com.vaadin.client.Util; import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner; import com.vaadin.shared.EventId; +import com.vaadin.shared.ui.window.WindowState.DisplayState; /** * "Sub window" component. @@ -58,18 +59,6 @@ import com.vaadin.shared.EventId; public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, ScrollHandler, KeyDownHandler, FocusHandler, BlurHandler, Focusable { - /** - * Minimum allowed height of a window. This refers to the content area, not - * the outer borders. - */ - private static final int MIN_CONTENT_AREA_HEIGHT = 100; - - /** - * Minimum allowed width of a window. This refers to the content area, not - * the outer borders. - */ - private static final int MIN_CONTENT_AREA_WIDTH = 150; - private static ArrayList<VWindow> windowOrder = new ArrayList<VWindow>(); private static boolean orderingDefered; @@ -114,6 +103,9 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, public Element closeBox; /** For internal use only. May be removed or replaced in the future. */ + public Element maximizeRestoreBox; + + /** For internal use only. May be removed or replaced in the future. */ public ApplicationConnection client; /** For internal use only. May be removed or replaced in the future. */ @@ -262,6 +254,9 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, resizeBox = DOM.createDiv(); DOM.setElementProperty(resizeBox, "className", CLASSNAME + "-resizebox"); closeBox = DOM.createDiv(); + maximizeRestoreBox = DOM.createDiv(); + DOM.setElementProperty(maximizeRestoreBox, "className", CLASSNAME + + "-maximizebox"); DOM.setElementProperty(closeBox, "className", CLASSNAME + "-closebox"); DOM.appendChild(footer, resizeBox); @@ -269,14 +264,15 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, DOM.setElementProperty(wrapper, "className", CLASSNAME + "-wrap"); DOM.appendChild(wrapper, header); + DOM.appendChild(wrapper, maximizeRestoreBox); DOM.appendChild(wrapper, closeBox); DOM.appendChild(header, headerText); DOM.appendChild(wrapper, contents); DOM.appendChild(wrapper, footer); DOM.appendChild(super.getContainerElement(), wrapper); - sinkEvents(Event.MOUSEEVENTS | Event.TOUCHEVENTS | Event.ONCLICK - | Event.ONLOSECAPTURE); + sinkEvents(Event.ONDBLCLICK | Event.MOUSEEVENTS | Event.TOUCHEVENTS + | Event.ONCLICK | Event.ONLOSECAPTURE); setWidget(contentPanel); @@ -575,6 +571,31 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, } } + public void updateMaximizeRestoreClassName(boolean visible, + DisplayState state) { + String className; + if (state == DisplayState.MAXIMIZED) { + className = CLASSNAME + "-restorebox"; + } else { + className = CLASSNAME + "-maximizebox"; + } + if (!visible) { + className = className + " " + className + "-disabled"; + } + maximizeRestoreBox.setClassName(className); + } + + // TODO this will eventually be removed, currently used to avoid updating to + // server side. + public void setPopupPositionNoUpdate(int left, int top) { + if (top < 0) { + // ensure window is not moved out of browser window from top of the + // screen + top = 0; + } + super.setPopupPosition(left, top); + } + @Override public void setPopupPosition(int left, int top) { if (top < 0) { @@ -616,6 +637,8 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, return contents; } + private Event headerDragPending; + @Override public void onBrowserEvent(final Event event) { boolean bubble = true; @@ -632,6 +655,28 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, onCloseClick(); } bubble = false; + } else if (target == maximizeRestoreBox) { + // handled in connector + if (type != Event.ONCLICK) { + bubble = false; + } + } else if (header.isOrHasChild(target) && !dragging) { + // dblclick handled in connector + if (type != Event.ONDBLCLICK && draggable) { + if (type == Event.ONMOUSEDOWN) { + headerDragPending = event; + } else if (type == Event.ONMOUSEMOVE + && headerDragPending != null) { + // ie won't work unless this is set here + dragging = true; + onDragEvent(headerDragPending); + onDragEvent(event); + headerDragPending = null; + } else { + headerDragPending = null; + } + bubble = false; + } } else if (dragging || !contents.isOrHasChild(target)) { onDragEvent(event); bubble = false; @@ -648,7 +693,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, */ if (type == Event.ONMOUSEDOWN && !contentPanel.getElement().isOrHasChild(target) - && target != closeBox) { + && target != closeBox && target != maximizeRestoreBox) { contentPanel.focus(); } @@ -746,16 +791,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, } int w = Util.getTouchOrMouseClientX(event) - startX + origW; - int minWidth = getMinWidth(); - if (w < minWidth) { - w = minWidth; - } - int h = Util.getTouchOrMouseClientY(event) - startY + origH; - int minHeight = getMinHeight(); - if (h < minHeight) { - h = minHeight; - } setWidth(w + "px"); setHeight(h + "px"); @@ -775,7 +811,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, } } - private void updateContentsSize() { + public void updateContentsSize() { LayoutManager layoutManager = getLayoutManager(); layoutManager.setNeedsMeasure(ConnectorMap.get(client).getConnector( this)); @@ -959,10 +995,6 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, contentPanel.focus(); } - public int getMinHeight() { - return MIN_CONTENT_AREA_HEIGHT + getDecorationHeight(); - } - private int getDecorationHeight() { LayoutManager lm = getLayoutManager(); int headerHeight = lm.getOuterHeight(header); @@ -974,10 +1006,6 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, return LayoutManager.get(client); } - public int getMinWidth() { - return MIN_CONTENT_AREA_WIDTH + getDecorationWidth(); - } - private int getDecorationWidth() { LayoutManager layoutManager = getLayoutManager(); return layoutManager.getOuterWidth(getElement()) diff --git a/client/src/com/vaadin/client/ui/window/WindowConnector.java b/client/src/com/vaadin/client/ui/window/WindowConnector.java index 8cfc25a9dc..66907fbfa4 100644 --- a/client/src/com/vaadin/client/ui/window/WindowConnector.java +++ b/client/src/com/vaadin/client/ui/window/WindowConnector.java @@ -20,7 +20,10 @@ import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.Style; import com.google.gwt.dom.client.Style.Position; import com.google.gwt.dom.client.Style.Unit; -import com.google.gwt.user.client.DOM; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.DoubleClickEvent; +import com.google.gwt.event.dom.client.DoubleClickHandler; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Window; import com.vaadin.client.ApplicationConnection; @@ -31,6 +34,7 @@ import com.vaadin.client.LayoutManager; import com.vaadin.client.Paintable; import com.vaadin.client.UIDL; import com.vaadin.client.Util; +import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.AbstractSingleComponentContainerConnector; import com.vaadin.client.ui.ClickEventHandler; import com.vaadin.client.ui.PostLayoutListener; @@ -43,6 +47,7 @@ import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.ui.Connect; import com.vaadin.shared.ui.window.WindowServerRpc; import com.vaadin.shared.ui.window.WindowState; +import com.vaadin.shared.ui.window.WindowState.DisplayState; @Connect(value = com.vaadin.ui.Window.class) public class WindowConnector extends AbstractSingleComponentContainerConnector @@ -57,7 +62,32 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector } }; - boolean minWidthChecked = false; + abstract class WindowEventHandler implements ClickHandler, + DoubleClickHandler { + } + + private WindowEventHandler maximizeRestoreClickHandler = new WindowEventHandler() { + + @Override + public void onClick(ClickEvent event) { + final Element target = event.getNativeEvent().getEventTarget() + .cast(); + if (target == getWidget().maximizeRestoreBox) { + // Click on maximize/restore box + onMaximizeRestore(); + } + } + + @Override + public void onDoubleClick(DoubleClickEvent event) { + final Element target = event.getNativeEvent().getEventTarget() + .cast(); + if (getWidget().header.isOrHasChild(target)) { + // Double click on header + onMaximizeRestore(); + } + } + }; @Override public boolean delegateCaptionHandling() { @@ -68,12 +98,18 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector protected void init() { super.init(); + VWindow window = getWidget(); + getLayoutManager().registerDependency(this, - getWidget().contentPanel.getElement()); - getLayoutManager().registerDependency(this, getWidget().header); - getLayoutManager().registerDependency(this, getWidget().footer); + window.contentPanel.getElement()); + getLayoutManager().registerDependency(this, window.header); + getLayoutManager().registerDependency(this, window.footer); - getWidget().setOwner(getConnection().getUIConnector().getWidget()); + window.addHandler(maximizeRestoreClickHandler, ClickEvent.getType()); + window.addHandler(maximizeRestoreClickHandler, + DoubleClickEvent.getType()); + + window.setOwner(getConnection().getUIConnector().getWidget()); } @Override @@ -87,109 +123,46 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector @Override public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { - getWidget().id = getConnectorId(); - getWidget().client = client; - - // Workaround needed for Testing Tools (GWT generates window DOM - // slightly different in different browsers). - DOM.setElementProperty(getWidget().closeBox, "id", getConnectorId() - + "_window_close"); - if (isRealUpdate(uidl)) { - if (getState().modal != getWidget().vaadinModality) { - getWidget().setVaadinModality(!getWidget().vaadinModality); - } - if (!getWidget().isAttached()) { - getWidget().setVisible(false); // hide until - // possible centering - getWidget().show(); - } - if (getState().resizable != getWidget().resizable) { - getWidget().setResizable(getState().resizable); - } - getWidget().resizeLazy = getState().resizeLazy; + VWindow window = getWidget(); + String connectorId = getConnectorId(); - getWidget().setDraggable(getState().draggable); + window.id = getConnectorId(); + window.client = client; - // Caption must be set before required header size is measured. If - // the caption attribute is missing the caption should be cleared. - String iconURL = null; - if (getIcon() != null) { - iconURL = getIcon(); - } - getWidget().setCaption(getState().caption, iconURL); - } + // Workaround needed for Testing Tools (GWT generates window DOM + // slightly different in different browsers). + window.closeBox.setId(connectorId + "_window_close"); + window.maximizeRestoreBox + .setId(connectorId + "_window_maximizerestore"); - getWidget().visibilityChangesDisabled = true; + window.visibilityChangesDisabled = true; if (!isRealUpdate(uidl)) { return; } - getWidget().visibilityChangesDisabled = false; - - clickEventHandler.handleEventHandlerRegistration(); - - getWidget().immediate = getState().immediate; - - getWidget().setClosable(!isReadOnly()); - - // Initialize the position form UIDL - int positionx = getState().positionX; - int positiony = getState().positionY; - if (positionx >= 0 || positiony >= 0) { - if (positionx < 0) { - positionx = 0; - } - if (positiony < 0) { - positiony = 0; - } - getWidget().setPopupPosition(positionx, positiony); - } - - int childIndex = 0; + window.visibilityChangesDisabled = false; // we may have actions for (int i = 0; i < uidl.getChildCount(); i++) { UIDL childUidl = uidl.getChildUIDL(i); if (childUidl.getTag().equals("actions")) { - if (getWidget().shortcutHandler == null) { - getWidget().shortcutHandler = new ShortcutActionHandler( - getConnectorId(), client); + if (window.shortcutHandler == null) { + window.shortcutHandler = new ShortcutActionHandler( + connectorId, client); } - getWidget().shortcutHandler.updateActionMap(childUidl); + window.shortcutHandler.updateActionMap(childUidl); } } - // setting scrollposition must happen after children is rendered - getWidget().contentPanel.setScrollPosition(getState().scrollTop); - getWidget().contentPanel - .setHorizontalScrollPosition(getState().scrollLeft); - - // Center this window on screen if requested - // This had to be here because we might not know the content size before - // everything is painted into the window - - // centered is this is unset on move/resize - getWidget().centered = getState().centered; - getWidget().setVisible(true); - - // ensure window is not larger than browser window - if (getWidget().getOffsetWidth() > Window.getClientWidth()) { - getWidget().setWidth(Window.getClientWidth() + "px"); - } - if (getWidget().getOffsetHeight() > Window.getClientHeight()) { - getWidget().setHeight(Window.getClientHeight() + "px"); - } - if (uidl.hasAttribute("bringToFront")) { /* * Focus as a side-effect. Will be overridden by * ApplicationConnection if another component was focused by the * server side. */ - getWidget().contentPanel.focus(); - getWidget().bringToFrontSequence = uidl - .getIntAttribute("bringToFront"); + window.contentPanel.focus(); + window.bringToFrontSequence = uidl.getIntAttribute("bringToFront"); VWindow.deferOrdering(); } } @@ -224,26 +197,6 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector boolean hasContent = (content != null); Element contentElement = window.contentPanel.getElement(); - if (!minWidthChecked) { - boolean needsMinWidth = !isUndefinedWidth() || !hasContent - || content.isRelativeWidth(); - int minWidth = window.getMinWidth(); - if (needsMinWidth && lm.getInnerWidth(contentElement) < minWidth) { - minWidthChecked = true; - // Use minimum width if less than a certain size - window.setWidth(minWidth + "px"); - } - minWidthChecked = true; - } - - boolean needsMinHeight = !isUndefinedHeight() || !hasContent - || content.isRelativeHeight(); - int minHeight = window.getMinHeight(); - if (needsMinHeight && lm.getInnerHeight(contentElement) < minHeight) { - // Use minimum height if less than a certain size - window.setHeight(minHeight + "px"); - } - Style contentStyle = window.contents.getStyle(); int headerHeight = lm.getOuterHeight(window.header); @@ -291,9 +244,9 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector @Override public void postLayout() { - minWidthChecked = false; VWindow window = getWidget(); - if (window.centered) { + if (window.centered + && getState().displayState != DisplayState.MAXIMIZED) { window.center(); } window.positionOrSizeUpdated(); @@ -304,6 +257,124 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector return (WindowState) super.getState(); } + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + super.onStateChanged(stateChangeEvent); + + VWindow window = getWidget(); + WindowState state = getState(); + + if (state.modal != window.vaadinModality) { + window.setVaadinModality(!window.vaadinModality); + } + if (!window.isAttached()) { + window.setVisible(false); // hide until possible centering + window.show(); + } + boolean resizeable = state.resizable + && state.displayState == DisplayState.NORMAL; + window.setResizable(resizeable); + + window.resizeLazy = state.resizeLazy; + + window.setDraggable(state.draggable + && state.displayState == DisplayState.NORMAL); + + window.updateMaximizeRestoreClassName(state.resizable, + state.displayState); + + // Caption must be set before required header size is measured. If + // the caption attribute is missing the caption should be cleared. + String iconURL = null; + if (getIcon() != null) { + iconURL = getIcon(); + } + window.setCaption(state.caption, iconURL); + + clickEventHandler.handleEventHandlerRegistration(); + + window.immediate = state.immediate; + + window.setClosable(!isReadOnly()); + // initialize position from state + updateWindowPosition(); + + // setting scrollposition must happen after children is rendered + window.contentPanel.setScrollPosition(state.scrollTop); + window.contentPanel.setHorizontalScrollPosition(state.scrollLeft); + + // Center this window on screen if requested + // This had to be here because we might not know the content size before + // everything is painted into the window + + // centered is this is unset on move/resize + window.centered = state.centered; + window.setVisible(true); + + // ensure window is not larger than browser window + if (window.getOffsetWidth() > Window.getClientWidth()) { + window.setWidth(Window.getClientWidth() + "px"); + } + if (window.getOffsetHeight() > Window.getClientHeight()) { + window.setHeight(Window.getClientHeight() + "px"); + } + } + + // Need to override default because of DisplayState + @Override + protected void updateComponentSize() { + if (getState().displayState == DisplayState.NORMAL) { + super.updateComponentSize(); + } else if (getState().displayState == DisplayState.MAXIMIZED) { + super.updateComponentSize("100%", "100%"); + } + } + + protected void updateWindowPosition() { + VWindow window = getWidget(); + WindowState state = getState(); + if (state.displayState == DisplayState.NORMAL) { + // if centered, position handled in postLayout() + if (!state.centered) { + window.setPopupPosition(state.positionX, state.positionY); + } + } else if (state.displayState == DisplayState.MAXIMIZED) { + window.setPopupPositionNoUpdate(0, 0); + window.bringToFront(); + } + } + + protected void updateDisplayState() { + VWindow window = getWidget(); + WindowState state = getState(); + + // update draggable on widget + window.setDraggable(state.draggable + && state.displayState == DisplayState.NORMAL); + // update resizable on widget + window.setResizable(state.resizable + && state.displayState == DisplayState.NORMAL); + updateComponentSize(); + updateWindowPosition(); + window.updateMaximizeRestoreClassName(state.resizable, + state.displayState); + window.updateContentsSize(); + } + + protected void onMaximizeRestore() { + WindowState state = getState(); + if (state.resizable) { + if (state.displayState == DisplayState.MAXIMIZED) { + state.displayState = DisplayState.NORMAL; + } else { + state.displayState = DisplayState.MAXIMIZED; + } + updateDisplayState(); + getRpcProxy(WindowServerRpc.class).windowDisplayStateChanged( + state.displayState); + } + } + /** * Gives the WindowConnector an order number. As a side effect, moves the * window according to its order number so the windows are stacked. This |