From: Leif Åstrand Date: Tue, 31 Jul 2012 09:00:44 +0000 (+0300) Subject: Merge remote-tracking branch 'origin/6.8' X-Git-Tag: 7.0.0.beta1~236^2~11 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=e6ba86347ce0aea0b2dd7aa064586ce4fe7f2096;p=vaadin-framework.git Merge remote-tracking branch 'origin/6.8' Conflicts: src/com/vaadin/terminal/gwt/client/ui/popupview/VPopupView.java tests/testbench/com/vaadin/tests/components/popupview/PopupViewClickShortcut.java tests/testbench/com/vaadin/tests/containers/sqlcontainer/CheckboxUpdateProblem.java --- e6ba86347ce0aea0b2dd7aa064586ce4fe7f2096 diff --cc src/com/vaadin/data/util/sqlcontainer/SQLContainer.java index 250b2eb4c3,156b51b94c..5827390723 --- a/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java +++ b/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java @@@ -530,10 -508,9 +530,11 @@@ public class SQLContainer implements Co /** * {@inheritDoc} */ + + @Override public void removeContainerFilter(Filter filter) { filters.remove(filter); + refresh(); } /** diff --cc src/com/vaadin/terminal/gwt/client/ui/popupview/VPopupView.java index c923c5d0ab,0000000000..1b7cfd091f mode 100644,000000..100644 --- a/src/com/vaadin/terminal/gwt/client/ui/popupview/VPopupView.java +++ b/src/com/vaadin/terminal/gwt/client/ui/popupview/VPopupView.java @@@ -1,340 -1,0 +1,373 @@@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ +package com.vaadin.terminal.gwt.client.ui.popupview; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +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.dom.client.KeyDownEvent; ++import com.google.gwt.event.dom.client.KeyDownHandler; +import com.google.gwt.event.logical.shared.CloseEvent; +import com.google.gwt.event.logical.shared.CloseHandler; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.ui.Focusable; +import com.google.gwt.user.client.ui.HTML; +import com.google.gwt.user.client.ui.HasWidgets; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.PopupPanel; +import com.google.gwt.user.client.ui.RootPanel; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.UIDL; +import com.vaadin.terminal.gwt.client.VCaptionWrapper; ++import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler; ++import com.vaadin.terminal.gwt.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner; +import com.vaadin.terminal.gwt.client.ui.VOverlay; +import com.vaadin.terminal.gwt.client.ui.richtextarea.VRichTextArea; + +public class VPopupView extends HTML { + + public static final String CLASSNAME = "v-popupview"; + + /** For server-client communication */ + String uidlId; + ApplicationConnection client; + + /** This variable helps to communicate popup visibility to the server */ + boolean hostPopupVisible; + + final CustomPopup popup; + private final Label loading = new Label(); + + /** + * loading constructor + */ + public VPopupView() { + super(); + popup = new CustomPopup(); + + setStyleName(CLASSNAME); + popup.setStyleName(CLASSNAME + "-popup"); + loading.setStyleName(CLASSNAME + "-loading"); + + setHTML(""); + popup.setWidget(loading); + + // When we click to open the popup... + addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + updateState(true); + } + }); + + // ..and when we close it + popup.addCloseHandler(new CloseHandler() { + @Override + public void onClose(CloseEvent event) { + updateState(false); + } + }); + + popup.setAnimationEnabled(true); + } + + /** + * Update popup visibility to server + * + * @param visibility + */ + private void updateState(boolean visible) { + // If we know the server connection + // then update the current situation + if (uidlId != null && client != null && isAttached()) { + client.updateVariable(uidlId, "popupVisibility", visible, true); + } + } + + void preparePopup(final CustomPopup popup) { + popup.setVisible(false); + popup.show(); + } + + /** + * Determines the correct position for a popup and displays the popup at + * that position. + * + * By default, the popup is shown centered relative to its host component, + * ensuring it is visible on the screen if possible. + * + * Can be overridden to customize the popup position. + * + * @param popup + */ + protected void showPopup(final CustomPopup popup) { + popup.setPopupPosition(0, 0); + + popup.setVisible(true); + } + + void center() { + int windowTop = RootPanel.get().getAbsoluteTop(); + int windowLeft = RootPanel.get().getAbsoluteLeft(); + int windowRight = windowLeft + RootPanel.get().getOffsetWidth(); + int windowBottom = windowTop + RootPanel.get().getOffsetHeight(); + + int offsetWidth = popup.getOffsetWidth(); + int offsetHeight = popup.getOffsetHeight(); + + int hostHorizontalCenter = VPopupView.this.getAbsoluteLeft() + + VPopupView.this.getOffsetWidth() / 2; + int hostVerticalCenter = VPopupView.this.getAbsoluteTop() + + VPopupView.this.getOffsetHeight() / 2; + + int left = hostHorizontalCenter - offsetWidth / 2; + int top = hostVerticalCenter - offsetHeight / 2; + + // Don't show the popup outside the screen. + if ((left + offsetWidth) > windowRight) { + left -= (left + offsetWidth) - windowRight; + } + + if ((top + offsetHeight) > windowBottom) { + top -= (top + offsetHeight) - windowBottom; + } + + if (left < 0) { + left = 0; + } + + if (top < 0) { + top = 0; + } + + popup.setPopupPosition(left, top); + } + + /** + * Make sure that we remove the popup when the main widget is removed. + * + * @see com.google.gwt.user.client.ui.Widget#onUnload() + */ + @Override + protected void onDetach() { + popup.hide(); + super.onDetach(); + } + + private static native void nativeBlur(Element e) + /*-{ + if(e && e.blur) { + e.blur(); + } + }-*/; + + /** + * This class is only protected to enable overriding showPopup, and is + * currently not intended to be extended or otherwise used directly. Its API + * (other than it being a VOverlay) is to be considered private and + * potentially subject to change. + */ + protected class CustomPopup extends VOverlay { + + private ComponentConnector popupComponentPaintable = null; + Widget popupComponentWidget = null; + VCaptionWrapper captionWrapper = null; + + private boolean hasHadMouseOver = false; + private boolean hideOnMouseOut = true; + private final Set activeChildren = new HashSet(); + private boolean hiding = false; + ++ private ShortcutActionHandler shortcutActionHandler; ++ + public CustomPopup() { + super(true, false, true); // autoHide, not modal, dropshadow ++ ++ // Delegate popup keyboard events to the relevant handler. The ++ // events do not propagate automatically because the popup is ++ // directly attached to the RootPanel. ++ addDomHandler(new KeyDownHandler() { ++ @Override ++ public void onKeyDown(KeyDownEvent event) { ++ if (shortcutActionHandler != null) { ++ shortcutActionHandler.handleKeyboardEvent(Event ++ .as(event.getNativeEvent())); ++ } ++ } ++ }, KeyDownEvent.getType()); + } + + // For some reason ONMOUSEOUT events are not always received, so we have + // to use ONMOUSEMOVE that doesn't target the popup + @Override + public boolean onEventPreview(Event event) { + Element target = DOM.eventGetTarget(event); + boolean eventTargetsPopup = DOM.isOrHasChild(getElement(), target); + int type = DOM.eventGetType(event); + + // Catch children that use keyboard, so we can unfocus them when + // hiding + if (eventTargetsPopup && type == Event.ONKEYPRESS) { + activeChildren.add(target); + } + + if (eventTargetsPopup && type == Event.ONMOUSEMOVE) { + hasHadMouseOver = true; + } + + if (!eventTargetsPopup && type == Event.ONMOUSEMOVE) { + if (hasHadMouseOver && hideOnMouseOut) { + hide(); + return true; + } + } + + // Was the TAB key released outside of our popup? + if (!eventTargetsPopup && type == Event.ONKEYUP + && event.getKeyCode() == KeyCodes.KEY_TAB) { + // Should we hide on focus out (mouse out)? + if (hideOnMouseOut) { + hide(); + return true; + } + } + + return super.onEventPreview(event); + } + + @Override + public void hide(boolean autoClosed) { + hiding = true; + syncChildren(); + if (popupComponentWidget != null && popupComponentWidget != loading) { + remove(popupComponentWidget); + } + hasHadMouseOver = false; ++ shortcutActionHandler = null; + super.hide(autoClosed); + } + + @Override + public void show() { + hiding = false; ++ ++ // Find the shortcut action handler that should handle keyboard ++ // events from the popup. The events do not propagate automatically ++ // because the popup is directly attached to the RootPanel. ++ Widget widget = VPopupView.this; ++ while (shortcutActionHandler == null && widget != null) { ++ if (widget instanceof ShortcutActionHandlerOwner) { ++ shortcutActionHandler = ((ShortcutActionHandlerOwner) widget) ++ .getShortcutActionHandler(); ++ } ++ widget = widget.getParent(); ++ } ++ + super.show(); + } + + /** + * Try to sync all known active child widgets to server + */ + public void syncChildren() { + // Notify children with focus + if ((popupComponentWidget instanceof Focusable)) { + ((Focusable) popupComponentWidget).setFocus(false); + } else { + + checkForRTE(popupComponentWidget); + } + + // Notify children that have used the keyboard + for (Element e : activeChildren) { + try { + nativeBlur(e); + } catch (Exception ignored) { + } + } + activeChildren.clear(); + } + + private void checkForRTE(Widget popupComponentWidget2) { + if (popupComponentWidget2 instanceof VRichTextArea) { + ((VRichTextArea) popupComponentWidget2) + .synchronizeContentToServer(); + } else if (popupComponentWidget2 instanceof HasWidgets) { + HasWidgets hw = (HasWidgets) popupComponentWidget2; + Iterator iterator = hw.iterator(); + while (iterator.hasNext()) { + checkForRTE(iterator.next()); + } + } + } + + @Override + public boolean remove(Widget w) { + + popupComponentPaintable = null; + popupComponentWidget = null; + captionWrapper = null; + + return super.remove(w); + } + + public void updateFromUIDL(UIDL uidl, ApplicationConnection client) { + + ComponentConnector newPopupComponent = client.getPaintable(uidl + .getChildUIDL(0)); + + if (newPopupComponent != popupComponentPaintable) { + Widget newWidget = newPopupComponent.getWidget(); + setWidget(newWidget); + popupComponentWidget = newWidget; + popupComponentPaintable = newPopupComponent; + } + + } + + public void setHideOnMouseOut(boolean hideOnMouseOut) { + this.hideOnMouseOut = hideOnMouseOut; + } + + /* + * + * We need a hack make popup act as a child of VPopupView in Vaadin's + * component tree, but work in default GWT manner when closing or + * opening. + * + * (non-Javadoc) + * + * @see com.google.gwt.user.client.ui.Widget#getParent() + */ + @Override + public Widget getParent() { + if (!isAttached() || hiding) { + return super.getParent(); + } else { + return VPopupView.this; + } + } + + @Override + protected void onDetach() { + super.onDetach(); + hiding = false; + } + + @Override + public Element getContainerElement() { + return super.getContainerElement(); + } + + }// class CustomPopup + +}// class VPopupView diff --cc src/com/vaadin/terminal/gwt/client/ui/splitpanel/VAbstractSplitPanel.java index 1c14ce2a73,0000000000..a20c0476a5 mode 100644,000000..100644 --- a/src/com/vaadin/terminal/gwt/client/ui/splitpanel/VAbstractSplitPanel.java +++ b/src/com/vaadin/terminal/gwt/client/ui/splitpanel/VAbstractSplitPanel.java @@@ -1,773 -1,0 +1,772 @@@ +/* +@VaadinApache2LicenseForJavaFiles@ + */ + +package com.vaadin.terminal.gwt.client.ui.splitpanel; + +import java.util.Collections; +import java.util.List; + +import com.google.gwt.dom.client.Node; +import com.google.gwt.dom.client.Style; +import com.google.gwt.event.dom.client.TouchCancelEvent; +import com.google.gwt.event.dom.client.TouchCancelHandler; +import com.google.gwt.event.dom.client.TouchEndEvent; +import com.google.gwt.event.dom.client.TouchEndHandler; +import com.google.gwt.event.dom.client.TouchMoveEvent; +import com.google.gwt.event.dom.client.TouchMoveHandler; +import com.google.gwt.event.dom.client.TouchStartEvent; +import com.google.gwt.event.dom.client.TouchStartHandler; +import com.google.gwt.event.shared.EventHandler; +import com.google.gwt.event.shared.GwtEvent; +import com.google.gwt.user.client.DOM; +import com.google.gwt.user.client.Element; +import com.google.gwt.user.client.Event; +import com.google.gwt.user.client.ui.ComplexPanel; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.BrowserInfo; +import com.vaadin.terminal.gwt.client.ComponentConnector; +import com.vaadin.terminal.gwt.client.ConnectorMap; +import com.vaadin.terminal.gwt.client.LayoutManager; +import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.VConsole; +import com.vaadin.terminal.gwt.client.ui.TouchScrollDelegate; +import com.vaadin.terminal.gwt.client.ui.TouchScrollDelegate.TouchScrollHandler; +import com.vaadin.terminal.gwt.client.ui.VOverlay; +import com.vaadin.terminal.gwt.client.ui.splitpanel.VAbstractSplitPanel.SplitterMoveHandler.SplitterMoveEvent; + +public class VAbstractSplitPanel extends ComplexPanel { + + private boolean enabled = false; + + public static final String CLASSNAME = "v-splitpanel"; + + public static final int ORIENTATION_HORIZONTAL = 0; + + public static final int ORIENTATION_VERTICAL = 1; + + private static final int MIN_SIZE = 30; + + private int orientation = ORIENTATION_HORIZONTAL; + + Widget firstChild; + + Widget secondChild; + + private final Element wrapper = DOM.createDiv(); + + private final Element firstContainer = DOM.createDiv(); + + private final Element secondContainer = DOM.createDiv(); + + final Element splitter = DOM.createDiv(); + + private boolean resizing; + + private boolean resized = false; + + private int origX; + + private int origY; + + private int origMouseX; + + private int origMouseY; + + private boolean locked = false; + + private boolean positionReversed = false; + + List componentStyleNames = Collections.emptyList(); + + private Element draggingCurtain; + + ApplicationConnection client; + + boolean immediate; + + /* The current position of the split handle in either percentages or pixels */ + String position; + + String maximumPosition; + + String minimumPosition; + + private TouchScrollHandler touchScrollHandler; + + protected Element scrolledContainer; + + protected int origScrollTop; + + public VAbstractSplitPanel() { + this(ORIENTATION_HORIZONTAL); + } + + public VAbstractSplitPanel(int orientation) { + setElement(DOM.createDiv()); + switch (orientation) { + case ORIENTATION_HORIZONTAL: + setStyleName(CLASSNAME + "-horizontal"); + break; + case ORIENTATION_VERTICAL: + default: + setStyleName(CLASSNAME + "-vertical"); + break; + } + // size below will be overridden in update from uidl, initial size + // needed to keep IE alive + setWidth(MIN_SIZE + "px"); + setHeight(MIN_SIZE + "px"); + constructDom(); + setOrientation(orientation); + sinkEvents(Event.MOUSEEVENTS); + + makeScrollable(); + + addDomHandler(new TouchCancelHandler() { + @Override + public void onTouchCancel(TouchCancelEvent event) { + // TODO When does this actually happen?? + VConsole.log("TOUCH CANCEL"); + } + }, TouchCancelEvent.getType()); + addDomHandler(new TouchStartHandler() { + @Override + public void onTouchStart(TouchStartEvent event) { + Node target = event.getTouches().get(0).getTarget().cast(); + if (splitter.isOrHasChild(target)) { + onMouseDown(Event.as(event.getNativeEvent())); + } + } + }, TouchStartEvent.getType()); + addDomHandler(new TouchMoveHandler() { + @Override + public void onTouchMove(TouchMoveEvent event) { + if (resizing) { + onMouseMove(Event.as(event.getNativeEvent())); + } + } + }, TouchMoveEvent.getType()); + addDomHandler(new TouchEndHandler() { + @Override + public void onTouchEnd(TouchEndEvent event) { + if (resizing) { + onMouseUp(Event.as(event.getNativeEvent())); + } + } + }, TouchEndEvent.getType()); + + } + + protected void constructDom() { + DOM.appendChild(splitter, DOM.createDiv()); // for styling + DOM.appendChild(getElement(), wrapper); + DOM.setStyleAttribute(wrapper, "position", "relative"); + DOM.setStyleAttribute(wrapper, "width", "100%"); + DOM.setStyleAttribute(wrapper, "height", "100%"); + + DOM.appendChild(wrapper, secondContainer); + DOM.appendChild(wrapper, firstContainer); + DOM.appendChild(wrapper, splitter); + + DOM.setStyleAttribute(splitter, "position", "absolute"); + DOM.setStyleAttribute(secondContainer, "position", "absolute"); + + setStylenames(); + } + + private void setOrientation(int orientation) { + this.orientation = orientation; + if (orientation == ORIENTATION_HORIZONTAL) { + DOM.setStyleAttribute(splitter, "height", "100%"); + DOM.setStyleAttribute(splitter, "top", "0"); + DOM.setStyleAttribute(firstContainer, "height", "100%"); + DOM.setStyleAttribute(secondContainer, "height", "100%"); + } else { + DOM.setStyleAttribute(splitter, "width", "100%"); + DOM.setStyleAttribute(splitter, "left", "0"); + DOM.setStyleAttribute(firstContainer, "width", "100%"); + DOM.setStyleAttribute(secondContainer, "width", "100%"); + } + } + + @Override + public boolean remove(Widget w) { + boolean removed = super.remove(w); + if (removed) { + if (firstChild == w) { + firstChild = null; + } else { + secondChild = null; + } + } + return removed; + } + + void setLocked(boolean newValue) { + if (locked != newValue) { + locked = newValue; + splitterSize = -1; + setStylenames(); + } + } + + void setPositionReversed(boolean reversed) { + if (positionReversed != reversed) { + if (orientation == ORIENTATION_HORIZONTAL) { + DOM.setStyleAttribute(splitter, "right", ""); + DOM.setStyleAttribute(splitter, "left", ""); + } else if (orientation == ORIENTATION_VERTICAL) { + DOM.setStyleAttribute(splitter, "top", ""); + DOM.setStyleAttribute(splitter, "bottom", ""); + } + + positionReversed = reversed; + } + } + + /** + * Converts given split position string (in pixels or percentage) to a + * floating point pixel value. + * + * @param pos + * @return + */ + private float convertToPixels(String pos) { + float posAsFloat; + if (pos.indexOf("%") > 0) { + posAsFloat = Math.round(Float.parseFloat(pos.substring(0, + pos.length() - 1)) + / 100 + * (orientation == ORIENTATION_HORIZONTAL ? getOffsetWidth() + : getOffsetHeight())); + } else { + posAsFloat = Float.parseFloat(pos.substring(0, pos.length() - 2)); + } + return posAsFloat; + } + + /** + * Converts given split position string (in pixels or percentage) to a float + * percentage value. + * + * @param pos + * @return + */ + private float convertToPercentage(String pos) { - float posAsFloat = 0; - - if (pos.indexOf("px") > 0) { - int posAsInt = Integer.parseInt(pos.substring(0, pos.length() - 2)); ++ if (pos.endsWith("px")) { ++ float pixelPosition = Float.parseFloat(pos.substring(0, ++ pos.length() - 2)); + int offsetLength = orientation == ORIENTATION_HORIZONTAL ? getOffsetWidth() + : getOffsetHeight(); + - // 100% needs special handling - if (posAsInt + getSplitterSize() >= offsetLength) { - posAsInt = offsetLength; ++ // Take splitter size into account at the edge ++ if (pixelPosition + getSplitterSize() >= offsetLength) { ++ return 100; + } - posAsFloat = ((float) posAsInt / (float) offsetLength * 100); + ++ return pixelPosition / offsetLength * 100; + } else { - posAsFloat = Float.parseFloat(pos.substring(0, pos.length() - 1)); ++ assert pos.endsWith("%"); ++ return Float.parseFloat(pos.substring(0, pos.length() - 1)); + } - return posAsFloat; + } + + /** + * Returns the given position clamped to the range between current minimum + * and maximum positions. + * + * TODO Should this be in the connector? + * + * @param pos + * Position of the splitter as a CSS string, either pixels or a + * percentage. + * @return minimumPosition if pos is less than minimumPosition; + * maximumPosition if pos is greater than maximumPosition; pos + * otherwise. + */ + private String checkSplitPositionLimits(String pos) { + float positionAsFloat = convertToPixels(pos); + + if (maximumPosition != null + && convertToPixels(maximumPosition) < positionAsFloat) { + pos = maximumPosition; + } else if (minimumPosition != null + && convertToPixels(minimumPosition) > positionAsFloat) { + pos = minimumPosition; + } + return pos; + } + + /** + * Converts given string to the same units as the split position is. + * + * @param pos + * position to be converted + * @return converted position string + */ + private String convertToPositionUnits(String pos) { + if (position.indexOf("%") != -1 && pos.indexOf("%") == -1) { + // position is in percentage, pos in pixels + pos = convertToPercentage(pos) + "%"; + } else if (position.indexOf("px") > 0 && pos.indexOf("px") == -1) { + // position is in pixels and pos in percentage + pos = convertToPixels(pos) + "px"; + } + + return pos; + } + + void setSplitPosition(String pos) { + if (pos == null) { + return; + } + + pos = checkSplitPositionLimits(pos); + if (!pos.equals(position)) { + position = convertToPositionUnits(pos); + } + + // Convert percentage values to pixels + if (pos.indexOf("%") > 0) { + int size = orientation == ORIENTATION_HORIZONTAL ? getOffsetWidth() + : getOffsetHeight(); + float percentage = Float.parseFloat(pos.substring(0, + pos.length() - 1)); + pos = percentage / 100 * size + "px"; + } + + String attributeName; + if (orientation == ORIENTATION_HORIZONTAL) { + if (positionReversed) { + attributeName = "right"; + } else { + attributeName = "left"; + } + } else { + if (positionReversed) { + attributeName = "bottom"; + } else { + attributeName = "top"; + } + } + + Style style = splitter.getStyle(); + if (!pos.equals(style.getProperty(attributeName))) { + style.setProperty(attributeName, pos); + updateSizes(); + } + } + + void updateSizes() { + if (!isAttached()) { + return; + } + + int wholeSize; + int pixelPosition; + + switch (orientation) { + case ORIENTATION_HORIZONTAL: + wholeSize = DOM.getElementPropertyInt(wrapper, "clientWidth"); + pixelPosition = DOM.getElementPropertyInt(splitter, "offsetLeft"); + + // reposition splitter in case it is out of box + if ((pixelPosition > 0 && pixelPosition + getSplitterSize() > wholeSize) + || (positionReversed && pixelPosition < 0)) { + pixelPosition = wholeSize - getSplitterSize(); + if (pixelPosition < 0) { + pixelPosition = 0; + } + setSplitPosition(pixelPosition + "px"); + return; + } + + DOM.setStyleAttribute(firstContainer, "width", pixelPosition + "px"); + int secondContainerWidth = (wholeSize - pixelPosition - getSplitterSize()); + if (secondContainerWidth < 0) { + secondContainerWidth = 0; + } + DOM.setStyleAttribute(secondContainer, "width", + secondContainerWidth + "px"); + DOM.setStyleAttribute(secondContainer, "left", + (pixelPosition + getSplitterSize()) + "px"); + + LayoutManager layoutManager = LayoutManager.get(client); + ConnectorMap connectorMap = ConnectorMap.get(client); + if (firstChild != null) { + ComponentConnector connector = connectorMap + .getConnector(firstChild); + if (connector.isRelativeWidth()) { + layoutManager.reportWidthAssignedToRelative(connector, + pixelPosition); + } else { + layoutManager.setNeedsMeasure(connector); + } + } + if (secondChild != null) { + ComponentConnector connector = connectorMap + .getConnector(secondChild); + if (connector.isRelativeWidth()) { + layoutManager.reportWidthAssignedToRelative(connector, + secondContainerWidth); + } else { + layoutManager.setNeedsMeasure(connector); + } + } + break; + case ORIENTATION_VERTICAL: + wholeSize = DOM.getElementPropertyInt(wrapper, "clientHeight"); + pixelPosition = DOM.getElementPropertyInt(splitter, "offsetTop"); + + // reposition splitter in case it is out of box + if ((pixelPosition > 0 && pixelPosition + getSplitterSize() > wholeSize) + || (positionReversed && pixelPosition < 0)) { + pixelPosition = wholeSize - getSplitterSize(); + if (pixelPosition < 0) { + pixelPosition = 0; + } + setSplitPosition(pixelPosition + "px"); + return; + } + + DOM.setStyleAttribute(firstContainer, "height", pixelPosition + + "px"); + int secondContainerHeight = (wholeSize - pixelPosition - getSplitterSize()); + if (secondContainerHeight < 0) { + secondContainerHeight = 0; + } + DOM.setStyleAttribute(secondContainer, "height", + secondContainerHeight + "px"); + DOM.setStyleAttribute(secondContainer, "top", + (pixelPosition + getSplitterSize()) + "px"); + + layoutManager = LayoutManager.get(client); + connectorMap = ConnectorMap.get(client); + if (firstChild != null) { + ComponentConnector connector = connectorMap + .getConnector(firstChild); + if (connector.isRelativeHeight()) { + layoutManager.reportHeightAssignedToRelative(connector, + pixelPosition); + } else { + layoutManager.setNeedsMeasure(connector); + } + } + if (secondChild != null) { + ComponentConnector connector = connectorMap + .getConnector(secondChild); + if (connector.isRelativeHeight()) { + layoutManager.reportHeightAssignedToRelative(connector, + secondContainerHeight); + } else { + layoutManager.setNeedsMeasure(connector); + } + } + break; + } + } + + void setFirstWidget(Widget w) { + if (firstChild != null) { + firstChild.removeFromParent(); + } + if (w != null) { + super.add(w, firstContainer); + } + firstChild = w; + } + + void setSecondWidget(Widget w) { + if (secondChild != null) { + secondChild.removeFromParent(); + } + if (w != null) { + super.add(w, secondContainer); + } + secondChild = w; + } + + @Override + public void onBrowserEvent(Event event) { + switch (DOM.eventGetType(event)) { + case Event.ONMOUSEMOVE: + // case Event.ONTOUCHMOVE: + if (resizing) { + onMouseMove(event); + } + break; + case Event.ONMOUSEDOWN: + // case Event.ONTOUCHSTART: + onMouseDown(event); + break; + case Event.ONMOUSEOUT: + // Dragging curtain interferes with click events if added in + // mousedown so we add it only when needed i.e., if the mouse moves + // outside the splitter. + if (resizing) { + showDraggingCurtain(); + } + break; + case Event.ONMOUSEUP: + // case Event.ONTOUCHEND: + if (resizing) { + onMouseUp(event); + } + break; + case Event.ONCLICK: + resizing = false; + break; + } + // Only fire click event listeners if the splitter isn't moved + if (Util.isTouchEvent(event) || !resized) { + super.onBrowserEvent(event); + } else if (DOM.eventGetType(event) == Event.ONMOUSEUP) { + // Reset the resized flag after a mouseup has occured so the next + // mousedown/mouseup can be interpreted as a click. + resized = false; + } + } + + public void onMouseDown(Event event) { + if (locked || !isEnabled()) { + return; + } + final Element trg = event.getEventTarget().cast(); + if (trg == splitter || trg == DOM.getChild(splitter, 0)) { + resizing = true; + DOM.setCapture(getElement()); + origX = DOM.getElementPropertyInt(splitter, "offsetLeft"); + origY = DOM.getElementPropertyInt(splitter, "offsetTop"); + origMouseX = Util.getTouchOrMouseClientX(event); + origMouseY = Util.getTouchOrMouseClientY(event); + event.stopPropagation(); + event.preventDefault(); + } + } + + public void onMouseMove(Event event) { + switch (orientation) { + case ORIENTATION_HORIZONTAL: + final int x = Util.getTouchOrMouseClientX(event); + onHorizontalMouseMove(x); + break; + case ORIENTATION_VERTICAL: + default: + final int y = Util.getTouchOrMouseClientY(event); + onVerticalMouseMove(y); + break; + } + + } + + private void onHorizontalMouseMove(int x) { + int newX = origX + x - origMouseX; + if (newX < 0) { + newX = 0; + } + if (newX + getSplitterSize() > getOffsetWidth()) { + newX = getOffsetWidth() - getSplitterSize(); + } + + if (position.indexOf("%") > 0) { + position = convertToPositionUnits(newX + "px"); + } else { + // Reversed position + if (positionReversed) { + position = (getOffsetWidth() - newX - getSplitterSize()) + "px"; + } else { + position = newX + "px"; + } + } + + if (origX != newX) { + resized = true; + } + + // Reversed position + if (positionReversed) { + newX = getOffsetWidth() - newX - getSplitterSize(); + } + + setSplitPosition(newX + "px"); + } + + private void onVerticalMouseMove(int y) { + int newY = origY + y - origMouseY; + if (newY < 0) { + newY = 0; + } + + if (newY + getSplitterSize() > getOffsetHeight()) { + newY = getOffsetHeight() - getSplitterSize(); + } + + if (position.indexOf("%") > 0) { + position = convertToPositionUnits(newY + "px"); + } else { + // Reversed position + if (positionReversed) { + position = (getOffsetHeight() - newY - getSplitterSize()) + + "px"; + } else { + position = newY + "px"; + } + } + + if (origY != newY) { + resized = true; + } + + // Reversed position + if (positionReversed) { + newY = getOffsetHeight() - newY - getSplitterSize(); + } + + setSplitPosition(newY + "px"); + } + + public void onMouseUp(Event event) { + DOM.releaseCapture(getElement()); + hideDraggingCurtain(); + resizing = false; + if (!Util.isTouchEvent(event)) { + onMouseMove(event); + } + fireEvent(new SplitterMoveEvent(this)); + } + + public interface SplitterMoveHandler extends EventHandler { + public void splitterMoved(SplitterMoveEvent event); + + public static class SplitterMoveEvent extends + GwtEvent { + + public static final Type TYPE = new Type(); + + private Widget splitPanel; + + public SplitterMoveEvent(Widget splitPanel) { + this.splitPanel = splitPanel; + } + + @Override + public com.google.gwt.event.shared.GwtEvent.Type getAssociatedType() { + return TYPE; + } + + @Override + protected void dispatch(SplitterMoveHandler handler) { + handler.splitterMoved(this); + } + + } + } + + String getSplitterPosition() { + return position; + } + + /** + * Used in FF to avoid losing mouse capture when pointer is moved on an + * iframe. + */ + private void showDraggingCurtain() { + if (!isDraggingCurtainRequired()) { + return; + } + if (draggingCurtain == null) { + draggingCurtain = DOM.createDiv(); + DOM.setStyleAttribute(draggingCurtain, "position", "absolute"); + DOM.setStyleAttribute(draggingCurtain, "top", "0px"); + DOM.setStyleAttribute(draggingCurtain, "left", "0px"); + DOM.setStyleAttribute(draggingCurtain, "width", "100%"); + DOM.setStyleAttribute(draggingCurtain, "height", "100%"); + DOM.setStyleAttribute(draggingCurtain, "zIndex", "" + + VOverlay.Z_INDEX); + + DOM.appendChild(wrapper, draggingCurtain); + } + } + + /** + * A dragging curtain is required in Gecko and Webkit. + * + * @return true if the browser requires a dragging curtain + */ + private boolean isDraggingCurtainRequired() { + return (BrowserInfo.get().isGecko() || BrowserInfo.get().isWebkit()); + } + + /** + * Hides dragging curtain + */ + private void hideDraggingCurtain() { + if (draggingCurtain != null) { + DOM.removeChild(wrapper, draggingCurtain); + draggingCurtain = null; + } + } + + private int splitterSize = -1; + + private int getSplitterSize() { + if (splitterSize < 0) { + if (isAttached()) { + switch (orientation) { + case ORIENTATION_HORIZONTAL: + splitterSize = DOM.getElementPropertyInt(splitter, + "offsetWidth"); + break; + + default: + splitterSize = DOM.getElementPropertyInt(splitter, + "offsetHeight"); + break; + } + } + } + return splitterSize; + } + + void setStylenames() { + final String splitterClass = CLASSNAME + + (orientation == ORIENTATION_HORIZONTAL ? "-hsplitter" + : "-vsplitter"); + final String firstContainerClass = CLASSNAME + "-first-container"; + final String secondContainerClass = CLASSNAME + "-second-container"; + final String lockedSuffix = locked ? "-locked" : ""; + + splitter.setClassName(splitterClass + lockedSuffix); + firstContainer.setClassName(firstContainerClass); + secondContainer.setClassName(secondContainerClass); + + for (String styleName : componentStyleNames) { + splitter.addClassName(splitterClass + "-" + styleName + + lockedSuffix); + firstContainer.addClassName(firstContainerClass + "-" + styleName); + secondContainer + .addClassName(secondContainerClass + "-" + styleName); + } + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public boolean isEnabled() { + return enabled; + } + + /** + * Ensures the panels are scrollable eg. after style name changes + */ + void makeScrollable() { + if (touchScrollHandler == null) { + touchScrollHandler = TouchScrollDelegate.enableTouchScrolling(this); + } + touchScrollHandler.addElement(firstContainer); + touchScrollHandler.addElement(secondContainer); + } +} diff --cc tests/testbench/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java index 66b5e23cda,c1107061ed..1bc76fff1e --- a/tests/testbench/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java +++ b/tests/testbench/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java @@@ -20,10 -24,12 +20,12 @@@ import com.vaadin.ui.AbstractField import com.vaadin.ui.MenuBar; import com.vaadin.ui.MenuBar.MenuItem; -public abstract class AbstractFieldTest extends +public abstract class AbstractFieldTest> extends AbstractComponentTest implements ValueChangeListener, - ReadOnlyStatusChangeListener, FocusListener, BlurListener { + ReadOnlyStatusChangeListener { + private boolean sortValueChanges = true; + @Override protected void createActions() { super.createActions(); diff --cc tests/testbench/com/vaadin/tests/components/popupview/PopupViewClickShortcut.java index 47c97bbc21,c8d4ee9858..6461d10277 --- a/tests/testbench/com/vaadin/tests/components/popupview/PopupViewClickShortcut.java +++ b/tests/testbench/com/vaadin/tests/components/popupview/PopupViewClickShortcut.java @@@ -45,17 -45,18 +45,19 @@@ public class PopupViewClickShortcut ext l.setCaption(caption); l.setWidth(null); - Button b = new Button("Submit " + caption, new Button.ClickListener() { - private int i = 5; + Button b = new Button("Submit " + caption + " (Ctrl+Alt+" + + String.valueOf(Character.toChars(keyCode)) + ")", + new Button.ClickListener() { + private int i = 5; - @Override - public void buttonClick(ClickEvent event) { - log.log("Submitted from " - + event.getButton().getParent().getCaption()); - t.addItem(new String[] { "added " + i++ }, i); - } - }); - b.setClickShortcut(keyCode, ModifierKey.ALT); ++ @Override + public void buttonClick(ClickEvent event) { + log.log("Submitted from " + + event.getButton().getParent().getCaption()); + t.addItem(new String[] { "added " + i++ }, i); + } + }); + b.setClickShortcut(keyCode, ModifierKey.CTRL, ModifierKey.ALT); l.addComponent(t); l.addComponent(b); diff --cc tests/testbench/com/vaadin/tests/containers/sqlcontainer/CheckboxUpdateProblem.java index a5a8f7d24b,e06db94589..f34c12607a --- a/tests/testbench/com/vaadin/tests/containers/sqlcontainer/CheckboxUpdateProblem.java +++ b/tests/testbench/com/vaadin/tests/containers/sqlcontainer/CheckboxUpdateProblem.java @@@ -10,20 -8,16 +8,15 @@@ import com.vaadin.data.Container.ItemSe import com.vaadin.data.Item; import com.vaadin.data.Property; import com.vaadin.data.Property.ValueChangeEvent; - import com.vaadin.data.util.sqlcontainer.AllTests; - import com.vaadin.data.util.sqlcontainer.SQLContainer; - import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool; - import com.vaadin.data.util.sqlcontainer.connection.SimpleJDBCConnectionPool; - import com.vaadin.data.util.sqlcontainer.query.TableQuery; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Form; import com.vaadin.ui.HorizontalSplitPanel; +import com.vaadin.ui.Root.LegacyWindow; import com.vaadin.ui.Table; -import com.vaadin.ui.Window; -public class CheckboxUpdateProblem extends Application implements - Property.ValueChangeListener { +public class CheckboxUpdateProblem extends Application.LegacyApplication + implements Property.ValueChangeListener { private final DatabaseHelper databaseHelper = new DatabaseHelper(); private Table testList; private final HorizontalSplitPanel horizontalSplit = new HorizontalSplitPanel(); @@@ -118,75 -109,4 +111,4 @@@ } - private class DatabaseHelper { - - private JDBCConnectionPool connectionPool = null; - private SQLContainer testContainer = null; - private static final String TABLENAME = "testtable"; - - public DatabaseHelper() { - initConnectionPool(); - initDatabase(); - initContainers(); - } - - private void initDatabase() { - try { - Connection conn = connectionPool.reserveConnection(); - Statement statement = conn.createStatement(); - try { - statement.execute("drop table " + TABLENAME); - } catch (SQLException e) { - // Will fail if table doesn't exist, which is OK. - conn.rollback(); - } - switch (AllTests.db) { - case MYSQL: - statement - .execute("create table " - + TABLENAME - + " (id integer auto_increment not null, field1 varchar(100), field2 boolean, primary key(id))"); - break; - case POSTGRESQL: - statement - .execute("create table " - + TABLENAME - + " (\"id\" serial primary key, \"field1\" varchar(100), \"field2\" boolean)"); - break; - } - statement.executeUpdate("insert into " + TABLENAME - + " values(default, 'Kalle', 'true')"); - statement.close(); - conn.commit(); - connectionPool.releaseConnection(conn); - } catch (SQLException e) { - e.printStackTrace(); - } - } - - private void initContainers() { - try { - TableQuery q1 = new TableQuery(TABLENAME, connectionPool); - q1.setVersionColumn("id"); - testContainer = new SQLContainer(q1); - } catch (SQLException e) { - e.printStackTrace(); - } - } - - private void initConnectionPool() { - try { - connectionPool = new SimpleJDBCConnectionPool( - AllTests.dbDriver, AllTests.dbURL, AllTests.dbUser, - AllTests.dbPwd, 2, 5); - } catch (SQLException e) { - e.printStackTrace(); - } - } - - public SQLContainer getTestContainer() { - return testContainer; - } - } - -} +} diff --cc tests/testbench/com/vaadin/tests/containers/sqlcontainer/ComboBoxUpdateProblem.java index 0000000000,ed6d39bb62..b7d1b8c37e mode 000000,100644..100644 --- a/tests/testbench/com/vaadin/tests/containers/sqlcontainer/ComboBoxUpdateProblem.java +++ b/tests/testbench/com/vaadin/tests/containers/sqlcontainer/ComboBoxUpdateProblem.java @@@ -1,0 -1,27 +1,27 @@@ + package com.vaadin.tests.containers.sqlcontainer; + + import com.vaadin.Application; + import com.vaadin.ui.AbstractSelect.Filtering; + import com.vaadin.ui.ComboBox; -import com.vaadin.ui.Window; ++import com.vaadin.ui.Root; + + /** + * See http://dev.vaadin.com/ticket/9155 . + */ -public class ComboBoxUpdateProblem extends Application { ++public class ComboBoxUpdateProblem extends Application.LegacyApplication { + private final DatabaseHelper databaseHelper = new DatabaseHelper(); + + @Override + public void init() { - setMainWindow(new Window("Test window")); ++ setMainWindow(new Root.LegacyWindow("Test window")); + + ComboBox combo = new ComboBox("Names", + databaseHelper.getTestContainer()); + combo.setItemCaptionPropertyId("FIELD1"); + combo.setFilteringMode(Filtering.FILTERINGMODE_CONTAINS); + combo.setImmediate(true); + + getMainWindow().addComponent(combo); + } + + }