From 52b602ed2e8ca7cbad266b59c45e916cb8394b56 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Tue, 12 May 2015 12:03:40 +0300 Subject: Catch all Exceptions when trying to open a gzipped resource (#13653) URLConnection.getInputStream may throw any IOException, not just FileNotFoundException. Additionally, catch and log unexpected non-IOExceptions just in case to keep the app from failing hard. Change-Id: Id7ce7ddee3de38ccd10d9e02e6c587a86b9cac96 --- server/src/com/vaadin/server/VaadinServlet.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server/src/com/vaadin/server/VaadinServlet.java b/server/src/com/vaadin/server/VaadinServlet.java index 053349a635..b30f6acf16 100644 --- a/server/src/com/vaadin/server/VaadinServlet.java +++ b/server/src/com/vaadin/server/VaadinServlet.java @@ -877,8 +877,13 @@ public class VaadinServlet extends HttpServlet implements Constants { is = connection.getInputStream(); // set gzip headers response.setHeader("Content-Encoding", "gzip"); - } catch (FileNotFoundException e) { + } catch (IOException e) { // NOP: will be still tried with non gzipped version + } catch (Exception e) { + getLogger().log( + Level.FINE, + "Unexpected exception looking for gzipped version of resource " + + urlStr, e); } } if (is == null) { -- cgit v1.2.3 From 1042bfde5f306c9b710f6cf4cf8d6b232e0301da Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Tue, 19 May 2015 15:20:12 +0300 Subject: Refactor focus related server API to class AbstractFocusable Change-Id: I58159d6f47d38230d583bd0cd61673bfbce02955 --- client/src/com/vaadin/client/ui/VButton.java | 3 - .../src/com/vaadin/client/ui/ui/UIConnector.java | 18 ++- server/src/com/vaadin/ui/AbstractFocusable.java | 134 +++++++++++++++++++++ server/src/com/vaadin/ui/Button.java | 105 +--------------- .../tests/components/AbstractComponentTest.java | 41 ++++++- .../abstractfield/AbstractFieldTest.java | 11 +- .../vaadin/tests/components/button/Buttons2.java | 3 - 7 files changed, 186 insertions(+), 129 deletions(-) create mode 100644 server/src/com/vaadin/ui/AbstractFocusable.java diff --git a/client/src/com/vaadin/client/ui/VButton.java b/client/src/com/vaadin/client/ui/VButton.java index bf321f7f00..2eb967c4fa 100644 --- a/client/src/com/vaadin/client/ui/VButton.java +++ b/client/src/com/vaadin/client/ui/VButton.java @@ -23,7 +23,6 @@ import com.google.gwt.dom.client.NativeEvent; 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.user.client.DOM; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.FocusWidget; @@ -94,8 +93,6 @@ public class VButton extends FocusWidget implements ClickHandler { /** For internal use only. May be removed or replaced in the future. */ public int clickShortcut = 0; - private HandlerRegistration focusHandlerRegistration; - private HandlerRegistration blurHandlerRegistration; private long lastClickTime = 0; public VButton() { diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java index e7c252f26a..da23ec4a5a 100644 --- a/client/src/com/vaadin/client/ui/ui/UIConnector.java +++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java @@ -59,6 +59,7 @@ import com.vaadin.client.ResourceLoader.ResourceLoadEvent; import com.vaadin.client.ResourceLoader.ResourceLoadListener; import com.vaadin.client.ServerConnector; import com.vaadin.client.UIDL; +import com.vaadin.client.Util; import com.vaadin.client.VConsole; import com.vaadin.client.ValueMap; import com.vaadin.client.annotations.OnStateChange; @@ -319,19 +320,19 @@ public class UIConnector extends AbstractSingleComponentContainerConnector Scheduler.get().scheduleDeferred(new Command() { @Override public void execute() { - ComponentConnector paintable = (ComponentConnector) uidl + ComponentConnector connector = (ComponentConnector) uidl .getPaintableAttribute("focused", getConnection()); - if (paintable == null) { + if (connector == null) { // Do not try to focus invisible components which not // present in UIDL return; } - final Widget toBeFocused = paintable.getWidget(); + final Widget toBeFocused = connector.getWidget(); /* * Two types of Widgets can be focused, either implementing - * GWT HasFocus of a thinner Vaadin specific Focusable + * GWT Focusable of a thinner Vaadin specific Focusable * interface. */ if (toBeFocused instanceof com.google.gwt.user.client.ui.Focusable) { @@ -340,7 +341,14 @@ public class UIConnector extends AbstractSingleComponentContainerConnector } else if (toBeFocused instanceof Focusable) { ((Focusable) toBeFocused).focus(); } else { - VConsole.log("Could not focus component"); + getLogger() + .severe("Server is trying to set focus to the widget of connector " + + Util.getConnectorString(connector) + + " but it is not focusable. The widget should implement either " + + com.google.gwt.user.client.ui.Focusable.class + .getName() + + " or " + + Focusable.class.getName()); } } }); diff --git a/server/src/com/vaadin/ui/AbstractFocusable.java b/server/src/com/vaadin/ui/AbstractFocusable.java new file mode 100644 index 0000000000..b9705cef6a --- /dev/null +++ b/server/src/com/vaadin/ui/AbstractFocusable.java @@ -0,0 +1,134 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.ui; + +import com.vaadin.event.FieldEvents.BlurEvent; +import com.vaadin.event.FieldEvents.BlurListener; +import com.vaadin.event.FieldEvents.BlurNotifier; +import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl; +import com.vaadin.event.FieldEvents.FocusEvent; +import com.vaadin.event.FieldEvents.FocusListener; +import com.vaadin.event.FieldEvents.FocusNotifier; +import com.vaadin.shared.ui.TabIndexState; +import com.vaadin.ui.Component.Focusable; + +/** + * An abstract base class for focusable components. Includes API for setting the + * tab index, programmatic focusing, and adding focus and blur listeners. + * + * @since + * @author Vaadin Ltd + */ +public abstract class AbstractFocusable extends AbstractComponent implements + Focusable, FocusNotifier, BlurNotifier { + + protected AbstractFocusable() { + registerRpc(new FocusAndBlurServerRpcImpl(this) { + @Override + protected void fireEvent(Event event) { + AbstractFocusable.this.fireEvent(event); + } + }); + } + + @Override + public void addBlurListener(BlurListener listener) { + addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener, + BlurListener.blurMethod); + } + + /** + * @deprecated As of 7.0, replaced by {@link #addBlurListener(BlurListener)} + */ + @Override + @Deprecated + public void addListener(BlurListener listener) { + addBlurListener(listener); + } + + @Override + public void removeBlurListener(BlurListener listener) { + removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener); + } + + /** + * @deprecated As of 7.0, replaced by + * {@link #removeBlurListener(BlurListener)} + */ + @Override + @Deprecated + public void removeListener(BlurListener listener) { + removeBlurListener(listener); + + } + + @Override + public void addFocusListener(FocusListener listener) { + addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener, + FocusListener.focusMethod); + + } + + /** + * @deprecated As of 7.0, replaced by + * {@link #addFocusListener(FocusListener)} + */ + @Override + @Deprecated + public void addListener(FocusListener listener) { + addFocusListener(listener); + } + + @Override + public void removeFocusListener(FocusListener listener) { + removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener); + } + + /** + * @deprecated As of 7.0, replaced by + * {@link #removeFocusListener(FocusListener)} + */ + @Override + @Deprecated + public void removeListener(FocusListener listener) { + removeFocusListener(listener); + } + + @Override + public void focus() { + super.focus(); + } + + @Override + public int getTabIndex() { + return getState(false).tabIndex; + } + + @Override + public void setTabIndex(int tabIndex) { + getState().tabIndex = tabIndex; + } + + @Override + protected TabIndexState getState() { + return (TabIndexState) super.getState(); + } + + @Override + protected TabIndexState getState(boolean markAsDirty) { + return (TabIndexState) super.getState(markAsDirty); + } +} diff --git a/server/src/com/vaadin/ui/Button.java b/server/src/com/vaadin/ui/Button.java index 6beb6ed686..a918780a60 100644 --- a/server/src/com/vaadin/ui/Button.java +++ b/server/src/com/vaadin/ui/Button.java @@ -24,12 +24,7 @@ import org.jsoup.nodes.Attributes; import org.jsoup.nodes.Element; import com.vaadin.event.Action; -import com.vaadin.event.FieldEvents; -import com.vaadin.event.FieldEvents.BlurEvent; -import com.vaadin.event.FieldEvents.BlurListener; import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl; -import com.vaadin.event.FieldEvents.FocusEvent; -import com.vaadin.event.FieldEvents.FocusListener; import com.vaadin.event.ShortcutAction; import com.vaadin.event.ShortcutAction.KeyCode; import com.vaadin.event.ShortcutAction.ModifierKey; @@ -38,7 +33,6 @@ import com.vaadin.server.Resource; import com.vaadin.shared.MouseEventDetails; import com.vaadin.shared.ui.button.ButtonServerRpc; import com.vaadin.shared.ui.button.ButtonState; -import com.vaadin.ui.Component.Focusable; import com.vaadin.ui.declarative.DesignAttributeHandler; import com.vaadin.ui.declarative.DesignContext; import com.vaadin.util.ReflectTools; @@ -50,8 +44,7 @@ import com.vaadin.util.ReflectTools; * @since 3.0 */ @SuppressWarnings("serial") -public class Button extends AbstractComponent implements - FieldEvents.BlurNotifier, FieldEvents.FocusNotifier, Focusable, +public class Button extends AbstractFocusable implements Action.ShortcutNotifier { private ButtonServerRpc rpc = new ButtonServerRpc() { @@ -72,20 +65,11 @@ public class Button extends AbstractComponent implements } }; - FocusAndBlurServerRpcImpl focusBlurRpc = new FocusAndBlurServerRpcImpl(this) { - - @Override - protected void fireEvent(Event event) { - Button.this.fireEvent(event); - } - }; - /** * Creates a new push button. */ public Button() { registerRpc(rpc); - registerRpc(focusBlurRpc); } /** @@ -393,67 +377,6 @@ public class Button extends AbstractComponent implements fireEvent(new Button.ClickEvent(this, details)); } - @Override - public void addBlurListener(BlurListener listener) { - addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener, - BlurListener.blurMethod); - } - - /** - * @deprecated As of 7.0, replaced by {@link #addBlurListener(BlurListener)} - **/ - @Override - @Deprecated - public void addListener(BlurListener listener) { - addBlurListener(listener); - } - - @Override - public void removeBlurListener(BlurListener listener) { - removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener); - } - - /** - * @deprecated As of 7.0, replaced by - * {@link #removeBlurListener(BlurListener)} - **/ - @Override - @Deprecated - public void removeListener(BlurListener listener) { - removeBlurListener(listener); - } - - @Override - public void addFocusListener(FocusListener listener) { - addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener, - FocusListener.focusMethod); - } - - /** - * @deprecated As of 7.0, replaced by - * {@link #addFocusListener(FocusListener)} - **/ - @Override - @Deprecated - public void addListener(FocusListener listener) { - addFocusListener(listener); - } - - @Override - public void removeFocusListener(FocusListener listener) { - removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener); - } - - /** - * @deprecated As of 7.0, replaced by - * {@link #removeFocusListener(FocusListener)} - **/ - @Override - @Deprecated - public void removeListener(FocusListener listener) { - removeFocusListener(listener); - } - /* * Actions */ @@ -575,32 +498,6 @@ public class Button extends AbstractComponent implements getState().disableOnClick = disableOnClick; } - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Component.Focusable#getTabIndex() - */ - @Override - public int getTabIndex() { - return getState(false).tabIndex; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Component.Focusable#setTabIndex(int) - */ - @Override - public void setTabIndex(int tabIndex) { - getState().tabIndex = tabIndex; - } - - @Override - public void focus() { - // Overridden only to make public - super.focus(); - } - @Override protected ButtonState getState() { return (ButtonState) super.getState(); diff --git a/uitest/src/com/vaadin/tests/components/AbstractComponentTest.java b/uitest/src/com/vaadin/tests/components/AbstractComponentTest.java index b289279b86..aca617aa5a 100644 --- a/uitest/src/com/vaadin/tests/components/AbstractComponentTest.java +++ b/uitest/src/com/vaadin/tests/components/AbstractComponentTest.java @@ -20,6 +20,7 @@ import com.vaadin.server.ThemeResource; import com.vaadin.tests.util.Log; import com.vaadin.tests.util.LoremIpsum; import com.vaadin.ui.AbstractComponent; +import com.vaadin.ui.Component.Focusable; import com.vaadin.ui.MenuBar; import com.vaadin.ui.MenuBar.MenuItem; import com.vaadin.ui.themes.BaseTheme; @@ -242,16 +243,18 @@ public abstract class AbstractComponentTest createStyleNameSelect(CATEGORY_DECORATIONS); + createFocusActions(); } protected Command focusListenerCommand = new Command() { @Override public void execute(T c, Boolean value, Object data) { + FocusNotifier fn = (FocusNotifier) c; if (value) { - ((FocusNotifier) c).addListener(AbstractComponentTest.this); + fn.addFocusListener(AbstractComponentTest.this); } else { - ((FocusNotifier) c).removeListener(AbstractComponentTest.this); + fn.removeFocusListener(AbstractComponentTest.this); } } }; @@ -259,10 +262,11 @@ public abstract class AbstractComponentTest @Override public void execute(T c, Boolean value, Object data) { + BlurNotifier bn = (BlurNotifier) c; if (value) { - ((BlurNotifier) c).addListener(AbstractComponentTest.this); + bn.addBlurListener(AbstractComponentTest.this); } else { - ((BlurNotifier) c).removeListener(AbstractComponentTest.this); + bn.removeBlurListener(AbstractComponentTest.this); } } }; @@ -279,6 +283,35 @@ public abstract class AbstractComponentTest } + private void createFocusActions() { + if (FocusNotifier.class.isAssignableFrom(getTestClass())) { + createFocusListener(CATEGORY_LISTENERS); + } + if (BlurNotifier.class.isAssignableFrom(getTestClass())) { + createBlurListener(CATEGORY_LISTENERS); + } + if (Focusable.class.isAssignableFrom(getTestClass())) { + LinkedHashMap tabIndexes = new LinkedHashMap(); + tabIndexes.put("0", 0); + tabIndexes.put("-1", -1); + tabIndexes.put("10", 10); + createSelectAction("Tab index", "State", tabIndexes, "0", + new Command() { + @Override + public void execute(T c, Integer tabIndex, Object data) { + ((Focusable) c).setTabIndex(tabIndex); + } + }); + + createClickAction("Set focus", "State", new Command() { + @Override + public void execute(T c, Void value, Object data) { + ((Focusable) c).focus(); + } + }, null); + } + } + private void createStyleNameSelect(String category) { LinkedHashMap options = new LinkedHashMap(); options.put("-", null); diff --git a/uitest/src/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java b/uitest/src/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java index 692ca25b07..496a44a6c1 100644 --- a/uitest/src/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java +++ b/uitest/src/com/vaadin/tests/components/abstractfield/AbstractFieldTest.java @@ -13,8 +13,6 @@ import com.vaadin.data.Property; import com.vaadin.data.Property.ReadOnlyStatusChangeEvent; import com.vaadin.data.Property.ReadOnlyStatusChangeListener; import com.vaadin.data.Property.ValueChangeListener; -import com.vaadin.event.FieldEvents.BlurNotifier; -import com.vaadin.event.FieldEvents.FocusNotifier; import com.vaadin.tests.components.AbstractComponentTest; import com.vaadin.ui.AbstractField; import com.vaadin.ui.MenuBar; @@ -29,15 +27,9 @@ public abstract class AbstractFieldTest extends @Override protected void createActions() { super.createActions(); + createBooleanAction("Required", CATEGORY_STATE, false, requiredCommand); createRequiredErrorSelect(CATEGORY_DECORATIONS); - if (FocusNotifier.class.isAssignableFrom(getTestClass())) { - createFocusListener(CATEGORY_LISTENERS); - } - - if (BlurNotifier.class.isAssignableFrom(getTestClass())) { - createBlurListener(CATEGORY_LISTENERS); - } createValueChangeListener(CATEGORY_LISTENERS); createReadOnlyStatusChangeListener(CATEGORY_LISTENERS); @@ -52,7 +44,6 @@ public abstract class AbstractFieldTest extends // * invalidallowed // * error indicator // - // * tabindex // * validation visible // * ShortcutListener diff --git a/uitest/src/com/vaadin/tests/components/button/Buttons2.java b/uitest/src/com/vaadin/tests/components/button/Buttons2.java index 7526e7dbc3..4f75dfbfef 100644 --- a/uitest/src/com/vaadin/tests/components/button/Buttons2.java +++ b/uitest/src/com/vaadin/tests/components/button/Buttons2.java @@ -42,9 +42,6 @@ public class Buttons2 extends AbstractComponentTest protected void createActions() { super.createActions(); - createFocusListener(CATEGORY_LISTENERS); - createBlurListener(CATEGORY_LISTENERS); - createBooleanAction("Disable on click", CATEGORY_FEATURES, false, disableOnClickCommand); addClickListener(CATEGORY_LISTENERS); -- cgit v1.2.3 From 26b06bd6361002faa9eb718fb082b4eb71e8b242 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Tue, 12 May 2015 17:01:14 +0300 Subject: Add focus API to Grid - Server-side Grid extends AbstractFocusable - Programmatic focus, tab index, focus/blur listeners - Client-side Grid implements GWT and Vaadin Focusable - Programmatic focus, tab index, access keys Change-Id: Ic8b35ba91f82d5fba8f819897774dc89f94ecf7b --- .../vaadin/client/connectors/GridConnector.java | 32 ++++++++- client/src/com/vaadin/client/widgets/Grid.java | 40 ++++++++++- server/src/com/vaadin/ui/Grid.java | 2 +- .../src/com/vaadin/shared/ui/grid/GridState.java | 4 +- .../grid/basicfeatures/GridBasicFeatures.java | 1 - .../grid/basicfeatures/server/GridFocusTest.java | 79 ++++++++++++++++++++++ 6 files changed, 150 insertions(+), 8 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridFocusTest.java diff --git a/client/src/com/vaadin/client/connectors/GridConnector.java b/client/src/com/vaadin/client/connectors/GridConnector.java index d31baaa665..3eb92ab94c 100644 --- a/client/src/com/vaadin/client/connectors/GridConnector.java +++ b/client/src/com/vaadin/client/connectors/GridConnector.java @@ -32,11 +32,17 @@ import java.util.logging.Logger; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.NativeEvent; +import com.google.gwt.event.dom.client.BlurEvent; +import com.google.gwt.event.dom.client.BlurHandler; +import com.google.gwt.event.dom.client.FocusEvent; +import com.google.gwt.event.dom.client.FocusHandler; +import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ComponentConnector; import com.vaadin.client.ConnectorHierarchyChangeEvent; import com.vaadin.client.DeferredWorker; +import com.vaadin.client.EventHelper; import com.vaadin.client.MouseEventDetailsBuilder; import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.communication.StateChangeEvent; @@ -80,6 +86,7 @@ import com.vaadin.client.widgets.Grid.FooterRow; import com.vaadin.client.widgets.Grid.HeaderCell; import com.vaadin.client.widgets.Grid.HeaderRow; import com.vaadin.shared.Connector; +import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc; import com.vaadin.shared.data.sort.SortDirection; import com.vaadin.shared.ui.Connect; import com.vaadin.shared.ui.grid.DetailsConnectorChange; @@ -112,7 +119,7 @@ import elemental.json.JsonValue; */ @Connect(com.vaadin.ui.Grid.class) public class GridConnector extends AbstractHasComponentsConnector implements - SimpleManagedLayout, DeferredWorker { + SimpleManagedLayout, DeferredWorker, FocusHandler, BlurHandler { private static final class CustomCellStyleGenerator implements CellStyleGenerator { @@ -757,6 +764,9 @@ public class GridConnector extends AbstractHasComponentsConnector implements private final LazyDetailsScrollAdjuster lazyDetailsScrollAdjuster = new LazyDetailsScrollAdjuster(); + private HandlerRegistration focusHandlerRegistration = null; + private HandlerRegistration blurHandlerRegistration = null; + @Override @SuppressWarnings("unchecked") public Grid getWidget() { @@ -982,6 +992,12 @@ public class GridConnector extends AbstractHasComponentsConnector implements getWidget().resetSizesFromDom(); lastKnownTheme = activeTheme; } + + // Focus and blur events + focusHandlerRegistration = EventHelper.updateFocusHandler(this, + focusHandlerRegistration); + blurHandlerRegistration = EventHelper.updateBlurHandler(this, + blurHandlerRegistration); } private void updateSelectDeselectAllowed() { @@ -1418,4 +1434,18 @@ public class GridConnector extends AbstractHasComponentsConnector implements public DetailsListener getDetailsListener() { return detailsListener; } + + @Override + public void onFocus(FocusEvent event) { + // EventHelper.updateFocusHandler ensures that this is called only when + // there is a listener on server side + getRpcProxy(FocusAndBlurServerRpc.class).focus(); + } + + @Override + public void onBlur(BlurEvent event) { + // EventHelper.updateFocusHandler ensures that this is called only when + // there is a listener on server side + getRpcProxy(FocusAndBlurServerRpc.class).blur(); + } } diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index c20bdb0bd4..9768a589f6 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -74,12 +74,14 @@ import com.google.gwt.user.client.ui.ResizeComposite; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.BrowserInfo; import com.vaadin.client.DeferredWorker; +import com.vaadin.client.Focusable; import com.vaadin.client.WidgetUtil; import com.vaadin.client.data.DataChangeHandler; import com.vaadin.client.data.DataSource; import com.vaadin.client.renderers.ComplexRenderer; import com.vaadin.client.renderers.Renderer; import com.vaadin.client.renderers.WidgetRenderer; +import com.vaadin.client.ui.FocusUtil; import com.vaadin.client.ui.SubPartAware; import com.vaadin.client.ui.dd.DragAndDropHandler; import com.vaadin.client.widget.escalator.Cell; @@ -203,8 +205,8 @@ import com.vaadin.shared.util.SharedUtil; * @author Vaadin Ltd */ public class Grid extends ResizeComposite implements - HasSelectionHandlers, SubPartAware, DeferredWorker, HasWidgets, - HasEnabled { + HasSelectionHandlers, SubPartAware, DeferredWorker, Focusable, + com.google.gwt.user.client.ui.Focusable, HasWidgets, HasEnabled { /** * Enum describing different sections of Grid. @@ -6158,6 +6160,14 @@ public class Grid extends ResizeComposite implements return; } + String eventType = event.getType(); + + if (eventType.equals(BrowserEvents.FOCUS) + || eventType.equals(BrowserEvents.BLUR)) { + super.onBrowserEvent(event); + return; + } + EventTarget target = event.getEventTarget(); if (!Element.is(target) || isOrContainsInSpacer(Element.as(target))) { @@ -6168,7 +6178,6 @@ public class Grid extends ResizeComposite implements RowContainer container = escalator.findRowContainer(e); Cell cell; - String eventType = event.getType(); if (container == null) { if (eventType.equals(BrowserEvents.KEYDOWN) || eventType.equals(BrowserEvents.KEYUP) @@ -7773,4 +7782,29 @@ public class Grid extends ResizeComposite implements sidebar.close(); } } + + @Override + public int getTabIndex() { + return FocusUtil.getTabIndex(this); + } + + @Override + public void setAccessKey(char key) { + FocusUtil.setAccessKey(this, key); + } + + @Override + public void setFocus(boolean focused) { + FocusUtil.setFocus(this, focused); + } + + @Override + public void setTabIndex(int index) { + FocusUtil.setTabIndex(this, index); + } + + @Override + public void focus() { + setFocus(true); + } } diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java index 075020b312..534146e3d7 100644 --- a/server/src/com/vaadin/ui/Grid.java +++ b/server/src/com/vaadin/ui/Grid.java @@ -172,7 +172,7 @@ import elemental.json.JsonValue; * @since 7.4 * @author Vaadin Ltd */ -public class Grid extends AbstractComponent implements SelectionNotifier, +public class Grid extends AbstractFocusable implements SelectionNotifier, SortNotifier, SelectiveRenderer, ItemClickNotifier { /** diff --git a/shared/src/com/vaadin/shared/ui/grid/GridState.java b/shared/src/com/vaadin/shared/ui/grid/GridState.java index e039f70988..bb35659591 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridState.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridState.java @@ -19,9 +19,9 @@ package com.vaadin.shared.ui.grid; import java.util.ArrayList; import java.util.List; -import com.vaadin.shared.AbstractComponentState; import com.vaadin.shared.annotations.DelegateToWidget; import com.vaadin.shared.data.sort.SortDirection; +import com.vaadin.shared.ui.TabIndexState; /** * The shared state for the {@link com.vaadin.ui.components.grid.Grid} component @@ -29,7 +29,7 @@ import com.vaadin.shared.data.sort.SortDirection; * @since 7.4 * @author Vaadin Ltd */ -public class GridState extends AbstractComponentState { +public class GridState extends TabIndexState { /** * A description of which of the three bundled SelectionModels is currently diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index 18f2d02e93..8d8be84169 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -627,7 +627,6 @@ public class GridBasicFeatures extends AbstractComponentTest { } } }); - createBooleanAction("Single select allow deselect", "State", singleSelectAllowDeselect, new Command() { @Override diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridFocusTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridFocusTest.java new file mode 100644 index 0000000000..ca9d78409c --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridFocusTest.java @@ -0,0 +1,79 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.grid.basicfeatures.server; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Before; +import org.junit.Test; + +import com.vaadin.testbench.elements.MenuBarElement; +import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest; + +/** + * Test for server-side Grid focus features. + * + * @since + * @author Vaadin Ltd + */ +public class GridFocusTest extends GridBasicFeaturesTest { + + @Before + public void setUp() { + openTestURL(); + } + + @Test + public void testFocusListener() { + selectMenuPath("Component", "Listeners", "Focus listener"); + + getGridElement().click(); + + assertTrue("Focus listener should be invoked", + getLogRow(0).contains("FocusEvent")); + } + + @Test + public void testBlurListener() { + selectMenuPath("Component", "Listeners", "Blur listener"); + + getGridElement().click(); + $(MenuBarElement.class).first().click(); + + assertTrue("Blur listener should be invoked", + getLogRow(0).contains("BlurEvent")); + } + + @Test + public void testProgrammaticFocus() { + selectMenuPath("Component", "State", "Set focus"); + + assertTrue("Grid cell (0, 0) should be focused", getGridElement() + .getCell(0, 0).isFocused()); + } + + @Test + public void testTabIndex() { + assertEquals(getGridElement().getAttribute("tabindex"), "0"); + + selectMenuPath("Component", "State", "Tab index", "-1"); + assertEquals(getGridElement().getAttribute("tabindex"), "-1"); + + selectMenuPath("Component", "State", "Tab index", "10"); + assertEquals(getGridElement().getAttribute("tabindex"), "10"); + } +} -- cgit v1.2.3 From 8ba56b9c442ee05845e5b0519c2f457c64352bd2 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Tue, 19 May 2015 19:30:06 +0300 Subject: Refactor handling of focus and blur RPC in Connectors (#17917) Change-Id: I2e4fb3fb941fda2aa4cbc7154fa9a3f7e8e9ce02 --- .../com/vaadin/client/ApplicationConnection.java | 11 ++- client/src/com/vaadin/client/EventHelper.java | 17 ++--- .../vaadin/client/connectors/GridConnector.java | 36 ++------- .../client/ui/ConnectorFocusAndBlurHandler.java | 87 ++++++++++++++++++++++ .../vaadin/client/ui/button/ButtonConnector.java | 38 +--------- .../client/ui/checkbox/CheckBoxConnector.java | 34 +-------- .../ui/nativebutton/NativeButtonConnector.java | 35 +-------- .../ui/nativeselect/NativeSelectConnector.java | 44 ++--------- 8 files changed, 121 insertions(+), 181 deletions(-) create mode 100644 client/src/com/vaadin/client/ui/ConnectorFocusAndBlurHandler.java diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index af86818fb3..a8266ad451 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -63,6 +63,7 @@ import com.google.gwt.user.client.Window.ClosingHandler; import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ApplicationConfiguration.ErrorMessage; +import com.vaadin.client.ApplicationConnection.ApplicationStoppedEvent; import com.vaadin.client.ResourceLoader.ResourceLoadEvent; import com.vaadin.client.ResourceLoader.ResourceLoadListener; import com.vaadin.client.communication.HasJavaScriptConnectorHelper; @@ -94,7 +95,6 @@ import com.vaadin.client.ui.VOverlay; import com.vaadin.client.ui.dd.VDragAndDropManager; import com.vaadin.client.ui.ui.UIConnector; import com.vaadin.client.ui.window.WindowConnector; -import com.vaadin.shared.AbstractComponentState; import com.vaadin.shared.ApplicationConstants; import com.vaadin.shared.JsonConstants; import com.vaadin.shared.VaadinUriResolver; @@ -3414,20 +3414,19 @@ public class ApplicationConnection implements HasHandlers { * before the component is updated so the value is correct if called from * updatedFromUIDL. * - * @param paintable + * @param connector * The connector to register event listeners for * @param eventIdentifier * The identifier for the event * @return true if at least one listener has been registered on server side * for the event identified by eventIdentifier. * @deprecated As of 7.0. Use - * {@link AbstractComponentState#hasEventListener(String)} - * instead + * {@link AbstractConnector#hasEventListener(String)} instead */ @Deprecated - public boolean hasEventListeners(ComponentConnector paintable, + public boolean hasEventListeners(ComponentConnector connector, String eventIdentifier) { - return paintable.hasEventListener(eventIdentifier); + return connector.hasEventListener(eventIdentifier); } /** diff --git a/client/src/com/vaadin/client/EventHelper.java b/client/src/com/vaadin/client/EventHelper.java index f251215d41..1ee252af0f 100644 --- a/client/src/com/vaadin/client/EventHelper.java +++ b/client/src/com/vaadin/client/EventHelper.java @@ -51,7 +51,6 @@ import com.google.gwt.user.client.ui.Widget; * * * - * */ public class EventHelper { @@ -69,7 +68,7 @@ public class EventHelper { */ public static HandlerRegistration updateFocusHandler( T connector, HandlerRegistration handlerRegistration) { - return updateHandler(connector, FOCUS, handlerRegistration, + return updateHandler(connector, connector, FOCUS, handlerRegistration, FocusEvent.getType(), connector.getWidget()); } @@ -89,7 +88,7 @@ public class EventHelper { */ public static HandlerRegistration updateFocusHandler( T connector, HandlerRegistration handlerRegistration, Widget widget) { - return updateHandler(connector, FOCUS, handlerRegistration, + return updateHandler(connector, connector, FOCUS, handlerRegistration, FocusEvent.getType(), widget); } @@ -107,7 +106,7 @@ public class EventHelper { */ public static HandlerRegistration updateBlurHandler( T connector, HandlerRegistration handlerRegistration) { - return updateHandler(connector, BLUR, handlerRegistration, + return updateHandler(connector, connector, BLUR, handlerRegistration, BlurEvent.getType(), connector.getWidget()); } @@ -128,23 +127,21 @@ public class EventHelper { */ public static HandlerRegistration updateBlurHandler( T connector, HandlerRegistration handlerRegistration, Widget widget) { - return updateHandler(connector, BLUR, handlerRegistration, + return updateHandler(connector, connector, BLUR, handlerRegistration, BlurEvent.getType(), widget); } - private static HandlerRegistration updateHandler( - ComponentConnector connector, String eventIdentifier, + public static HandlerRegistration updateHandler( + ComponentConnector connector, H handler, String eventIdentifier, HandlerRegistration handlerRegistration, Type type, Widget widget) { if (connector.hasEventListener(eventIdentifier)) { if (handlerRegistration == null) { - handlerRegistration = widget.addDomHandler((H) connector, type); + handlerRegistration = widget.addDomHandler(handler, type); } } else if (handlerRegistration != null) { handlerRegistration.removeHandler(); handlerRegistration = null; } return handlerRegistration; - } - } diff --git a/client/src/com/vaadin/client/connectors/GridConnector.java b/client/src/com/vaadin/client/connectors/GridConnector.java index 3eb92ab94c..47b21a3429 100644 --- a/client/src/com/vaadin/client/connectors/GridConnector.java +++ b/client/src/com/vaadin/client/connectors/GridConnector.java @@ -32,17 +32,11 @@ import java.util.logging.Logger; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.NativeEvent; -import com.google.gwt.event.dom.client.BlurEvent; -import com.google.gwt.event.dom.client.BlurHandler; -import com.google.gwt.event.dom.client.FocusEvent; -import com.google.gwt.event.dom.client.FocusHandler; -import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ComponentConnector; import com.vaadin.client.ConnectorHierarchyChangeEvent; import com.vaadin.client.DeferredWorker; -import com.vaadin.client.EventHelper; import com.vaadin.client.MouseEventDetailsBuilder; import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.communication.StateChangeEvent; @@ -52,6 +46,7 @@ import com.vaadin.client.data.DataSource.RowHandle; import com.vaadin.client.renderers.Renderer; import com.vaadin.client.ui.AbstractFieldConnector; import com.vaadin.client.ui.AbstractHasComponentsConnector; +import com.vaadin.client.ui.ConnectorFocusAndBlurHandler; import com.vaadin.client.ui.SimpleManagedLayout; import com.vaadin.client.widget.grid.CellReference; import com.vaadin.client.widget.grid.CellStyleGenerator; @@ -86,7 +81,6 @@ import com.vaadin.client.widgets.Grid.FooterRow; import com.vaadin.client.widgets.Grid.HeaderCell; import com.vaadin.client.widgets.Grid.HeaderRow; import com.vaadin.shared.Connector; -import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc; import com.vaadin.shared.data.sort.SortDirection; import com.vaadin.shared.ui.Connect; import com.vaadin.shared.ui.grid.DetailsConnectorChange; @@ -119,7 +113,7 @@ import elemental.json.JsonValue; */ @Connect(com.vaadin.ui.Grid.class) public class GridConnector extends AbstractHasComponentsConnector implements - SimpleManagedLayout, DeferredWorker, FocusHandler, BlurHandler { + SimpleManagedLayout, DeferredWorker { private static final class CustomCellStyleGenerator implements CellStyleGenerator { @@ -764,9 +758,6 @@ public class GridConnector extends AbstractHasComponentsConnector implements private final LazyDetailsScrollAdjuster lazyDetailsScrollAdjuster = new LazyDetailsScrollAdjuster(); - private HandlerRegistration focusHandlerRegistration = null; - private HandlerRegistration blurHandlerRegistration = null; - @Override @SuppressWarnings("unchecked") public Grid getWidget() { @@ -915,6 +906,9 @@ public class GridConnector extends AbstractHasComponentsConnector implements getWidget().addColumnReorderHandler(columnReorderHandler); getWidget().addColumnVisibilityChangeHandler( columnVisibilityChangeHandler); + + ConnectorFocusAndBlurHandler.addHandlers(this); + getWidget().setDetailsGenerator(customDetailsGenerator); getLayoutManager().registerDependency(this, getWidget().getElement()); @@ -992,12 +986,6 @@ public class GridConnector extends AbstractHasComponentsConnector implements getWidget().resetSizesFromDom(); lastKnownTheme = activeTheme; } - - // Focus and blur events - focusHandlerRegistration = EventHelper.updateFocusHandler(this, - focusHandlerRegistration); - blurHandlerRegistration = EventHelper.updateBlurHandler(this, - blurHandlerRegistration); } private void updateSelectDeselectAllowed() { @@ -1434,18 +1422,4 @@ public class GridConnector extends AbstractHasComponentsConnector implements public DetailsListener getDetailsListener() { return detailsListener; } - - @Override - public void onFocus(FocusEvent event) { - // EventHelper.updateFocusHandler ensures that this is called only when - // there is a listener on server side - getRpcProxy(FocusAndBlurServerRpc.class).focus(); - } - - @Override - public void onBlur(BlurEvent event) { - // EventHelper.updateFocusHandler ensures that this is called only when - // there is a listener on server side - getRpcProxy(FocusAndBlurServerRpc.class).blur(); - } } diff --git a/client/src/com/vaadin/client/ui/ConnectorFocusAndBlurHandler.java b/client/src/com/vaadin/client/ui/ConnectorFocusAndBlurHandler.java new file mode 100644 index 0000000000..817d070a9f --- /dev/null +++ b/client/src/com/vaadin/client/ui/ConnectorFocusAndBlurHandler.java @@ -0,0 +1,87 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.ui; + +import com.google.gwt.event.dom.client.BlurEvent; +import com.google.gwt.event.dom.client.BlurHandler; +import com.google.gwt.event.dom.client.FocusEvent; +import com.google.gwt.event.dom.client.FocusHandler; +import com.google.gwt.event.shared.HandlerRegistration; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.client.EventHelper; +import com.vaadin.client.communication.StateChangeEvent; +import com.vaadin.client.communication.StateChangeEvent.StateChangeHandler; +import com.vaadin.shared.EventId; +import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc; + +/** + * A handler for focus and blur events which uses {@link FocusAndBlurServerRpc} + * to transmit received events to the server. Events are only handled if there + * is a corresponding listener on the server side. + * + * @since + * @author Vaadin Ltd + */ +public class ConnectorFocusAndBlurHandler implements StateChangeHandler, + FocusHandler, BlurHandler { + + private final AbstractComponentConnector connector; + private final Widget widget; + private HandlerRegistration focusRegistration = null; + private HandlerRegistration blurRegistration = null; + + public static void addHandlers(AbstractComponentConnector connector) { + addHandlers(connector, connector.getWidget()); + } + + public static void addHandlers(AbstractComponentConnector connector, + Widget widget) { + connector.addStateChangeHandler("registeredEventListeners", + new ConnectorFocusAndBlurHandler(connector, widget)); + } + + private ConnectorFocusAndBlurHandler(AbstractComponentConnector connector, + Widget widget) { + this.connector = connector; + this.widget = widget; + } + + @Override + public void onStateChanged(StateChangeEvent stateChangeEvent) { + focusRegistration = EventHelper.updateHandler(connector, this, + EventId.FOCUS, focusRegistration, FocusEvent.getType(), widget); + blurRegistration = EventHelper.updateHandler(connector, this, + EventId.BLUR, blurRegistration, BlurEvent.getType(), widget); + } + + @Override + public void onFocus(FocusEvent event) { + // updateHandler ensures that this is called only when + // there is a listener on the server side + getRpc().focus(); + } + + @Override + public void onBlur(BlurEvent event) { + // updateHandler ensures that this is called only when + // there is a listener on the server side + getRpc().blur(); + } + + private FocusAndBlurServerRpc getRpc() { + return connector.getRpcProxy(FocusAndBlurServerRpc.class); + } +} diff --git a/client/src/com/vaadin/client/ui/button/ButtonConnector.java b/client/src/com/vaadin/client/ui/button/ButtonConnector.java index 2d13d62a91..2c2006e19b 100644 --- a/client/src/com/vaadin/client/ui/button/ButtonConnector.java +++ b/client/src/com/vaadin/client/ui/button/ButtonConnector.java @@ -16,24 +16,17 @@ package com.vaadin.client.ui.button; -import com.google.gwt.event.dom.client.BlurEvent; -import com.google.gwt.event.dom.client.BlurHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.event.dom.client.FocusEvent; -import com.google.gwt.event.dom.client.FocusHandler; -import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.DOM; -import com.vaadin.client.EventHelper; import com.vaadin.client.MouseEventDetailsBuilder; import com.vaadin.client.VCaption; import com.vaadin.client.annotations.OnStateChange; -import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.AbstractComponentConnector; +import com.vaadin.client.ui.ConnectorFocusAndBlurHandler; import com.vaadin.client.ui.Icon; import com.vaadin.client.ui.VButton; import com.vaadin.shared.MouseEventDetails; -import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc; import com.vaadin.shared.ui.Connect; import com.vaadin.shared.ui.Connect.LoadStyle; import com.vaadin.shared.ui.button.ButtonServerRpc; @@ -42,10 +35,7 @@ import com.vaadin.ui.Button; @Connect(value = Button.class, loadStyle = LoadStyle.EAGER) public class ButtonConnector extends AbstractComponentConnector implements - BlurHandler, FocusHandler, ClickHandler { - - private HandlerRegistration focusHandlerRegistration = null; - private HandlerRegistration blurHandlerRegistration = null; + ClickHandler { @Override public boolean delegateCaptionHandling() { @@ -57,6 +47,7 @@ public class ButtonConnector extends AbstractComponentConnector implements super.init(); getWidget().addClickHandler(this); getWidget().client = getConnection(); + ConnectorFocusAndBlurHandler.addHandlers(this); } @OnStateChange("errorMessage") @@ -90,15 +81,6 @@ public class ButtonConnector extends AbstractComponentConnector implements } } - @Override - public void onStateChanged(StateChangeEvent stateChangeEvent) { - super.onStateChanged(stateChangeEvent); - focusHandlerRegistration = EventHelper.updateFocusHandler(this, - focusHandlerRegistration); - blurHandlerRegistration = EventHelper.updateBlurHandler(this, - blurHandlerRegistration); - } - @OnStateChange({ "caption", "captionAsHtml" }) void setCaption() { VCaption.setCaptionText(getWidget().captionElement, getState()); @@ -126,20 +108,6 @@ public class ButtonConnector extends AbstractComponentConnector implements return (ButtonState) super.getState(); } - @Override - public void onFocus(FocusEvent event) { - // EventHelper.updateFocusHandler ensures that this is called only when - // there is a listener on server side - getRpcProxy(FocusAndBlurServerRpc.class).focus(); - } - - @Override - public void onBlur(BlurEvent event) { - // EventHelper.updateFocusHandler ensures that this is called only when - // there is a listener on server side - getRpcProxy(FocusAndBlurServerRpc.class).blur(); - } - @Override public void onClick(ClickEvent event) { if (getState().disableOnClick) { diff --git a/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java b/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java index 63984ff225..3daac849d0 100644 --- a/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java +++ b/client/src/com/vaadin/client/ui/checkbox/CheckBoxConnector.java @@ -16,25 +16,19 @@ package com.vaadin.client.ui.checkbox; import com.google.gwt.dom.client.Style.Display; -import com.google.gwt.event.dom.client.BlurEvent; -import com.google.gwt.event.dom.client.BlurHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.event.dom.client.FocusEvent; -import com.google.gwt.event.dom.client.FocusHandler; -import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Event; -import com.vaadin.client.EventHelper; import com.vaadin.client.MouseEventDetailsBuilder; import com.vaadin.client.VCaption; import com.vaadin.client.VTooltip; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.AbstractFieldConnector; +import com.vaadin.client.ui.ConnectorFocusAndBlurHandler; import com.vaadin.client.ui.Icon; import com.vaadin.client.ui.VCheckBox; import com.vaadin.shared.MouseEventDetails; -import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc; import com.vaadin.shared.ui.Connect; import com.vaadin.shared.ui.checkbox.CheckBoxServerRpc; import com.vaadin.shared.ui.checkbox.CheckBoxState; @@ -42,10 +36,7 @@ import com.vaadin.ui.CheckBox; @Connect(CheckBox.class) public class CheckBoxConnector extends AbstractFieldConnector implements - FocusHandler, BlurHandler, ClickHandler { - - private HandlerRegistration focusHandlerRegistration; - private HandlerRegistration blurHandlerRegistration; + ClickHandler { @Override public boolean delegateCaptionHandling() { @@ -55,21 +46,18 @@ public class CheckBoxConnector extends AbstractFieldConnector implements @Override protected void init() { super.init(); + getWidget().addClickHandler(this); getWidget().client = getConnection(); getWidget().id = getConnectorId(); + ConnectorFocusAndBlurHandler.addHandlers(this); } @Override public void onStateChanged(StateChangeEvent stateChangeEvent) { super.onStateChanged(stateChangeEvent); - focusHandlerRegistration = EventHelper.updateFocusHandler(this, - focusHandlerRegistration); - blurHandlerRegistration = EventHelper.updateBlurHandler(this, - blurHandlerRegistration); - if (null != getState().errorMessage) { getWidget().setAriaInvalid(true); @@ -126,20 +114,6 @@ public class CheckBoxConnector extends AbstractFieldConnector implements return (VCheckBox) super.getWidget(); } - @Override - public void onFocus(FocusEvent event) { - // EventHelper.updateFocusHandler ensures that this is called only when - // there is a listener on server side - getRpcProxy(FocusAndBlurServerRpc.class).focus(); - } - - @Override - public void onBlur(BlurEvent event) { - // EventHelper.updateFocusHandler ensures that this is called only when - // there is a listener on server side - getRpcProxy(FocusAndBlurServerRpc.class).blur(); - } - @Override public void onClick(ClickEvent event) { if (!isEnabled()) { diff --git a/client/src/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java b/client/src/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java index 2aae9beae6..65d4a1eb9b 100644 --- a/client/src/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java +++ b/client/src/com/vaadin/client/ui/nativebutton/NativeButtonConnector.java @@ -15,30 +15,20 @@ */ package com.vaadin.client.ui.nativebutton; -import com.google.gwt.event.dom.client.BlurEvent; -import com.google.gwt.event.dom.client.BlurHandler; -import com.google.gwt.event.dom.client.FocusEvent; -import com.google.gwt.event.dom.client.FocusHandler; -import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.DOM; -import com.vaadin.client.EventHelper; import com.vaadin.client.VCaption; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.AbstractComponentConnector; +import com.vaadin.client.ui.ConnectorFocusAndBlurHandler; import com.vaadin.client.ui.Icon; import com.vaadin.client.ui.VNativeButton; -import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc; import com.vaadin.shared.ui.Connect; import com.vaadin.shared.ui.button.ButtonServerRpc; import com.vaadin.shared.ui.button.NativeButtonState; import com.vaadin.ui.NativeButton; @Connect(NativeButton.class) -public class NativeButtonConnector extends AbstractComponentConnector implements - BlurHandler, FocusHandler { - - private HandlerRegistration focusHandlerRegistration; - private HandlerRegistration blurHandlerRegistration; +public class NativeButtonConnector extends AbstractComponentConnector { @Override public void init() { @@ -47,6 +37,8 @@ public class NativeButtonConnector extends AbstractComponentConnector implements getWidget().buttonRpcProxy = getRpcProxy(ButtonServerRpc.class); getWidget().client = getConnection(); getWidget().paintableId = getConnectorId(); + + ConnectorFocusAndBlurHandler.addHandlers(this); } @Override @@ -59,10 +51,6 @@ public class NativeButtonConnector extends AbstractComponentConnector implements super.onStateChanged(stateChangeEvent); getWidget().disableOnClick = getState().disableOnClick; - focusHandlerRegistration = EventHelper.updateFocusHandler(this, - focusHandlerRegistration); - blurHandlerRegistration = EventHelper.updateBlurHandler(this, - blurHandlerRegistration); // Set text VCaption.setCaptionText(getWidget(), getState()); @@ -107,19 +95,4 @@ public class NativeButtonConnector extends AbstractComponentConnector implements public NativeButtonState getState() { return (NativeButtonState) super.getState(); } - - @Override - public void onFocus(FocusEvent event) { - // EventHelper.updateFocusHandler ensures that this is called only when - // there is a listener on server side - getRpcProxy(FocusAndBlurServerRpc.class).focus(); - } - - @Override - public void onBlur(BlurEvent event) { - // EventHelper.updateFocusHandler ensures that this is called only when - // there is a listener on server side - getRpcProxy(FocusAndBlurServerRpc.class).blur(); - } - } diff --git a/client/src/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java b/client/src/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java index 938903da9a..d6ff2015b4 100644 --- a/client/src/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java +++ b/client/src/com/vaadin/client/ui/nativeselect/NativeSelectConnector.java @@ -16,55 +16,23 @@ package com.vaadin.client.ui.nativeselect; -import com.google.gwt.event.dom.client.BlurEvent; -import com.google.gwt.event.dom.client.BlurHandler; -import com.google.gwt.event.dom.client.FocusEvent; -import com.google.gwt.event.dom.client.FocusHandler; -import com.google.gwt.event.shared.HandlerRegistration; -import com.vaadin.client.EventHelper; -import com.vaadin.client.annotations.OnStateChange; +import com.vaadin.client.ui.ConnectorFocusAndBlurHandler; import com.vaadin.client.ui.VNativeSelect; import com.vaadin.client.ui.optiongroup.OptionGroupBaseConnector; -import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc; import com.vaadin.shared.ui.Connect; import com.vaadin.ui.NativeSelect; @Connect(NativeSelect.class) -public class NativeSelectConnector extends OptionGroupBaseConnector implements - BlurHandler, FocusHandler { +public class NativeSelectConnector extends OptionGroupBaseConnector { - private HandlerRegistration focusHandlerRegistration = null; - private HandlerRegistration blurHandlerRegistration = null; - - public NativeSelectConnector() { - super(); - } - - @OnStateChange("registeredEventListeners") - private void onServerEventListenerChanged() { - focusHandlerRegistration = EventHelper.updateFocusHandler(this, - focusHandlerRegistration, getWidget().getSelect()); - blurHandlerRegistration = EventHelper.updateBlurHandler(this, - blurHandlerRegistration, getWidget().getSelect()); + @Override + protected void init() { + super.init(); + ConnectorFocusAndBlurHandler.addHandlers(this, getWidget().getSelect()); } @Override public VNativeSelect getWidget() { return (VNativeSelect) super.getWidget(); } - - @Override - public void onFocus(FocusEvent event) { - // EventHelper.updateFocusHandler ensures that this is called only when - // there is a listener on server side - getRpcProxy(FocusAndBlurServerRpc.class).focus(); - } - - @Override - public void onBlur(BlurEvent event) { - // EventHelper.updateFocusHandler ensures that this is called only when - // there is a listener on server side - getRpcProxy(FocusAndBlurServerRpc.class).blur(); - } - } -- cgit v1.2.3 From fad6e73e62c53802092e824c67dd901e73683e6a Mon Sep 17 00:00:00 2001 From: patrik Date: Mon, 18 May 2015 14:36:18 +0300 Subject: Add grid editor events (#17451) Change-Id: Iebc4aece2a5be6b51289f5c2abf2d54d146621ae --- .../vaadin/client/connectors/GridConnector.java | 30 +++++ .../widget/grid/events/EditorCloseEvent.java | 34 +++++ .../client/widget/grid/events/EditorEvent.java | 108 +++++++++++++++ .../widget/grid/events/EditorEventHandler.java | 49 +++++++ .../client/widget/grid/events/EditorMoveEvent.java | 34 +++++ .../client/widget/grid/events/EditorOpenEvent.java | 34 +++++ client/src/com/vaadin/client/widgets/Grid.java | 35 ++++- server/src/com/vaadin/ui/Grid.java | 145 +++++++++++++++++++++ .../com/vaadin/shared/ui/grid/GridConstants.java | 15 +++ .../com/vaadin/shared/ui/grid/GridServerRpc.java | 25 ++++ .../grid/basicfeatures/GridBasicFeatures.java | 29 +++++ 11 files changed, 537 insertions(+), 1 deletion(-) create mode 100644 client/src/com/vaadin/client/widget/grid/events/EditorCloseEvent.java create mode 100644 client/src/com/vaadin/client/widget/grid/events/EditorEvent.java create mode 100644 client/src/com/vaadin/client/widget/grid/events/EditorEventHandler.java create mode 100644 client/src/com/vaadin/client/widget/grid/events/EditorMoveEvent.java create mode 100644 client/src/com/vaadin/client/widget/grid/events/EditorOpenEvent.java diff --git a/client/src/com/vaadin/client/connectors/GridConnector.java b/client/src/com/vaadin/client/connectors/GridConnector.java index 47b21a3429..2542e80075 100644 --- a/client/src/com/vaadin/client/connectors/GridConnector.java +++ b/client/src/com/vaadin/client/connectors/GridConnector.java @@ -60,6 +60,10 @@ import com.vaadin.client.widget.grid.events.ColumnReorderEvent; import com.vaadin.client.widget.grid.events.ColumnReorderHandler; import com.vaadin.client.widget.grid.events.ColumnVisibilityChangeEvent; import com.vaadin.client.widget.grid.events.ColumnVisibilityChangeHandler; +import com.vaadin.client.widget.grid.events.EditorCloseEvent; +import com.vaadin.client.widget.grid.events.EditorEventHandler; +import com.vaadin.client.widget.grid.events.EditorMoveEvent; +import com.vaadin.client.widget.grid.events.EditorOpenEvent; import com.vaadin.client.widget.grid.events.GridClickEvent; import com.vaadin.client.widget.grid.events.GridDoubleClickEvent; import com.vaadin.client.widget.grid.events.SelectAllEvent; @@ -912,6 +916,32 @@ public class GridConnector extends AbstractHasComponentsConnector implements getWidget().setDetailsGenerator(customDetailsGenerator); getLayoutManager().registerDependency(this, getWidget().getElement()); + getWidget().addEditorEventHandler(new EditorEventHandler() { + @Override + public void onEditorOpen(EditorOpenEvent e) { + if (hasEventListener(GridConstants.EDITOR_OPEN_EVENT_ID)) { + String rowKey = getRowKey((JsonObject) e.getRow()); + getRpcProxy(GridServerRpc.class).editorOpen(rowKey); + } + } + + @Override + public void onEditorMove(EditorMoveEvent e) { + if (hasEventListener(GridConstants.EDITOR_MOVE_EVENT_ID)) { + String rowKey = getRowKey((JsonObject) e.getRow()); + getRpcProxy(GridServerRpc.class).editorMove(rowKey); + } + } + + @Override + public void onEditorClose(EditorCloseEvent e) { + if (hasEventListener(GridConstants.EDITOR_CLOSE_EVENT_ID)) { + String rowKey = getRowKey((JsonObject) e.getRow()); + getRpcProxy(GridServerRpc.class).editorClose(rowKey); + } + } + }); + layout(); } diff --git a/client/src/com/vaadin/client/widget/grid/events/EditorCloseEvent.java b/client/src/com/vaadin/client/widget/grid/events/EditorCloseEvent.java new file mode 100644 index 0000000000..99f59aa82a --- /dev/null +++ b/client/src/com/vaadin/client/widget/grid/events/EditorCloseEvent.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.widget.grid.events; + +import com.vaadin.client.widget.grid.CellReference; + +/** + * Event that gets fired when an open editor is closed (and not reopened + * elsewhere) + */ +public class EditorCloseEvent extends EditorEvent { + + public EditorCloseEvent(CellReference cell) { + super(cell); + } + + @Override + protected void dispatch(EditorEventHandler handler) { + handler.onEditorClose(this); + } +} \ No newline at end of file diff --git a/client/src/com/vaadin/client/widget/grid/events/EditorEvent.java b/client/src/com/vaadin/client/widget/grid/events/EditorEvent.java new file mode 100644 index 0000000000..eb34033197 --- /dev/null +++ b/client/src/com/vaadin/client/widget/grid/events/EditorEvent.java @@ -0,0 +1,108 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.widget.grid.events; + +import com.google.gwt.event.shared.GwtEvent; +import com.vaadin.client.widget.grid.CellReference; +import com.vaadin.client.widgets.Grid; +import com.vaadin.client.widgets.Grid.Column; + +/** + * Base class for editor events. + */ +public abstract class EditorEvent extends GwtEvent { + public static final Type TYPE = new Type(); + + private CellReference cell; + + protected EditorEvent(CellReference cell) { + this.cell = cell; + } + + @Override + public Type getAssociatedType() { + return TYPE; + } + + /** + * Get a reference to the Grid that fired this Event. + * + * @return a Grid reference + */ + @SuppressWarnings("unchecked") + public Grid getGrid() { + return (Grid) cell.getGrid(); + } + + /** + * Get a reference to the cell that was active when this Event was fired. + * NOTE: do NOT rely on this information remaining accurate after + * leaving the event handler. + * + * @return a cell reference + */ + @SuppressWarnings("unchecked") + public CellReference getCell() { + return (CellReference) cell; + } + + /** + * Get a reference to the row that was active when this Event was fired. + * NOTE: do NOT rely on this information remaining accurate after + * leaving the event handler. + * + * @return a row data object + */ + @SuppressWarnings("unchecked") + public T getRow() { + return (T) cell.getRow(); + } + + /** + * Get the index of the row that was active when this Event was fired. NOTE: + * do NOT rely on this information remaining accurate after leaving + * the event handler. + * + * @return an integer value + */ + public int getRowIndex() { + return cell.getRowIndex(); + } + + /** + * Get a reference to the column that was active when this Event was fired. + * NOTE: do NOT rely on this information remaining accurate after + * leaving the event handler. + * + * @return a column object + */ + @SuppressWarnings("unchecked") + public Column getColumn() { + return (Column) cell.getColumn(); + } + + /** + * Get the index of the column that was active when this Event was fired. + * NOTE: do NOT rely on this information remaining accurate after + * leaving the event handler. + * + * @return an integer value + */ + public int getColumnIndex() { + return cell.getColumnIndex(); + } + +} \ No newline at end of file diff --git a/client/src/com/vaadin/client/widget/grid/events/EditorEventHandler.java b/client/src/com/vaadin/client/widget/grid/events/EditorEventHandler.java new file mode 100644 index 0000000000..4f9396a9f1 --- /dev/null +++ b/client/src/com/vaadin/client/widget/grid/events/EditorEventHandler.java @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.widget.grid.events; + +import com.google.gwt.event.shared.EventHandler; + +/** + * Common handler interface for editor events + */ +public interface EditorEventHandler extends EventHandler { + + /** + * Action to perform when the editor has been opened + * + * @param e + * an editor open event object + */ + public void onEditorOpen(EditorOpenEvent e); + + /** + * Action to perform when the editor is re-opened on another row + * + * @param e + * an editor move event object + */ + public void onEditorMove(EditorMoveEvent e); + + /** + * Action to perform when the editor is closed + * + * @param e + * an editor close event object + */ + public void onEditorClose(EditorCloseEvent e); + +} \ No newline at end of file diff --git a/client/src/com/vaadin/client/widget/grid/events/EditorMoveEvent.java b/client/src/com/vaadin/client/widget/grid/events/EditorMoveEvent.java new file mode 100644 index 0000000000..0e5e2dcd7b --- /dev/null +++ b/client/src/com/vaadin/client/widget/grid/events/EditorMoveEvent.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.widget.grid.events; + +import com.vaadin.client.widget.grid.CellReference; + +/** + * Event that gets fired when an already open editor is closed and re-opened on + * another row + */ +public class EditorMoveEvent extends EditorEvent { + + public EditorMoveEvent(CellReference cell) { + super(cell); + } + + @Override + protected void dispatch(EditorEventHandler handler) { + handler.onEditorMove(this); + } +} \ No newline at end of file diff --git a/client/src/com/vaadin/client/widget/grid/events/EditorOpenEvent.java b/client/src/com/vaadin/client/widget/grid/events/EditorOpenEvent.java new file mode 100644 index 0000000000..df0171945f --- /dev/null +++ b/client/src/com/vaadin/client/widget/grid/events/EditorOpenEvent.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.widget.grid.events; + +import com.vaadin.client.widget.grid.CellReference; + +/** + * Event that gets fired when the editor is opened + */ +public class EditorOpenEvent extends EditorEvent { + + public EditorOpenEvent(CellReference cell) { + super(cell); + } + + @Override + protected void dispatch(EditorEventHandler handler) { + handler.onEditorOpen(this); + } + +} \ No newline at end of file diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 9768a589f6..21cf84cc0d 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -120,6 +120,11 @@ import com.vaadin.client.widget.grid.events.ColumnReorderEvent; import com.vaadin.client.widget.grid.events.ColumnReorderHandler; import com.vaadin.client.widget.grid.events.ColumnVisibilityChangeEvent; import com.vaadin.client.widget.grid.events.ColumnVisibilityChangeHandler; +import com.vaadin.client.widget.grid.events.EditorCloseEvent; +import com.vaadin.client.widget.grid.events.EditorEvent; +import com.vaadin.client.widget.grid.events.EditorEventHandler; +import com.vaadin.client.widget.grid.events.EditorMoveEvent; +import com.vaadin.client.widget.grid.events.EditorOpenEvent; import com.vaadin.client.widget.grid.events.FooterClickHandler; import com.vaadin.client.widget.grid.events.FooterDoubleClickHandler; import com.vaadin.client.widget.grid.events.FooterKeyDownHandler; @@ -1188,6 +1193,7 @@ public class Grid extends ResizeComposite implements + " remember to call success() or fail()?"); } }; + private final EditorRequestImpl.RequestCallback bindRequestCallback = new EditorRequestImpl.RequestCallback() { @Override public void onSuccess(EditorRequest request) { @@ -1313,6 +1319,7 @@ public class Grid extends ResizeComposite implements handler.cancel(request); state = State.INACTIVE; updateSelectionCheckboxesAsNeeded(true); + grid.fireEvent(new EditorCloseEvent(grid.eventCell)); } private void updateSelectionCheckboxesAsNeeded(boolean isEnabled) { @@ -5706,6 +5713,19 @@ public class Grid extends ResizeComposite implements return editor; } + /** + * Add handler for editor open/move/close events + * + * @param handler + * editor handler object + * @return a {@link HandlerRegistration} object that can be used to remove + * the event handler + */ + public HandlerRegistration addEditorEventHandler(EditorEventHandler handler) { + return addHandler(handler, EditorEvent.TYPE); + + } + protected Escalator getEscalator() { return escalator; } @@ -6285,12 +6305,25 @@ public class Grid extends ResizeComposite implements } if (container == escalator.getBody() && editor.isEnabled()) { + + boolean wasOpen = editor.getState() != Editor.State.INACTIVE; + boolean opened = false; + if (event.getTypeInt() == Event.ONDBLCLICK) { editor.editRow(eventCell.getRowIndex()); - return true; + opened = true; } else if (event.getTypeInt() == Event.ONKEYDOWN && event.getKeyCode() == Editor.KEYCODE_SHOW) { editor.editRow(cellFocusHandler.rowWithFocus); + opened = true; + } + + if (opened) { + if (wasOpen) { + fireEvent(new EditorMoveEvent(eventCell)); + } else { + fireEvent(new EditorOpenEvent(eventCell)); + } return true; } } diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java index 534146e3d7..21bfd1b68f 100644 --- a/server/src/com/vaadin/ui/Grid.java +++ b/server/src/com/vaadin/ui/Grid.java @@ -57,6 +57,7 @@ import com.vaadin.data.RpcDataProviderExtension.DetailComponentManager; import com.vaadin.data.Validator.InvalidValueException; import com.vaadin.data.fieldgroup.DefaultFieldGroupFieldFactory; import com.vaadin.data.fieldgroup.FieldGroup; +import com.vaadin.data.fieldgroup.FieldGroup.BindException; import com.vaadin.data.fieldgroup.FieldGroup.CommitException; import com.vaadin.data.fieldgroup.FieldGroupFieldFactory; import com.vaadin.data.sort.Sort; @@ -510,6 +511,100 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, } + /** + * Interface for an editor event listener + */ + public interface EditorListener extends Serializable { + + public static final Method EDITOR_OPEN_METHOD = ReflectTools + .findMethod(EditorListener.class, "editorOpened", + EditorOpenEvent.class); + public static final Method EDITOR_MOVE_METHOD = ReflectTools + .findMethod(EditorListener.class, "editorMoved", + EditorMoveEvent.class); + public static final Method EDITOR_CLOSE_METHOD = ReflectTools + .findMethod(EditorListener.class, "editorClosed", + EditorCloseEvent.class); + + /** + * Called when an editor is opened + * + * @param e + * an editor open event object + */ + public void editorOpened(EditorOpenEvent e); + + /** + * Called when an editor is reopened without closing it first + * + * @param e + * an editor move event object + */ + public void editorMoved(EditorMoveEvent e); + + /** + * Called when an editor is closed + * + * @param e + * an editor close event object + */ + public void editorClosed(EditorCloseEvent e); + + } + + /** + * Base class for editor related events + */ + public static abstract class EditorEvent extends Component.Event { + + private Object itemID; + + protected EditorEvent(Grid source, Object itemID) { + super(source); + this.itemID = itemID; + } + + /** + * Get the item (row) for which this editor was opened + */ + public Object getItem() { + return itemID; + } + + } + + /** + * This event gets fired when an editor is opened + */ + public static class EditorOpenEvent extends EditorEvent { + + public EditorOpenEvent(Grid source, Object itemID) { + super(source, itemID); + } + } + + /** + * This event gets fired when an editor is opened while another row is being + * edited (i.e. editor focus moves elsewhere) + */ + public static class EditorMoveEvent extends EditorEvent { + + public EditorMoveEvent(Grid source, Object itemID) { + super(source, itemID); + } + } + + /** + * This event gets fired when an editor is dismissed or closed by other + * means. + */ + public static class EditorCloseEvent extends EditorEvent { + + public EditorCloseEvent(Grid source, Object itemID) { + super(source, itemID); + } + } + /** * Default error handler for the editor * @@ -3808,6 +3903,24 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, detailComponentManager.getAndResetConnectorChanges(), fetchId); } + + @Override + public void editorOpen(String rowKey) { + fireEvent(new EditorOpenEvent(Grid.this, getKeyMapper() + .getItemId(rowKey))); + } + + @Override + public void editorMove(String rowKey) { + fireEvent(new EditorMoveEvent(Grid.this, getKeyMapper() + .getItemId(rowKey))); + } + + @Override + public void editorClose(String rowKey) { + fireEvent(new EditorCloseEvent(Grid.this, getKeyMapper() + .getItemId(rowKey))); + } }); registerRpc(new EditorServerRpc() { @@ -5875,6 +5988,37 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, return getState(false).editorCancelCaption; } + /** + * Add an editor event listener + * + * @param listener + * the event listener object to add + */ + public void addEditorListener(EditorListener listener) { + addListener(GridConstants.EDITOR_OPEN_EVENT_ID, EditorOpenEvent.class, + listener, EditorListener.EDITOR_OPEN_METHOD); + addListener(GridConstants.EDITOR_MOVE_EVENT_ID, EditorMoveEvent.class, + listener, EditorListener.EDITOR_MOVE_METHOD); + addListener(GridConstants.EDITOR_CLOSE_EVENT_ID, + EditorCloseEvent.class, listener, + EditorListener.EDITOR_CLOSE_METHOD); + } + + /** + * Remove an editor event listener + * + * @param listener + * the event listener object to remove + */ + public void removeEditorListener(EditorListener listener) { + removeListener(GridConstants.EDITOR_OPEN_EVENT_ID, + EditorOpenEvent.class, listener); + removeListener(GridConstants.EDITOR_MOVE_EVENT_ID, + EditorMoveEvent.class, listener); + removeListener(GridConstants.EDITOR_CLOSE_EVENT_ID, + EditorCloseEvent.class, listener); + } + @Override public void addItemClickListener(ItemClickListener listener) { addListener(GridConstants.ITEM_CLICK_EVENT_ID, ItemClickEvent.class, @@ -6169,6 +6313,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, result.add("footer-visible"); result.add("editor-error-handler"); result.add("height-mode"); + return result; } } diff --git a/shared/src/com/vaadin/shared/ui/grid/GridConstants.java b/shared/src/com/vaadin/shared/ui/grid/GridConstants.java index 0606e4b1cc..5b2ac96975 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridConstants.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridConstants.java @@ -74,4 +74,19 @@ public final class GridConstants implements Serializable { /** The default cancel button caption in the editor */ public static final String DEFAULT_CANCEL_CAPTION = "Cancel"; + + /** + * Event ID constant for editor open event + */ + public static final String EDITOR_OPEN_EVENT_ID = "editorOpen"; + + /** + * Event ID constant for editor move event + */ + public static final String EDITOR_MOVE_EVENT_ID = "editorMove"; + + /** + * Event ID constant for editor close event + */ + public static final String EDITOR_CLOSE_EVENT_ID = "editorClose"; } diff --git a/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java index dca55c11c4..99b339765a 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java @@ -36,6 +36,31 @@ public interface GridServerRpc extends ServerRpc { void sort(String[] columnIds, SortDirection[] directions, boolean userOriginated); + /** + * Informs the server that the editor was opened (fresh) on a certain row + * + * @param rowKey + * a key identifying item the editor was opened on + */ + void editorOpen(String rowKey); + + /** + * Informs the server that the editor was reopened (without closing it in + * between) on another row + * + * @param rowKey + * a key identifying item the editor was opened on + */ + void editorMove(String rowKey); + + /** + * Informs the server that the editor was closed + * + * @param rowKey + * a key identifying item the editor was opened on + */ + void editorClose(String rowKey); + /** * Informs the server that an item has been clicked in Grid. * diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index 8d8be84169..181f99a2c7 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -57,6 +57,10 @@ import com.vaadin.ui.Grid.ColumnReorderListener; import com.vaadin.ui.Grid.ColumnVisibilityChangeEvent; import com.vaadin.ui.Grid.ColumnVisibilityChangeListener; import com.vaadin.ui.Grid.DetailsGenerator; +import com.vaadin.ui.Grid.EditorCloseEvent; +import com.vaadin.ui.Grid.EditorListener; +import com.vaadin.ui.Grid.EditorMoveEvent; +import com.vaadin.ui.Grid.EditorOpenEvent; import com.vaadin.ui.Grid.FooterCell; import com.vaadin.ui.Grid.HeaderCell; import com.vaadin.ui.Grid.HeaderRow; @@ -401,6 +405,7 @@ public class GridBasicFeatures extends AbstractComponentTest { } protected void createGridActions() { + LinkedHashMap primaryStyleNames = new LinkedHashMap(); primaryStyleNames.put("v-grid", "v-grid"); primaryStyleNames.put("v-escalator", "v-escalator"); @@ -1218,6 +1223,30 @@ public class GridBasicFeatures extends AbstractComponentTest { c.setEditorCancelCaption("ʃǝɔuɐↃ"); } }, null); + + createClickAction("Add editor state listener", "Editor", + new Command() { + @Override + public void execute(Grid grid, String value, Object data) { + grid.addEditorListener(new EditorListener() { + @Override + public void editorOpened(EditorOpenEvent e) { + log("Editor opened"); + } + + @Override + public void editorMoved(EditorMoveEvent e) { + log("Editor moved"); + } + + @Override + public void editorClosed(EditorCloseEvent e) { + log("Editor closed"); + } + }); + } + }, null); + } @SuppressWarnings("boxing") -- cgit v1.2.3 From 469a53e1256f143f506f8a3b59ef7fc505353495 Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Mon, 25 May 2015 12:09:23 +0300 Subject: Add unbuffered editing mode to Grid Save and cancel buttons are hidden and the backing field group is set to unbuffered mode. Change-Id: I7da46ae3f1b84cc5ac8c918be38919962aff88ed --- client/src/com/vaadin/client/widgets/Grid.java | 38 ++++++++++++++++++++-- server/src/com/vaadin/ui/Grid.java | 33 +++++++++++++++++++ .../src/com/vaadin/shared/ui/grid/GridState.java | 4 +++ .../grid/basicfeatures/GridBasicFeatures.java | 8 +++++ .../grid/basicfeatures/server/GridEditorTest.java | 37 +++++++++++++++++++++ 5 files changed, 118 insertions(+), 2 deletions(-) diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 21cf84cc0d..bf5494291f 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -1225,6 +1225,7 @@ public class Grid extends ResizeComposite implements /** A set of all the columns that display an error flag. */ private final Set> columnErrors = new HashSet>(); + private boolean buffered = true; public Editor() { saveButton = new Button(); @@ -1504,8 +1505,10 @@ public class Grid extends ResizeComposite implements messageAndButtonsWrapper.appendChild(buttonsWrapper); } - attachWidget(saveButton, buttonsWrapper); - attachWidget(cancelButton, buttonsWrapper); + if (isBuffered()) { + attachWidget(saveButton, buttonsWrapper); + attachWidget(cancelButton, buttonsWrapper); + } updateHorizontalScrollPosition(); @@ -1715,6 +1718,14 @@ public class Grid extends ResizeComposite implements public boolean isEditorColumnError(Column column) { return columnErrors.contains(column); } + + public void setBuffered(boolean buffered) { + this.buffered = buffered; + } + + public boolean isBuffered() { + return buffered; + } } public static abstract class AbstractGridKeyEvent @@ -7840,4 +7851,27 @@ public class Grid extends ResizeComposite implements public void focus() { setFocus(true); } + + /** + * Sets the buffered editor mode. + * + * @since + * @param editorUnbuffered + * true to enable buffered editor, + * false to disable it + */ + public void setEditorBuffered(boolean editorBuffered) { + editor.setBuffered(editorBuffered); + } + + /** + * Gets the buffered editor mode. + * + * @since + * @return true if buffered editor is enabled, + * false otherwise + */ + public boolean isEditorBuffered() { + return editor.isBuffered(); + } } diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java index 21bfd1b68f..fc5adbbff0 100644 --- a/server/src/com/vaadin/ui/Grid.java +++ b/server/src/com/vaadin/ui/Grid.java @@ -6019,6 +6019,39 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, EditorCloseEvent.class, listener); } + /** + * Sets the buffered editor mode. The default mode is buffered ( + * true). + * + * @since + * @param editorBuffered + * true to enable buffered editor, + * false to disable it + * @throws IllegalStateException + * If editor is active while attempting to change the buffered + * mode. + */ + public void setEditorBuffered(boolean editorBuffered) + throws IllegalStateException { + if (isEditorActive()) { + throw new IllegalStateException( + "Can't change editor unbuffered mode while editor is active."); + } + getState().editorBuffered = editorBuffered; + editorFieldGroup.setBuffered(editorBuffered); + } + + /** + * Gets the buffered editor mode. + * + * @since + * @return true if buffered editor is enabled, + * false otherwise + */ + public boolean isEditorBuffered() { + return getState().editorBuffered; + } + @Override public void addItemClickListener(ItemClickListener listener) { addListener(GridConstants.ITEM_CLICK_EVENT_ID, ItemClickEvent.class, diff --git a/shared/src/com/vaadin/shared/ui/grid/GridState.java b/shared/src/com/vaadin/shared/ui/grid/GridState.java index bb35659591..3faa4b441c 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridState.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridState.java @@ -154,6 +154,10 @@ public class GridState extends TabIndexState { /** The enabled state of the editor interface */ public boolean editorEnabled = false; + /** Buffered editor mode */ + @DelegateToWidget + public boolean editorBuffered = true; + /** Whether row data might contain generated row styles */ public boolean hasRowStyleGenerator; /** Whether row data might contain generated cell styles */ diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index 181f99a2c7..ba19d7ee72 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -1176,6 +1176,14 @@ public class GridBasicFeatures extends AbstractComponentTest { } }); + createBooleanAction("Buffered mode", "Editor", true, + new Command() { + @Override + public void execute(Grid c, Boolean value, Object data) { + c.setEditorBuffered(value); + } + }); + createClickAction("Edit item 5", "Editor", new Command() { @Override public void execute(Grid c, String value, Object data) { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java index f37a94358a..8a8792c351 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java @@ -47,6 +47,8 @@ public class GridEditorTest extends GridBasicFeaturesTest { "Editor", "Edit item 100" }; private static final String[] TOGGLE_EDIT_ENABLED = new String[] { "Component", "Editor", "Enabled" }; + private static final String[] TOGGLE_EDITOR_BUFFERED_ENABLED = new String[] { + "Component", "Editor", "Buffered mode" }; @Before public void setUp() { @@ -302,6 +304,41 @@ public class GridEditorTest extends GridBasicFeaturesTest { getGridElement().getEditor().isEditable(3)); } + @Test + public void testEditorUnbufferedShowsNoButtons() { + selectMenuPath(TOGGLE_EDITOR_BUFFERED_ENABLED); + selectMenuPath(EDIT_ITEM_5); + + assertEditorOpen(); + + boolean saveButtonFound = true; + try { + getSaveButton(); + } catch (NoSuchElementException e) { + saveButtonFound = false; + } + assertFalse("Save button should not be visible in unbuffered mode.", + saveButtonFound); + + boolean cancelButtonFound = true; + try { + getCancelButton(); + } catch (NoSuchElementException e) { + cancelButtonFound = false; + } + assertFalse("Cancel button should not be visible in unbuffered mode.", + cancelButtonFound); + } + + @Test + public void testEditorUnbufferedWhileOpen() { + selectMenuPath(EDIT_ITEM_5); + selectMenuPath(TOGGLE_EDITOR_BUFFERED_ENABLED); + assertEditorOpen(); + boolean thrown = logContainsText("Exception occured, java.lang.IllegalStateException"); + assertTrue("IllegalStateException thrown", thrown); + } + private WebElement getSaveButton() { return getDriver().findElement(By.className("v-grid-editor-save")); } -- cgit v1.2.3 From feab1153761049b4f833174586d158bef22eb15c Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Tue, 26 May 2015 15:57:16 +0300 Subject: Let mouse click move editor in unbuffered mode Change-Id: I90a01ee7877aec35835145fb8b9c2dd49899dc5a --- client/src/com/vaadin/client/widgets/Grid.java | 35 ++++- server/src/com/vaadin/ui/Grid.java | 4 +- .../server/GridEditorBufferedTest.java | 153 ++++++++++++++++++ .../grid/basicfeatures/server/GridEditorTest.java | 173 ++------------------- .../server/GridEditorUnbufferedTest.java | 88 +++++++++++ 5 files changed, 279 insertions(+), 174 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index bf5494291f..4616c43902 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -1425,6 +1425,13 @@ public class Grid extends ResizeComposite implements } } + protected void hide() { + hideOverlay(); + grid.getEscalator().setScrollLocked(Direction.VERTICAL, false); + state = State.INACTIVE; + updateSelectionCheckboxesAsNeeded(true); + } + protected void setGrid(final Grid grid) { assert grid != null : "Grid cannot be null"; assert this.grid == null : "Can only attach editor to Grid once"; @@ -5063,7 +5070,7 @@ public class Grid extends ResizeComposite implements sinkEvents(getHeader().getConsumedEvents()); sinkEvents(Arrays.asList(BrowserEvents.KEYDOWN, BrowserEvents.KEYUP, BrowserEvents.KEYPRESS, BrowserEvents.DBLCLICK, - BrowserEvents.MOUSEDOWN)); + BrowserEvents.MOUSEDOWN, BrowserEvents.CLICK)); // Make ENTER and SHIFT+ENTER in the header perform sorting addHeaderKeyUpHandler(new HeaderKeyUpHandler() { @@ -6306,31 +6313,43 @@ public class Grid extends ResizeComposite implements } private boolean handleEditorEvent(Event event, RowContainer container) { + int type = event.getTypeInt(); + boolean editorIsActive = editor.getState() != Editor.State.INACTIVE; - if (editor.getState() != Editor.State.INACTIVE) { - if (event.getTypeInt() == Event.ONKEYDOWN + if (editorIsActive) { + // React to closing by keyboard in buffered and unbuffered mode + if (type == Event.ONKEYDOWN && event.getKeyCode() == Editor.KEYCODE_HIDE) { editor.cancel(); + return true; + } + // Swallow all other events in buffered mode and everything except + // ONCLICK in unbuffered mode + if (editor.isBuffered() || type != Event.ONCLICK) { + return true; } - return true; } if (container == escalator.getBody() && editor.isEnabled()) { - boolean wasOpen = editor.getState() != Editor.State.INACTIVE; boolean opened = false; - if (event.getTypeInt() == Event.ONDBLCLICK) { + if (editorIsActive && !editor.isBuffered() && type == Event.ONCLICK) { + editor.hide(); + cellFocusHandler.setCellFocus(eventCell); + editor.editRow(eventCell.getRowIndex()); + opened = true; + } else if (type == Event.ONDBLCLICK) { editor.editRow(eventCell.getRowIndex()); opened = true; - } else if (event.getTypeInt() == Event.ONKEYDOWN + } else if (type == Event.ONKEYDOWN && event.getKeyCode() == Editor.KEYCODE_SHOW) { editor.editRow(cellFocusHandler.rowWithFocus); opened = true; } if (opened) { - if (wasOpen) { + if (editorIsActive) { fireEvent(new EditorMoveEvent(eventCell)); } else { fireEvent(new EditorOpenEvent(eventCell)); diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java index fc5adbbff0..43e82560df 100644 --- a/server/src/com/vaadin/ui/Grid.java +++ b/server/src/com/vaadin/ui/Grid.java @@ -3930,13 +3930,13 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, boolean success = false; try { Object id = getContainerDataSource().getIdByIndex(rowIndex); - if (editedItemId == null) { + if (!isEditorBuffered() || editedItemId == null) { editedItemId = id; } if (editedItemId.equals(id)) { - success = true; doEditItem(); + success = true; } } catch (Exception e) { handleError(e); diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java new file mode 100644 index 0000000000..49a5174f8d --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java @@ -0,0 +1,153 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.grid.basicfeatures.server; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Before; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.shared.ui.grid.GridConstants; +import com.vaadin.testbench.elements.GridElement.GridEditorElement; +import com.vaadin.testbench.elements.NotificationElement; + +public class GridEditorBufferedTest extends GridEditorTest { + + @Override + @Before + public void setUp() { + super.setUp(); + } + + @Test + public void testSave() { + selectMenuPath(EDIT_ITEM_100); + + WebElement textField = getEditorWidgets().get(0); + + textField.click(); + + textField.sendKeys(" changed"); + + WebElement saveButton = getEditor().findElement( + By.className("v-grid-editor-save")); + + saveButton.click(); + + assertEquals("(100, 0) changed", getGridElement().getCell(100, 0) + .getText()); + } + + @Test + public void testProgrammaticSave() { + selectMenuPath(EDIT_ITEM_100); + + WebElement textField = getEditorWidgets().get(0); + + textField.click(); + + textField.sendKeys(" changed"); + + selectMenuPath("Component", "Editor", "Save"); + + assertEquals("(100, 0) changed", getGridElement().getCell(100, 0) + .getText()); + } + + @Test + public void testInvalidEdition() { + selectMenuPath(EDIT_ITEM_5); + assertFalse(logContainsText("Exception occured, java.lang.IllegalStateException")); + + GridEditorElement editor = getGridElement().getEditor(); + + assertFalse( + "Field 7 should not have been marked with an error before error", + editor.isFieldErrorMarked(7)); + + WebElement intField = editor.getField(7); + intField.clear(); + intField.sendKeys("banana phone"); + editor.save(); + + assertEquals("Column 7: Could not convert value to Integer", + editor.getErrorMessage()); + assertTrue("Field 7 should have been marked with an error after error", + editor.isFieldErrorMarked(7)); + editor.cancel(); + + selectMenuPath(EDIT_ITEM_100); + assertFalse("Exception should not exist", + isElementPresent(NotificationElement.class)); + assertEquals("There should be no editor error message", null, + editor.getErrorMessage()); + } + + @Test + public void testEditorInDisabledGrid() { + int originalScrollPos = getGridVerticalScrollPos(); + + selectMenuPath(EDIT_ITEM_5); + assertEditorOpen(); + + selectMenuPath("Component", "State", "Enabled"); + assertEditorOpen(); + + GridEditorElement editor = getGridElement().getEditor(); + editor.save(); + assertEditorOpen(); + + editor.cancel(); + assertEditorOpen(); + + selectMenuPath("Component", "State", "Enabled"); + + scrollGridVerticallyTo(100); + assertEquals("Grid shouldn't scroll vertically while editing", + originalScrollPos, getGridVerticalScrollPos()); + } + + @Test + public void testCaptionChange() { + selectMenuPath(EDIT_ITEM_5); + assertEquals("Save button caption should've been \"" + + GridConstants.DEFAULT_SAVE_CAPTION + "\" to begin with", + GridConstants.DEFAULT_SAVE_CAPTION, getSaveButton().getText()); + assertEquals("Cancel button caption should've been \"" + + GridConstants.DEFAULT_CANCEL_CAPTION + "\" to begin with", + GridConstants.DEFAULT_CANCEL_CAPTION, getCancelButton() + .getText()); + + selectMenuPath("Component", "Editor", "Change save caption"); + assertNotEquals( + "Save button caption should've changed while editor is open", + GridConstants.DEFAULT_SAVE_CAPTION, getSaveButton().getText()); + + getCancelButton().click(); + + selectMenuPath("Component", "Editor", "Change cancel caption"); + selectMenuPath(EDIT_ITEM_5); + assertNotEquals( + "Cancel button caption should've changed while editor is closed", + GridConstants.DEFAULT_CANCEL_CAPTION, getCancelButton() + .getText()); + } +} diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java index 8a8792c351..b32d50024d 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java @@ -17,7 +17,6 @@ package com.vaadin.tests.components.grid.basicfeatures.server; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -32,23 +31,18 @@ import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; -import com.vaadin.shared.ui.grid.GridConstants; import com.vaadin.testbench.elements.GridElement.GridCellElement; -import com.vaadin.testbench.elements.GridElement.GridEditorElement; -import com.vaadin.testbench.elements.NotificationElement; import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeatures; import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest; -public class GridEditorTest extends GridBasicFeaturesTest { +public abstract class GridEditorTest extends GridBasicFeaturesTest { - private static final String[] EDIT_ITEM_5 = new String[] { "Component", + protected static final String[] EDIT_ITEM_5 = new String[] { "Component", "Editor", "Edit item 5" }; - private static final String[] EDIT_ITEM_100 = new String[] { "Component", + protected static final String[] EDIT_ITEM_100 = new String[] { "Component", "Editor", "Edit item 100" }; - private static final String[] TOGGLE_EDIT_ENABLED = new String[] { + protected static final String[] TOGGLE_EDIT_ENABLED = new String[] { "Component", "Editor", "Enabled" }; - private static final String[] TOGGLE_EDITOR_BUFFERED_ENABLED = new String[] { - "Component", "Editor", "Buffered mode" }; @Before public void setUp() { @@ -129,112 +123,22 @@ public class GridEditorTest extends GridBasicFeaturesTest { assertEquals("100", widgets.get(8).getAttribute("value")); } - @Test - public void testSave() { - selectMenuPath(EDIT_ITEM_100); - - WebElement textField = getEditorWidgets().get(0); - - textField.click(); - - textField.sendKeys(" changed"); - - WebElement saveButton = getEditor().findElement( - By.className("v-grid-editor-save")); - - saveButton.click(); - - assertEquals("(100, 0) changed", getGridElement().getCell(100, 0) - .getText()); - } - - @Test - public void testProgrammaticSave() { - selectMenuPath(EDIT_ITEM_100); - - WebElement textField = getEditorWidgets().get(0); - - textField.click(); - - textField.sendKeys(" changed"); - - selectMenuPath("Component", "Editor", "Save"); - - assertEquals("(100, 0) changed", getGridElement().getCell(100, 0) - .getText()); - } - - @Test - public void testCaptionChange() { - selectMenuPath(EDIT_ITEM_5); - assertEquals("Save button caption should've been \"" - + GridConstants.DEFAULT_SAVE_CAPTION + "\" to begin with", - GridConstants.DEFAULT_SAVE_CAPTION, getSaveButton().getText()); - assertEquals("Cancel button caption should've been \"" - + GridConstants.DEFAULT_CANCEL_CAPTION + "\" to begin with", - GridConstants.DEFAULT_CANCEL_CAPTION, getCancelButton() - .getText()); - - selectMenuPath("Component", "Editor", "Change save caption"); - assertNotEquals( - "Save button caption should've changed while editor is open", - GridConstants.DEFAULT_SAVE_CAPTION, getSaveButton().getText()); - - getCancelButton().click(); - - selectMenuPath("Component", "Editor", "Change cancel caption"); - selectMenuPath(EDIT_ITEM_5); - assertNotEquals( - "Cancel button caption should've changed while editor is closed", - GridConstants.DEFAULT_CANCEL_CAPTION, getCancelButton() - .getText()); - } - - private void assertEditorOpen() { + protected void assertEditorOpen() { assertNotNull("Editor is supposed to be open", getEditor()); assertEquals("Unexpected number of widgets", GridBasicFeatures.EDITABLE_COLUMNS, getEditorWidgets().size()); } - private void assertEditorClosed() { + protected void assertEditorClosed() { assertNull("Editor is supposed to be closed", getEditor()); } - private List getEditorWidgets() { + protected List getEditorWidgets() { assertNotNull(getEditor()); return getEditor().findElements(By.className("v-textfield")); } - @Test - public void testInvalidEdition() { - selectMenuPath(EDIT_ITEM_5); - assertFalse(logContainsText("Exception occured, java.lang.IllegalStateException")); - - GridEditorElement editor = getGridElement().getEditor(); - - assertFalse( - "Field 7 should not have been marked with an error before error", - editor.isFieldErrorMarked(7)); - - WebElement intField = editor.getField(7); - intField.clear(); - intField.sendKeys("banana phone"); - editor.save(); - - assertEquals("Column 7: Could not convert value to Integer", - editor.getErrorMessage()); - assertTrue("Field 7 should have been marked with an error after error", - editor.isFieldErrorMarked(7)); - editor.cancel(); - - selectMenuPath(EDIT_ITEM_100); - assertFalse("Exception should not exist", - isElementPresent(NotificationElement.class)); - assertEquals("There should be no editor error message", null, - editor.getErrorMessage()); - } - @Test public void testNoScrollAfterEditByAPI() { int originalScrollPos = getGridVerticalScrollPos(); @@ -271,30 +175,6 @@ public class GridEditorTest extends GridBasicFeaturesTest { originalScrollPos, getGridVerticalScrollPos()); } - @Test - public void testEditorInDisabledGrid() { - int originalScrollPos = getGridVerticalScrollPos(); - - selectMenuPath(EDIT_ITEM_5); - assertEditorOpen(); - - selectMenuPath("Component", "State", "Enabled"); - assertEditorOpen(); - - GridEditorElement editor = getGridElement().getEditor(); - editor.save(); - assertEditorOpen(); - - editor.cancel(); - assertEditorOpen(); - - selectMenuPath("Component", "State", "Enabled"); - - scrollGridVerticallyTo(100); - assertEquals("Grid shouldn't scroll vertically while editing", - originalScrollPos, getGridVerticalScrollPos()); - } - @Test public void testUneditableColumn() { selectMenuPath(EDIT_ITEM_5); @@ -304,46 +184,11 @@ public class GridEditorTest extends GridBasicFeaturesTest { getGridElement().getEditor().isEditable(3)); } - @Test - public void testEditorUnbufferedShowsNoButtons() { - selectMenuPath(TOGGLE_EDITOR_BUFFERED_ENABLED); - selectMenuPath(EDIT_ITEM_5); - - assertEditorOpen(); - - boolean saveButtonFound = true; - try { - getSaveButton(); - } catch (NoSuchElementException e) { - saveButtonFound = false; - } - assertFalse("Save button should not be visible in unbuffered mode.", - saveButtonFound); - - boolean cancelButtonFound = true; - try { - getCancelButton(); - } catch (NoSuchElementException e) { - cancelButtonFound = false; - } - assertFalse("Cancel button should not be visible in unbuffered mode.", - cancelButtonFound); - } - - @Test - public void testEditorUnbufferedWhileOpen() { - selectMenuPath(EDIT_ITEM_5); - selectMenuPath(TOGGLE_EDITOR_BUFFERED_ENABLED); - assertEditorOpen(); - boolean thrown = logContainsText("Exception occured, java.lang.IllegalStateException"); - assertTrue("IllegalStateException thrown", thrown); - } - - private WebElement getSaveButton() { + protected WebElement getSaveButton() { return getDriver().findElement(By.className("v-grid-editor-save")); } - private WebElement getCancelButton() { + protected WebElement getCancelButton() { return getDriver().findElement(By.className("v-grid-editor-cancel")); } } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java new file mode 100644 index 0000000000..821239f1dc --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java @@ -0,0 +1,88 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.grid.basicfeatures.server; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Before; +import org.junit.Test; +import org.openqa.selenium.NoSuchElementException; + +public class GridEditorUnbufferedTest extends GridEditorTest { + + private static final String[] TOGGLE_EDITOR_BUFFERED = new String[] { + "Component", "Editor", "Buffered mode" }; + + @Override + @Before + public void setUp() { + super.setUp(); + selectMenuPath(TOGGLE_EDITOR_BUFFERED); + } + + @Test + public void testEditorShowsNoButtons() { + selectMenuPath(EDIT_ITEM_5); + + assertEditorOpen(); + + boolean saveButtonFound = true; + try { + getSaveButton(); + } catch (NoSuchElementException e) { + saveButtonFound = false; + } + assertFalse("Save button should not be visible in unbuffered mode.", + saveButtonFound); + + boolean cancelButtonFound = true; + try { + getCancelButton(); + } catch (NoSuchElementException e) { + cancelButtonFound = false; + } + assertFalse("Cancel button should not be visible in unbuffered mode.", + cancelButtonFound); + } + + @Test + public void testToggleEditorUnbufferedWhileOpen() { + selectMenuPath(EDIT_ITEM_5); + assertEditorOpen(); + selectMenuPath(TOGGLE_EDITOR_BUFFERED); + boolean thrown = logContainsText("Exception occured, java.lang.IllegalStateException"); + assertTrue("IllegalStateException thrown", thrown); + } + + @Test + public void testEditorMove() { + selectMenuPath(EDIT_ITEM_5); + + assertEditorOpen(); + + String firstFieldValue = getEditorWidgets().get(0) + .getAttribute("value"); + assertTrue("Editor is not at correct row index (5)", + "(5, 0)".equals(firstFieldValue)); + + getGridElement().getCell(10, 0).click(); + firstFieldValue = getEditorWidgets().get(0).getAttribute("value"); + + assertTrue("Editor is not at correct row index (10)", + "(10, 0)".equals(firstFieldValue)); + } +} -- cgit v1.2.3 From 11d95f2a97f4ffc4ded3421952ab2f57683679b4 Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Wed, 27 May 2015 15:33:56 +0300 Subject: Allow vertical scroll in unbuffered edit mode. Change-Id: Ia1e3dde57fdfcbc4fef6b91d3686dc9121e8ad56 --- client/src/com/vaadin/client/widgets/Grid.java | 44 +++++++++++++++++- .../server/GridEditorBufferedTest.java | 52 +++++++++++++++++++++- .../grid/basicfeatures/server/GridEditorTest.java | 44 ------------------ .../server/GridEditorUnbufferedTest.java | 45 ++++++++++++++++++- 4 files changed, 137 insertions(+), 48 deletions(-) diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 4616c43902..037131bec8 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -1227,6 +1227,11 @@ public class Grid extends ResizeComposite implements private final Set> columnErrors = new HashSet>(); private boolean buffered = true; + /** Original position of editor */ + private double originalTop; + /** Original scroll position of grid when editor was opened */ + private double originalScrollTop; + public Editor() { saveButton = new Button(); saveButton.setText(GridConstants.DEFAULT_SAVE_CAPTION); @@ -1420,7 +1425,8 @@ public class Grid extends ResizeComposite implements EditorRequest request = new EditorRequestImpl(grid, rowIndex, bindRequestCallback); handler.bind(request); - grid.getEscalator().setScrollLocked(Direction.VERTICAL, true); + grid.getEscalator().setScrollLocked(Direction.VERTICAL, + isBuffered()); updateSelectionCheckboxesAsNeeded(false); } } @@ -1484,6 +1490,9 @@ public class Grid extends ResizeComposite implements @Override public void onScroll(ScrollEvent event) { updateHorizontalScrollPosition(); + if (!isBuffered()) { + updateVerticalScrollPosition(); + } } }); @@ -1527,9 +1536,11 @@ public class Grid extends ResizeComposite implements int gridTop = gridElement.getAbsoluteTop(); double overlayTop = rowTop + bodyTop - gridTop; - if (buttonsShouldBeRenderedBelow(tr)) { + originalScrollTop = grid.getScrollTop(); + if (!isBuffered() || buttonsShouldBeRenderedBelow(tr)) { // Default case, editor buttons are below the edited row editorOverlay.getStyle().setTop(overlayTop, Unit.PX); + originalTop = overlayTop; editorOverlay.getStyle().clearBottom(); } else { // Move message and buttons wrapper on top of cell wrapper if @@ -1649,6 +1660,35 @@ public class Grid extends ResizeComposite implements cellWrapper.getStyle().setLeft(-scrollLeft, Unit.PX); } + /** + * Moves the editor overlay on scroll so that it stays on top of the + * edited row. This will also snap the editor to top or bottom of the + * row container if the edited row is scrolled out of the visible area. + */ + private void updateVerticalScrollPosition() { + double newScrollTop = grid.getScrollTop(); + + int gridTop = grid.getElement().getAbsoluteTop(); + int editorHeight = editorOverlay.getOffsetHeight(); + + Escalator escalator = grid.getEscalator(); + TableSectionElement header = escalator.getHeader().getElement(); + int footerTop = escalator.getFooter().getElement().getAbsoluteTop(); + int headerBottom = header.getAbsoluteBottom(); + + double newTop = originalTop - (newScrollTop - originalScrollTop); + + if (newTop + gridTop < headerBottom) { + // Snap editor to top of the row container + newTop = header.getOffsetHeight(); + } else if (newTop + gridTop > footerTop - editorHeight) { + // Snap editor to the bottom of the row container + newTop = footerTop - editorHeight - gridTop; + } + + editorOverlay.getStyle().setTop(newTop, Unit.PX); + } + protected void setGridEnabled(boolean enabled) { // TODO: This should be informed to handler as well so possible // fields can be disabled. diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java index 49a5174f8d..cc4b894e14 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java @@ -23,9 +23,13 @@ import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; import org.openqa.selenium.By; +import org.openqa.selenium.Keys; +import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; import com.vaadin.shared.ui.grid.GridConstants; +import com.vaadin.testbench.elements.GridElement.GridCellElement; import com.vaadin.testbench.elements.GridElement.GridEditorElement; import com.vaadin.testbench.elements.NotificationElement; @@ -121,7 +125,8 @@ public class GridEditorBufferedTest extends GridEditorTest { selectMenuPath("Component", "State", "Enabled"); scrollGridVerticallyTo(100); - assertEquals("Grid shouldn't scroll vertically while editing", + assertEquals( + "Grid shouldn't scroll vertically while editing in buffered mode", originalScrollPos, getGridVerticalScrollPos()); } @@ -150,4 +155,49 @@ public class GridEditorBufferedTest extends GridEditorTest { GridConstants.DEFAULT_CANCEL_CAPTION, getCancelButton() .getText()); } + + @Test(expected = NoSuchElementException.class) + public void testVerticalScrollLocking() { + selectMenuPath(EDIT_ITEM_5); + getGridElement().getCell(200, 0); + } + + @Test + public void testNoScrollAfterEditByAPI() { + int originalScrollPos = getGridVerticalScrollPos(); + + selectMenuPath(EDIT_ITEM_5); + + scrollGridVerticallyTo(100); + assertEquals( + "Grid shouldn't scroll vertically while editing in buffered mode", + originalScrollPos, getGridVerticalScrollPos()); + } + + @Test + public void testNoScrollAfterEditByMouse() { + int originalScrollPos = getGridVerticalScrollPos(); + + GridCellElement cell_5_0 = getGridElement().getCell(5, 0); + new Actions(getDriver()).doubleClick(cell_5_0).perform(); + + scrollGridVerticallyTo(100); + assertEquals( + "Grid shouldn't scroll vertically while editing in buffered mode", + originalScrollPos, getGridVerticalScrollPos()); + } + + @Test + public void testNoScrollAfterEditByKeyboard() { + int originalScrollPos = getGridVerticalScrollPos(); + + GridCellElement cell_5_0 = getGridElement().getCell(5, 0); + cell_5_0.click(); + new Actions(getDriver()).sendKeys(Keys.ENTER).perform(); + + scrollGridVerticallyTo(100); + assertEquals( + "Grid shouldn't scroll vertically while editing in buffered mode", + originalScrollPos, getGridVerticalScrollPos()); + } } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java index b32d50024d..9f743c93a1 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java @@ -27,11 +27,9 @@ import org.junit.Before; import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.Keys; -import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; -import com.vaadin.testbench.elements.GridElement.GridCellElement; import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeatures; import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest; @@ -84,12 +82,6 @@ public abstract class GridEditorTest extends GridBasicFeaturesTest { assertEditorOpen(); } - @Test(expected = NoSuchElementException.class) - public void testVerticalScrollLocking() { - selectMenuPath(EDIT_ITEM_5); - getGridElement().getCell(200, 0); - } - @Test public void testKeyboardOpeningClosing() { @@ -139,42 +131,6 @@ public abstract class GridEditorTest extends GridBasicFeaturesTest { } - @Test - public void testNoScrollAfterEditByAPI() { - int originalScrollPos = getGridVerticalScrollPos(); - - selectMenuPath(EDIT_ITEM_5); - - scrollGridVerticallyTo(100); - assertEquals("Grid shouldn't scroll vertically while editing", - originalScrollPos, getGridVerticalScrollPos()); - } - - @Test - public void testNoScrollAfterEditByMouse() { - int originalScrollPos = getGridVerticalScrollPos(); - - GridCellElement cell_5_0 = getGridElement().getCell(5, 0); - new Actions(getDriver()).doubleClick(cell_5_0).perform(); - - scrollGridVerticallyTo(100); - assertEquals("Grid shouldn't scroll vertically while editing", - originalScrollPos, getGridVerticalScrollPos()); - } - - @Test - public void testNoScrollAfterEditByKeyboard() { - int originalScrollPos = getGridVerticalScrollPos(); - - GridCellElement cell_5_0 = getGridElement().getCell(5, 0); - cell_5_0.click(); - new Actions(getDriver()).sendKeys(Keys.ENTER).perform(); - - scrollGridVerticallyTo(100); - assertEquals("Grid shouldn't scroll vertically while editing", - originalScrollPos, getGridVerticalScrollPos()); - } - @Test public void testUneditableColumn() { selectMenuPath(EDIT_ITEM_5); diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java index 821239f1dc..59e9a2972a 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java @@ -20,7 +20,11 @@ import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +import org.openqa.selenium.Keys; import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.interactions.Actions; + +import com.vaadin.testbench.elements.GridElement.GridCellElement; public class GridEditorUnbufferedTest extends GridEditorTest { @@ -85,4 +89,43 @@ public class GridEditorUnbufferedTest extends GridEditorTest { assertTrue("Editor is not at correct row index (10)", "(10, 0)".equals(firstFieldValue)); } -} + + @Test + public void testNoScrollAfterEditByAPI() { + int originalScrollPos = getGridVerticalScrollPos(); + + selectMenuPath(EDIT_ITEM_5); + + scrollGridVerticallyTo(100); + assertGreater( + "Grid should scroll vertically while editing in unbuffered mode", + getGridVerticalScrollPos(), originalScrollPos); + } + + @Test + public void testNoScrollAfterEditByMouse() { + int originalScrollPos = getGridVerticalScrollPos(); + + GridCellElement cell_5_0 = getGridElement().getCell(5, 0); + new Actions(getDriver()).doubleClick(cell_5_0).perform(); + + scrollGridVerticallyTo(100); + assertGreater( + "Grid should scroll vertically while editing in unbuffered mode", + getGridVerticalScrollPos(), originalScrollPos); + } + + @Test + public void testNoScrollAfterEditByKeyboard() { + int originalScrollPos = getGridVerticalScrollPos(); + + GridCellElement cell_5_0 = getGridElement().getCell(5, 0); + cell_5_0.click(); + new Actions(getDriver()).sendKeys(Keys.ENTER).perform(); + + scrollGridVerticallyTo(100); + assertGreater( + "Grid should scroll vertically while editing in unbuffered mode", + getGridVerticalScrollPos(), originalScrollPos); + } +} \ No newline at end of file -- cgit v1.2.3 From cf563c053fdf0d6b2991eba98e1cc118a8e74e54 Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Fri, 29 May 2015 13:53:56 +0300 Subject: Unbuffered editor hides notification area if no error msg present. Change-Id: I2441d684baeb9dc48ffad845a097c6cce51a9436 --- client/src/com/vaadin/client/widgets/Grid.java | 16 ++++++++++++++++ .../basicfeatures/server/GridEditorUnbufferedTest.java | 15 +++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 037131bec8..cc37074259 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -41,6 +41,7 @@ import com.google.gwt.dom.client.EventTarget; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.Node; import com.google.gwt.dom.client.Style; +import com.google.gwt.dom.client.Style.Display; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.dom.client.TableCellElement; import com.google.gwt.dom.client.TableRowElement; @@ -1261,6 +1262,10 @@ public class Grid extends ResizeComposite implements messageWrapper.appendChild(message); } } + // In unbuffered mode only show message wrapper if there is an error + if (!isBuffered()) { + setMessageAndButtonsWrapperVisible(errorMessage != null); + } } public int getRow() { @@ -1526,6 +1531,8 @@ public class Grid extends ResizeComposite implements attachWidget(cancelButton, buttonsWrapper); } + setMessageAndButtonsWrapperVisible(isBuffered()); + updateHorizontalScrollPosition(); AbstractRowContainer body = (AbstractRowContainer) grid @@ -1768,11 +1775,20 @@ public class Grid extends ResizeComposite implements public void setBuffered(boolean buffered) { this.buffered = buffered; + setMessageAndButtonsWrapperVisible(buffered); } public boolean isBuffered() { return buffered; } + + private void setMessageAndButtonsWrapperVisible(boolean visible) { + if (visible) { + messageAndButtonsWrapper.getStyle().clearDisplay(); + } else { + messageAndButtonsWrapper.getStyle().setDisplay(Display.NONE); + } + } } public static abstract class AbstractGridKeyEvent diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java index 59e9a2972a..60fe154f85 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java @@ -20,8 +20,10 @@ import static org.junit.Assert.assertTrue; import org.junit.Before; import org.junit.Test; +import org.openqa.selenium.By; import org.openqa.selenium.Keys; import org.openqa.selenium.NoSuchElementException; +import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; import com.vaadin.testbench.elements.GridElement.GridCellElement; @@ -90,6 +92,19 @@ public class GridEditorUnbufferedTest extends GridEditorTest { "(10, 0)".equals(firstFieldValue)); } + @Test + public void testErrorMessageWrapperHidden() { + selectMenuPath(EDIT_ITEM_5); + + assertEditorOpen(); + + WebElement editorFooter = getEditor().findElement( + By.className("v-grid-editor-footer")); + + assertTrue("Editor footer should not be visible when there's no error", + editorFooter.getCssValue("display").equalsIgnoreCase("none")); + } + @Test public void testNoScrollAfterEditByAPI() { int originalScrollPos = getGridVerticalScrollPos(); -- cgit v1.2.3 From 6008e42ce8d1e796e402dfd8d3f462c502d22269 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Tue, 2 Jun 2015 12:19:11 +0300 Subject: Don't open Grid editor from header or footer Change-Id: Ide40c6331a41bbdd4b5eb7baddbec07fcccb2a5d --- client/src/com/vaadin/client/widgets/Grid.java | 8 ++++---- .../grid/basicfeatures/server/GridEditorTest.java | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 9cd42199c7..cb3735c141 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -6462,10 +6462,10 @@ public class Grid extends ResizeComposite implements final int key = event.getKeyCode(); final boolean editorIsActive = editor.getState() != Editor.State.INACTIVE; - final boolean openEvent = type == Event.ONDBLCLICK - || (type == Event.ONKEYDOWN && key == Editor.KEYCODE_SHOW); + final boolean openEvent = eventCell.isBody() + && (type == Event.ONDBLCLICK || (type == Event.ONKEYDOWN && key == Editor.KEYCODE_SHOW)); - final boolean moveEvent = type == Event.ONCLICK; + final boolean moveEvent = eventCell.isBody() && type == Event.ONCLICK; final boolean closeEvent = type == Event.ONKEYDOWN && key == Editor.KEYCODE_HIDE; @@ -6477,7 +6477,7 @@ public class Grid extends ResizeComposite implements return true; - } else if (editorIsActive && eventCell.isBody() && moveEvent) { + } else if (editorIsActive && moveEvent) { editor.hide(); cellFocusHandler.setCellFocus(eventCell); diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java index b724ce4aa4..4c4b1c6f8b 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java @@ -188,6 +188,23 @@ public abstract class GridEditorTest extends GridBasicFeaturesTest { } + @Test + public void testNoOpenFromHeaderOrFooter() { + selectMenuPath("Component", "Footer", "Visible"); + + getGridElement().getHeaderCell(0, 0).doubleClick(); + assertEditorClosed(); + + new Actions(getDriver()).sendKeys(Keys.ENTER).perform(); + assertEditorClosed(); + + getGridElement().getFooterCell(0, 0).doubleClick(); + assertEditorClosed(); + + new Actions(getDriver()).sendKeys(Keys.ENTER).perform(); + assertEditorClosed(); + } + protected WebElement getSaveButton() { return getDriver().findElement(By.className("v-grid-editor-save")); } -- cgit v1.2.3 From ec54a601dc882333687bcef2b4fa59c02e6c4ede Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Tue, 2 Jun 2015 12:39:05 +0300 Subject: Update editor overlay position on Grid resize Change-Id: I980d6fa95939273c493e8ed726aa436d9d961003 --- client/src/com/vaadin/client/widgets/Grid.java | 5 +++ .../grid/basicfeatures/server/GridEditorTest.java | 46 ++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index cb3735c141..2717dc3580 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -7692,6 +7692,11 @@ public class Grid extends ResizeComposite implements @Override public void execute() { recalculateColumnWidths(); + // Vertical resizing could make editor positioning invalid so it + // needs to be recalculated on resize + if (isEditorActive()) { + editor.updateVerticalScrollPosition(); + } } }); } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java index 4c4b1c6f8b..0a6d884251 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java @@ -30,6 +30,7 @@ import org.openqa.selenium.Keys; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; +import com.vaadin.testbench.TestBenchElement; import com.vaadin.testbench.elements.GridElement.GridCellElement; import com.vaadin.testbench.elements.GridElement.GridEditorElement; import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeatures; @@ -205,6 +206,51 @@ public abstract class GridEditorTest extends GridBasicFeaturesTest { assertEditorClosed(); } + public void testEditorMoveOnResize() { + selectMenuPath("Component", "Size", "Height", "500px"); + getGridElement().getCell(22, 0).doubleClick(); + assertEditorOpen(); + + GridEditorElement editor = getGridElement().getEditor(); + TestBenchElement tableWrapper = getGridElement().getTableWrapper(); + + int tableWrapperBottom = tableWrapper.getLocation().getY() + + tableWrapper.getSize().getHeight(); + int editorBottom = editor.getLocation().getY() + + editor.getSize().getHeight(); + + assertTrue("Editor should not be initially outside grid", + tableWrapperBottom - editorBottom <= 2); + + selectMenuPath("Component", "Size", "Height", "300px"); + assertEditorOpen(); + + tableWrapperBottom = tableWrapper.getLocation().getY() + + tableWrapper.getSize().getHeight(); + editorBottom = editor.getLocation().getY() + + editor.getSize().getHeight(); + + assertTrue("Editor should not be outside grid after resize", + tableWrapperBottom - editorBottom <= 2); + } + + public void testEditorDoesNotMoveOnResizeIfNotNeeded() { + selectMenuPath("Component", "Size", "Height", "500px"); + + selectMenuPath(EDIT_ITEM_5); + assertEditorOpen(); + + GridEditorElement editor = getGridElement().getEditor(); + + int editorPos = editor.getLocation().getY(); + + selectMenuPath("Component", "Size", "Height", "300px"); + assertEditorOpen(); + + assertTrue("Editor should not have moved due to resize", + editorPos == editor.getLocation().getY()); + } + protected WebElement getSaveButton() { return getDriver().findElement(By.className("v-grid-editor-save")); } -- cgit v1.2.3 From eed4059ca05483f7874f45bfbd876b6c2dfe4bb0 Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Tue, 2 Jun 2015 16:29:57 +0300 Subject: On progr. editor open, focus target cell if Grid had focus prior Change-Id: I8ad9100356a309309e1f8964d6bc293981b2a827 --- client/src/com/vaadin/client/widgets/Grid.java | 18 ++++++++++++++++-- .../grid/basicfeatures/GridBasicFeatures.java | 21 +++++++++++++++++++++ .../grid/basicfeatures/server/GridEditorTest.java | 14 ++++++++++++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 2717dc3580..db3cea58dc 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -1280,12 +1280,26 @@ public class Grid extends ResizeComposite implements } /** - * Equivalent to {@code editRow(rowIndex, -1)}. + * If a cell of this Grid had focus once this editRow call was + * triggered, the editor component at the previously focused column + * index will be focused. + * + * If a Grid cell was not focused prior to calling this method, it will + * be equivalent to {@code editRow(rowIndex, -1)}. * * @see #editRow(int, int) */ public void editRow(int rowIndex) { - editRow(rowIndex, -1); + // Focus the last focused column in the editor iff grid or its child + // was focused before the edit request + Cell focusedCell = grid.cellFocusHandler.getFocusedCell(); + if (focusedCell != null + && grid.getElement().isOrHasChild( + WidgetUtil.getFocusedElement())) { + editRow(rowIndex, focusedCell.getColumn()); + } else { + editRow(rowIndex, -1); + } } /** diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index c98ee5c53b..a9cc528ac0 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -127,6 +127,14 @@ public class GridBasicFeatures extends AbstractComponentTest { } }; + private ItemClickListener editorOpeningItemClickListener = new ItemClickListener() { + + @Override + public void itemClick(ItemClickEvent event) { + grid.editItem(event.getItemId()); + } + }; + private ColumnReorderListener columnReorderListener = new ColumnReorderListener() { @Override @@ -642,6 +650,19 @@ public class GridBasicFeatures extends AbstractComponentTest { } } + }); + createBooleanAction("EditorOpeningItemClickListener", "State", false, + new Command() { + + @Override + public void execute(Grid c, Boolean value, Object data) { + if (!value) { + c.removeItemClickListener(editorOpeningItemClickListener); + } else { + c.addItemClickListener(editorOpeningItemClickListener); + } + } + }); createBooleanAction("ColumnReorderListener", "State", false, new Command() { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java index 0a6d884251..ba6c29522b 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java @@ -161,6 +161,20 @@ public abstract class GridEditorTest extends GridBasicFeaturesTest { assertEquals("", cell.getText(), focused.getAttribute("value")); } + @Test + public void testFocusOnProgrammaticOpenOnItemClick() { + selectMenuPath("Component", "State", "EditorOpeningItemClickListener"); + + GridCellElement cell = getGridElement().getCell(4, 2); + + cell.click(); + + WebElement focused = getFocusedElement(); + + assertEquals("", "input", focused.getTagName()); + assertEquals("", cell.getText(), focused.getAttribute("value")); + } + @Test public void testNoFocusOnProgrammaticOpen() { -- cgit v1.2.3 From a4b2dc6caf82487903e583edfa30eec837bbb5b1 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Wed, 3 Jun 2015 15:19:48 +0300 Subject: Fix broken Grid editor tests Change-Id: Iaef796694f09983d208b63af5e211e74512ff7be --- .../basicfeatures/server/GridEditorBufferedTest.java | 2 +- .../grid/basicfeatures/server/GridEditorTest.java | 8 ++++++-- .../server/GridEditorUnbufferedTest.java | 19 +++---------------- 3 files changed, 10 insertions(+), 19 deletions(-) diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java index 9f55d2adcb..606fe783d4 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java @@ -102,7 +102,7 @@ public class GridEditorBufferedTest extends GridEditorTest { assertFalse("Exception should not exist", isElementPresent(NotificationElement.class)); assertEquals("There should be no editor error message", null, - editor.getErrorMessage()); + getGridElement().getEditor().getErrorMessage()); } @Test diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java index ba6c29522b..dbb903ff98 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java @@ -38,6 +38,10 @@ import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest; public abstract class GridEditorTest extends GridBasicFeaturesTest { + protected static final By BY_EDITOR_CANCEL = By + .className("v-grid-editor-cancel"); + protected static final By BY_EDITOR_SAVE = By + .className("v-grid-editor-save"); protected static final String[] EDIT_ITEM_5 = new String[] { "Component", "Editor", "Edit item 5" }; protected static final String[] EDIT_ITEM_100 = new String[] { "Component", @@ -266,10 +270,10 @@ public abstract class GridEditorTest extends GridBasicFeaturesTest { } protected WebElement getSaveButton() { - return getDriver().findElement(By.className("v-grid-editor-save")); + return getDriver().findElement(BY_EDITOR_SAVE); } protected WebElement getCancelButton() { - return getDriver().findElement(By.className("v-grid-editor-cancel")); + return getDriver().findElement(BY_EDITOR_CANCEL); } } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java index 80e273ff1d..90a4c8b0b1 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java @@ -22,7 +22,6 @@ import org.junit.Before; import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.Keys; -import org.openqa.selenium.NoSuchElementException; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; @@ -48,23 +47,11 @@ public class GridEditorUnbufferedTest extends GridEditorTest { assertEditorOpen(); - boolean saveButtonFound = true; - try { - getSaveButton(); - } catch (NoSuchElementException e) { - saveButtonFound = false; - } assertFalse("Save button should not be visible in unbuffered mode.", - saveButtonFound); - - boolean cancelButtonFound = true; - try { - getCancelButton(); - } catch (NoSuchElementException e) { - cancelButtonFound = false; - } + isElementPresent(BY_EDITOR_SAVE)); + assertFalse("Cancel button should not be visible in unbuffered mode.", - cancelButtonFound); + isElementPresent(BY_EDITOR_CANCEL)); } @Test -- cgit v1.2.3 From 1b67d65d9718745edc69a51c082e917a2bbee2e0 Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Tue, 2 Jun 2015 15:08:03 +0300 Subject: Allow programmatically opening editor in unbuffered mode ..when the editor is already open on another row Change-Id: Ibec04dc7b1559149cf33e36fada8d676d943fc72 --- client/src/com/vaadin/client/widgets/Grid.java | 24 +++++++++++----------- server/src/com/vaadin/ui/Grid.java | 9 +++++--- .../server/GridEditorBufferedTest.java | 16 +++++++++++++++ .../server/GridEditorUnbufferedTest.java | 14 +++++++++++++ 4 files changed, 48 insertions(+), 15 deletions(-) diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index db3cea58dc..834280d89d 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -1209,7 +1209,6 @@ public class Grid extends ResizeComposite implements assert rowIndex == request.getRowIndex() : "Request row index " + request.getRowIndex() + " did not match the saved row index " + rowIndex; - showOverlay(); } } @@ -1316,7 +1315,8 @@ public class Grid extends ResizeComposite implements * @throws IllegalStateException * if this editor is not enabled * @throws IllegalStateException - * if this editor is already in edit mode + * if this editor is already in edit mode and in buffered + * mode * * @since 7.5 */ @@ -1326,8 +1326,10 @@ public class Grid extends ResizeComposite implements "Cannot edit row: editor is not enabled"); } if (state != State.INACTIVE) { - throw new IllegalStateException( - "Cannot edit row: editor already in edit mode"); + if (isBuffered()) { + throw new IllegalStateException( + "Cannot edit row: editor already in edit mode"); + } } this.rowIndex = rowIndex; @@ -1474,13 +1476,6 @@ public class Grid extends ResizeComposite implements } } - protected void hide() { - hideOverlay(); - grid.getEscalator().setScrollLocked(Direction.VERTICAL, false); - state = State.INACTIVE; - updateSelectionCheckboxesAsNeeded(true); - } - protected void setGrid(final Grid grid) { assert grid != null : "Grid cannot be null"; assert this.grid == null : "Can only attach editor to Grid once"; @@ -1539,6 +1534,8 @@ public class Grid extends ResizeComposite implements * @since 7.5 */ protected void showOverlay() { + // Ensure overlay is hidden initially + hideOverlay(); DivElement gridElement = DivElement.as(grid.getElement()); @@ -1646,6 +1643,10 @@ public class Grid extends ResizeComposite implements } protected void hideOverlay() { + if (editorOverlay.getParentElement() == null) { + return; + } + for (Widget w : columnToWidget.values()) { setParent(w, null); } @@ -6492,7 +6493,6 @@ public class Grid extends ResizeComposite implements return true; } else if (editorIsActive && moveEvent) { - editor.hide(); cellFocusHandler.setCellFocus(eventCell); editor.editRow(eventCell.getRowIndex(), diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java index 74f58ecf74..68676e5435 100644 --- a/server/src/com/vaadin/ui/Grid.java +++ b/server/src/com/vaadin/ui/Grid.java @@ -3383,7 +3383,8 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, private final String nullRepresentation; - protected AbstractRenderer(Class presentationType, String nullRepresentation) { + protected AbstractRenderer(Class presentationType, + String nullRepresentation) { this.presentationType = presentationType; this.nullRepresentation = nullRepresentation; } @@ -3428,6 +3429,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, /** * Null representation for the renderer + * * @return a textual representation of {@code null} */ protected String getNullRepresentation() { @@ -5819,7 +5821,8 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, * @param itemId * the id of the item to edit * @throws IllegalStateException - * if the editor is not enabled or already editing an item + * if the editor is not enabled or already editing an item in + * buffered mode * @throws IllegalArgumentException * if the {@code itemId} is not in the backing container * @see #setEditorEnabled(boolean) @@ -5828,7 +5831,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, IllegalArgumentException { if (!isEditorEnabled()) { throw new IllegalStateException("Item editor is not enabled"); - } else if (editedItemId != null) { + } else if (isEditorBuffered() && editedItemId != null) { throw new IllegalStateException("Editing item + " + itemId + " failed. Item editor is already editing item " + editedItemId); diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java index 606fe783d4..728c32af5d 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java @@ -214,4 +214,20 @@ public class GridEditorBufferedTest extends GridEditorTest { getGridElement().getCell(4, 0).doubleClick(); assertEditorClosed(); } + + @Test + public void testProgrammaticOpeningWhenOpen() { + selectMenuPath(EDIT_ITEM_5); + assertEditorOpen(); + assertEquals("Editor should edit row 5", "(5, 0)", getEditorWidgets() + .get(0).getAttribute("value")); + + selectMenuPath(EDIT_ITEM_100); + boolean thrown = logContainsText("Exception occured, java.lang.IllegalStateException"); + assertTrue("IllegalStateException thrown", thrown); + + assertEditorOpen(); + assertEquals("Editor should still edit row 5", "(5, 0)", + getEditorWidgets().get(0).getAttribute("value")); + } } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java index 90a4c8b0b1..4725d24903 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java @@ -15,6 +15,7 @@ */ package com.vaadin.tests.components.grid.basicfeatures.server; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -162,4 +163,17 @@ public class GridEditorUnbufferedTest extends GridEditorTest { getGridElement().getCell(4, 0).doubleClick(); assertEditorClosed(); } + + @Test + public void testProgrammaticOpeningWhenOpen() { + selectMenuPath(EDIT_ITEM_5); + assertEditorOpen(); + assertEquals("Editor should edit row 5", "(5, 0)", getEditorWidgets() + .get(0).getAttribute("value")); + + selectMenuPath(EDIT_ITEM_100); + assertEditorOpen(); + assertEquals("Editor should edit row 100", "(100, 0)", + getEditorWidgets().get(0).getAttribute("value")); + } } \ No newline at end of file -- cgit v1.2.3 From 97bb024d847e3eaddd537dacdfe5eaff9b319334 Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Tue, 30 Jun 2015 12:05:11 +0300 Subject: Use the type and key vars since they are there already Change-Id: I76fca3f2260dadbaf65496ce02b25e8d0f6c9a2f --- client/src/com/vaadin/client/widgets/Grid.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 57c8a503f5..2cc1fbad2b 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -6560,23 +6560,22 @@ public class Grid extends ResizeComposite implements int currentX = WidgetUtil.getTouchOrMouseClientX(event); int currentY = WidgetUtil.getTouchOrMouseClientY(event); - final boolean validTouchOpenEvent = event.getTypeInt() == Event.ONTOUCHEND + final boolean validTouchOpenEvent = type == Event.ONTOUCHEND && now - lastTouchEventTime < 500 && lastTouchEventRow == eventCell.getRowIndex() && Math.abs(lastTouchEventX - currentX) < 20 && Math.abs(lastTouchEventY - currentY) < 20; final boolean openEvent = eventCell.isBody() - && (event.getTypeInt() == Event.ONDBLCLICK - || (event.getTypeInt() == Event.ONKEYDOWN && event - .getKeyCode() == Editor.KEYCODE_SHOW) || validTouchOpenEvent); + && (type == Event.ONDBLCLICK + || (type == Event.ONKEYDOWN && key == Editor.KEYCODE_SHOW) || validTouchOpenEvent); - if (event.getTypeInt() == Event.ONTOUCHSTART) { + if (type == Event.ONTOUCHSTART) { lastTouchEventX = currentX; lastTouchEventY = currentY; } - if (event.getTypeInt() == Event.ONTOUCHEND) { + if (type == Event.ONTOUCHEND) { lastTouchEventTime = now; lastTouchEventRow = eventCell.getRowIndex(); } -- cgit v1.2.3 From db9929d8fc79d37bb299bad2ee644428f3bddc94 Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Thu, 25 Jun 2015 15:01:06 +0300 Subject: Added test to confirm that value change affects the editor field Change-Id: I06e4ba377d89393f2ca912ecb5f845f3992a864a --- .../grid/basicfeatures/GridBasicFeatures.java | 32 ++++++++++++++++++++++ .../server/GridEditorUnbufferedTest.java | 18 ++++++++++++ 2 files changed, 50 insertions(+) diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index 44a6da224e..35e39c9986 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -29,6 +29,8 @@ import java.util.Random; import com.vaadin.data.Container.Filter; import com.vaadin.data.Item; import com.vaadin.data.Property; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.data.fieldgroup.FieldGroup.CommitException; import com.vaadin.data.sort.Sort; import com.vaadin.data.sort.SortOrder; @@ -48,6 +50,7 @@ import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.Component; import com.vaadin.ui.CssLayout; +import com.vaadin.ui.Field; import com.vaadin.ui.Grid; import com.vaadin.ui.Grid.CellReference; import com.vaadin.ui.Grid.CellStyleGenerator; @@ -135,6 +138,16 @@ public class GridBasicFeatures extends AbstractComponentTest { } }; + private ValueChangeListener reactiveValueChanger = new ValueChangeListener() { + @Override + @SuppressWarnings("unchecked") + public void valueChange(ValueChangeEvent event) { + Object id = grid.getEditedItemId(); + grid.getContainerDataSource().getContainerProperty(id, "Column 2") + .setValue("Modified"); + } + }; + private ColumnReorderListener columnReorderListener = new ColumnReorderListener() { @Override @@ -663,6 +676,25 @@ public class GridBasicFeatures extends AbstractComponentTest { } } + }); + createBooleanAction("ReactiveValueChanger", "State", false, + new Command() { + + @Override + public void execute(Grid c, Boolean value, Object data) { + Field targetField = grid.getEditorFieldGroup() + .getField("Column 0"); + if (targetField != null) { + if (!value) { + targetField + .removeValueChangeListener(reactiveValueChanger); + } else { + targetField + .addValueChangeListener(reactiveValueChanger); + } + } + } + }); createBooleanAction("ColumnReorderListener", "State", false, new Command() { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java index 4725d24903..87c6cc805d 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java @@ -176,4 +176,22 @@ public class GridEditorUnbufferedTest extends GridEditorTest { assertEquals("Editor should edit row 100", "(100, 0)", getEditorWidgets().get(0).getAttribute("value")); } + + @Test + public void testExternalValueChangePassesToEditor() { + selectMenuPath(EDIT_ITEM_5); + assertEditorOpen(); + + selectMenuPath("Component", "State", "ReactiveValueChanger"); + + getEditorWidgets().get(0).click(); + getEditorWidgets().get(0).sendKeys("changing value"); + + // Focus another field to cause the value to be sent to the server + getEditorWidgets().get(2).click(); + + assertEquals("Value of Column 2 in the editor was not changed", + "Modified", getEditorWidgets().get(2).getAttribute("value")); + } + } \ No newline at end of file -- cgit v1.2.3 From 5460f5ec736f479795d3301acb73d62040c99311 Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Thu, 25 Jun 2015 16:32:32 +0300 Subject: Fixes non-editable column and selection visibility in editor Change-Id: Ic336ac744ce66b1fd182aaae3cff6d1006b8238f --- WebContent/VAADIN/themes/base/grid/grid.scss | 12 ++++++++++++ client/src/com/vaadin/client/widgets/Grid.java | 7 ++++++- .../grid/basicfeatures/server/GridEditorTest.java | 14 ++++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) diff --git a/WebContent/VAADIN/themes/base/grid/grid.scss b/WebContent/VAADIN/themes/base/grid/grid.scss index 1653032703..3fa5ddeb19 100644 --- a/WebContent/VAADIN/themes/base/grid/grid.scss +++ b/WebContent/VAADIN/themes/base/grid/grid.scss @@ -189,6 +189,14 @@ $v-grid-details-border-bottom-stripe: 1px solid darken($v-grid-row-background-co } // Rows + .#{$primaryStyleName}-row.editing { + > td { + background: $v-grid-editor-background-color; + } + &.#{$primaryStyleName}-row-selected > .v-grid-cell { + border-left: $v-grid-border; + } + } .#{$primaryStyleName}-row > td, .#{$primaryStyleName}-editor-cells > div { @@ -349,6 +357,10 @@ $v-grid-details-border-bottom-stripe: 1px solid darken($v-grid-row-background-co vertical-align: middle; background: $v-grid-editor-background-color; + &.not-editable { + visibility: hidden; + } + &:first-child { border-left: none; } diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 1dd9a9f06b..c46e8d03e8 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -1115,6 +1115,7 @@ public class Grid extends ResizeComposite implements private static final String ERROR_CLASS_NAME = "error"; private static final String NOT_EDITABLE_CLASS_NAME = "not-editable"; + private static final String CURRENTLY_EDITING_CLASS_NAME = "editing"; protected enum State { INACTIVE, ACTIVATING, BINDING, ACTIVE, SAVING @@ -1542,6 +1543,7 @@ public class Grid extends ResizeComposite implements TableRowElement tr = grid.getEscalator().getBody() .getRowElement(rowIndex); + tr.addClassName(CURRENTLY_EDITING_CLASS_NAME); scrollHandler = grid.addScrollHandler(new ScrollHandler() { @Override @@ -1647,7 +1649,6 @@ public class Grid extends ResizeComposite implements if (editorOverlay.getParentElement() == null) { return; } - for (Widget w : columnToWidget.values()) { setParent(w, null); } @@ -1656,6 +1657,10 @@ public class Grid extends ResizeComposite implements detachWidget(saveButton); detachWidget(cancelButton); + TableRowElement tr = grid.getEscalator().getBody() + .getRowElement(rowIndex); + tr.removeClassName(CURRENTLY_EDITING_CLASS_NAME); + editorOverlay.removeAllChildren(); cellWrapper.removeAllChildren(); editorOverlay.removeFromParent(); diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java index dbb903ff98..2cb40e1df8 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java @@ -56,6 +56,20 @@ public abstract class GridEditorTest extends GridBasicFeaturesTest { selectMenuPath(TOGGLE_EDIT_ENABLED); } + @Test + public void testNonEditableCellDoesNotBlockContents() { + selectMenuPath(EDIT_ITEM_5); + assertEditorOpen(); + + WebElement editorCellContainer = getEditor().findElement( + By.className("v-grid-editor-cells")); + WebElement nonEditableDiv = editorCellContainer.findElements( + By.tagName("div")).get(3); + + assertEquals("Non editable div was not hidden", "hidden", + nonEditableDiv.getCssValue("visibility")); + } + @Test public void testProgrammaticOpeningClosing() { selectMenuPath(EDIT_ITEM_5); -- cgit v1.2.3 From e13f2d53bc9deca2797c1699b974059a5f992616 Mon Sep 17 00:00:00 2001 From: Henri Sara Date: Thu, 2 Jul 2015 09:44:27 +0300 Subject: Update @since tags for 7.6 Change-Id: I764ebdbf656aecede222d5a5362ac6abcdbcb949 --- client/src/com/vaadin/client/ui/ConnectorFocusAndBlurHandler.java | 2 +- client/src/com/vaadin/client/widgets/Grid.java | 4 ++-- server/src/com/vaadin/ui/AbstractFocusable.java | 2 +- server/src/com/vaadin/ui/Grid.java | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/client/src/com/vaadin/client/ui/ConnectorFocusAndBlurHandler.java b/client/src/com/vaadin/client/ui/ConnectorFocusAndBlurHandler.java index 817d070a9f..8272f99d25 100644 --- a/client/src/com/vaadin/client/ui/ConnectorFocusAndBlurHandler.java +++ b/client/src/com/vaadin/client/ui/ConnectorFocusAndBlurHandler.java @@ -32,7 +32,7 @@ import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc; * to transmit received events to the server. Events are only handled if there * is a corresponding listener on the server side. * - * @since + * @since 7.6 * @author Vaadin Ltd */ public class ConnectorFocusAndBlurHandler implements StateChangeHandler, diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index c46e8d03e8..1665a76c7a 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -8124,7 +8124,7 @@ public class Grid extends ResizeComposite implements /** * Sets the buffered editor mode. * - * @since + * @since 7.6 * @param editorUnbuffered * true to enable buffered editor, * false to disable it @@ -8136,7 +8136,7 @@ public class Grid extends ResizeComposite implements /** * Gets the buffered editor mode. * - * @since + * @since 7.6 * @return true if buffered editor is enabled, * false otherwise */ diff --git a/server/src/com/vaadin/ui/AbstractFocusable.java b/server/src/com/vaadin/ui/AbstractFocusable.java index b9705cef6a..ad3b96f29b 100644 --- a/server/src/com/vaadin/ui/AbstractFocusable.java +++ b/server/src/com/vaadin/ui/AbstractFocusable.java @@ -29,7 +29,7 @@ import com.vaadin.ui.Component.Focusable; * An abstract base class for focusable components. Includes API for setting the * tab index, programmatic focusing, and adding focus and blur listeners. * - * @since + * @since 7.6 * @author Vaadin Ltd */ public abstract class AbstractFocusable extends AbstractComponent implements diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java index 64f26b6205..80af88e32b 100644 --- a/server/src/com/vaadin/ui/Grid.java +++ b/server/src/com/vaadin/ui/Grid.java @@ -6115,7 +6115,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, * Sets the buffered editor mode. The default mode is buffered ( * true). * - * @since + * @since 7.6 * @param editorBuffered * true to enable buffered editor, * false to disable it @@ -6136,7 +6136,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, /** * Gets the buffered editor mode. * - * @since + * @since 7.6 * @return true if buffered editor is enabled, * false otherwise */ -- cgit v1.2.3 From 2b255c73094fe4d785a225ca6334790b645b4b64 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Thu, 2 Jul 2015 13:10:24 +0300 Subject: Fix Grid regression in editor opening with no focused element Change-Id: I94d9765cb8177b6cc83158486b609efb255e4beb --- client/src/com/vaadin/client/widgets/Grid.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 1665a76c7a..eabe133fd1 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -1294,9 +1294,9 @@ public class Grid extends ResizeComposite implements // Focus the last focused column in the editor iff grid or its child // was focused before the edit request Cell focusedCell = grid.cellFocusHandler.getFocusedCell(); - if (focusedCell != null - && grid.getElement().isOrHasChild( - WidgetUtil.getFocusedElement())) { + Element focusedElement = WidgetUtil.getFocusedElement(); + if (focusedCell != null && focusedElement != null + && grid.getElement().isOrHasChild(focusedElement)) { editRow(rowIndex, focusedCell.getColumn()); } else { editRow(rowIndex, -1); -- cgit v1.2.3 From aecc8f5a42faa6ee461e879f552ced37d1a47d0d Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Fri, 3 Jul 2015 11:42:35 +0000 Subject: Revert "Fixes non-editable column and selection visibility in editor" This reverts commit 5460f5ec736f479795d3301acb73d62040c99311. Change-Id: I043e3db57b55694c6ef87751e487472a778c1b8a --- WebContent/VAADIN/themes/base/grid/grid.scss | 12 ------------ client/src/com/vaadin/client/widgets/Grid.java | 7 +------ .../grid/basicfeatures/server/GridEditorTest.java | 14 -------------- 3 files changed, 1 insertion(+), 32 deletions(-) diff --git a/WebContent/VAADIN/themes/base/grid/grid.scss b/WebContent/VAADIN/themes/base/grid/grid.scss index 3fa5ddeb19..1653032703 100644 --- a/WebContent/VAADIN/themes/base/grid/grid.scss +++ b/WebContent/VAADIN/themes/base/grid/grid.scss @@ -189,14 +189,6 @@ $v-grid-details-border-bottom-stripe: 1px solid darken($v-grid-row-background-co } // Rows - .#{$primaryStyleName}-row.editing { - > td { - background: $v-grid-editor-background-color; - } - &.#{$primaryStyleName}-row-selected > .v-grid-cell { - border-left: $v-grid-border; - } - } .#{$primaryStyleName}-row > td, .#{$primaryStyleName}-editor-cells > div { @@ -357,10 +349,6 @@ $v-grid-details-border-bottom-stripe: 1px solid darken($v-grid-row-background-co vertical-align: middle; background: $v-grid-editor-background-color; - &.not-editable { - visibility: hidden; - } - &:first-child { border-left: none; } diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index eabe133fd1..5cbfd5ea75 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -1115,7 +1115,6 @@ public class Grid extends ResizeComposite implements private static final String ERROR_CLASS_NAME = "error"; private static final String NOT_EDITABLE_CLASS_NAME = "not-editable"; - private static final String CURRENTLY_EDITING_CLASS_NAME = "editing"; protected enum State { INACTIVE, ACTIVATING, BINDING, ACTIVE, SAVING @@ -1543,7 +1542,6 @@ public class Grid extends ResizeComposite implements TableRowElement tr = grid.getEscalator().getBody() .getRowElement(rowIndex); - tr.addClassName(CURRENTLY_EDITING_CLASS_NAME); scrollHandler = grid.addScrollHandler(new ScrollHandler() { @Override @@ -1649,6 +1647,7 @@ public class Grid extends ResizeComposite implements if (editorOverlay.getParentElement() == null) { return; } + for (Widget w : columnToWidget.values()) { setParent(w, null); } @@ -1657,10 +1656,6 @@ public class Grid extends ResizeComposite implements detachWidget(saveButton); detachWidget(cancelButton); - TableRowElement tr = grid.getEscalator().getBody() - .getRowElement(rowIndex); - tr.removeClassName(CURRENTLY_EDITING_CLASS_NAME); - editorOverlay.removeAllChildren(); cellWrapper.removeAllChildren(); editorOverlay.removeFromParent(); diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java index 2cb40e1df8..dbb903ff98 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java @@ -56,20 +56,6 @@ public abstract class GridEditorTest extends GridBasicFeaturesTest { selectMenuPath(TOGGLE_EDIT_ENABLED); } - @Test - public void testNonEditableCellDoesNotBlockContents() { - selectMenuPath(EDIT_ITEM_5); - assertEditorOpen(); - - WebElement editorCellContainer = getEditor().findElement( - By.className("v-grid-editor-cells")); - WebElement nonEditableDiv = editorCellContainer.findElements( - By.tagName("div")).get(3); - - assertEquals("Non editable div was not hidden", "hidden", - nonEditableDiv.getCssValue("visibility")); - } - @Test public void testProgrammaticOpeningClosing() { selectMenuPath(EDIT_ITEM_5); -- cgit v1.2.3 From 7a5b61f19838dec76715026e5232c565082190a7 Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Fri, 3 Jul 2015 13:52:51 +0300 Subject: Added missing "grid" TestCategory for grid tests Change-Id: I9d78fba84fca2eef72c751b76d7748cbd40210b3 --- .../tests/components/grid/GridCellFocusOnResetSizeTest.java | 2 ++ .../vaadin/tests/components/grid/GridDetailsWidthTest.java | 2 ++ .../components/grid/GridInitiallyHiddenColumnsTest.java | 2 ++ .../tests/components/grid/GridMultiSelectionOnInitTest.java | 2 ++ .../vaadin/tests/components/grid/GridSortIndicatorTest.java | 2 ++ .../tests/components/grid/GridSpacerDecoClipTest.java | 13 ++++++++----- .../components/grid/GridSubPixelProblemWrappingTest.java | 2 ++ .../tests/components/grid/GridSwitchRenderersTest.java | 2 ++ .../vaadin/tests/components/grid/GridThemeChangeTest.java | 2 ++ .../vaadin/tests/components/grid/GridWidthIncreaseTest.java | 2 ++ .../tests/components/grid/JavaScriptRenderersTest.java | 2 ++ .../components/grid/ProgrammaticEditorControlTest.java | 2 ++ .../vaadin/tests/components/grid/SelectDuringInitTest.java | 2 ++ .../grid/basicfeatures/server/GridClearContainerTest.java | 2 ++ 14 files changed, 34 insertions(+), 5 deletions(-) diff --git a/uitest/src/com/vaadin/tests/components/grid/GridCellFocusOnResetSizeTest.java b/uitest/src/com/vaadin/tests/components/grid/GridCellFocusOnResetSizeTest.java index 31ccb4eaf2..cccb306369 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridCellFocusOnResetSizeTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridCellFocusOnResetSizeTest.java @@ -24,8 +24,10 @@ import org.openqa.selenium.By; import com.vaadin.testbench.elements.GridElement; import com.vaadin.testbench.elementsbase.ServerClass; +import com.vaadin.testbench.parallel.TestCategory; import com.vaadin.tests.tb3.MultiBrowserTest; +@TestCategory("grid") public class GridCellFocusOnResetSizeTest extends MultiBrowserTest { @ServerClass("com.vaadin.tests.widgetset.server.TestWidgetComponent") diff --git a/uitest/src/com/vaadin/tests/components/grid/GridDetailsWidthTest.java b/uitest/src/com/vaadin/tests/components/grid/GridDetailsWidthTest.java index 0a6f53820e..41838b427b 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridDetailsWidthTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridDetailsWidthTest.java @@ -23,8 +23,10 @@ import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import com.vaadin.testbench.elements.GridElement; +import com.vaadin.testbench.parallel.TestCategory; import com.vaadin.tests.tb3.SingleBrowserTest; +@TestCategory("grid") public class GridDetailsWidthTest extends SingleBrowserTest { @Test diff --git a/uitest/src/com/vaadin/tests/components/grid/GridInitiallyHiddenColumnsTest.java b/uitest/src/com/vaadin/tests/components/grid/GridInitiallyHiddenColumnsTest.java index a3e941053a..f495d7f2aa 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridInitiallyHiddenColumnsTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridInitiallyHiddenColumnsTest.java @@ -23,8 +23,10 @@ import org.openqa.selenium.By; import org.openqa.selenium.WebElement; import com.vaadin.testbench.elements.GridElement; +import com.vaadin.testbench.parallel.TestCategory; import com.vaadin.tests.tb3.SingleBrowserTest; +@TestCategory("grid") public class GridInitiallyHiddenColumnsTest extends SingleBrowserTest { @Test diff --git a/uitest/src/com/vaadin/tests/components/grid/GridMultiSelectionOnInitTest.java b/uitest/src/com/vaadin/tests/components/grid/GridMultiSelectionOnInitTest.java index 5f5b4df8de..d5eedae824 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridMultiSelectionOnInitTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridMultiSelectionOnInitTest.java @@ -21,8 +21,10 @@ import org.junit.Test; import org.openqa.selenium.By; import com.vaadin.testbench.elements.GridElement; +import com.vaadin.testbench.parallel.TestCategory; import com.vaadin.tests.tb3.MultiBrowserTest; +@TestCategory("grid") public class GridMultiSelectionOnInitTest extends MultiBrowserTest { @Test diff --git a/uitest/src/com/vaadin/tests/components/grid/GridSortIndicatorTest.java b/uitest/src/com/vaadin/tests/components/grid/GridSortIndicatorTest.java index 30ce7b76f9..2874ec32a6 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridSortIndicatorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridSortIndicatorTest.java @@ -20,8 +20,10 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import com.vaadin.testbench.elements.GridElement; +import com.vaadin.testbench.parallel.TestCategory; import com.vaadin.tests.tb3.MultiBrowserTest; +@TestCategory("grid") public class GridSortIndicatorTest extends MultiBrowserTest { @Test diff --git a/uitest/src/com/vaadin/tests/components/grid/GridSpacerDecoClipTest.java b/uitest/src/com/vaadin/tests/components/grid/GridSpacerDecoClipTest.java index c2cfe3cd7d..f08ab7a8a4 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridSpacerDecoClipTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridSpacerDecoClipTest.java @@ -15,20 +15,23 @@ */ package com.vaadin.tests.components.grid; -import com.vaadin.testbench.TestBenchElement; -import com.vaadin.testbench.elements.GridElement; -import com.vaadin.tests.minitutorials.v7_5.ShowingExtraDataForRows; -import com.vaadin.tests.tb3.MultiBrowserTest; import org.junit.Assert; import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.SearchContext; +import com.vaadin.testbench.TestBenchElement; +import com.vaadin.testbench.elements.GridElement; +import com.vaadin.testbench.parallel.TestCategory; +import com.vaadin.tests.minitutorials.v7_5.ShowingExtraDataForRows; +import com.vaadin.tests.tb3.MultiBrowserTest; + /** * Test for "Grid detail row outline overflows" (#17826) * * @author Vaadin Ltd */ +@TestCategory("grid") public class GridSpacerDecoClipTest extends MultiBrowserTest { private static final String SPACER_CSS_CLASS_DECO = "v-grid-spacer-deco"; @@ -88,7 +91,7 @@ public class GridSpacerDecoClipTest extends MultiBrowserTest { } private TestBenchElement getSpacerDeco(int index) { - SearchContext context = this.getContext(); + SearchContext context = getContext(); return (TestBenchElement) context.findElements( By.className(SPACER_CSS_CLASS_DECO)).get(index); } diff --git a/uitest/src/com/vaadin/tests/components/grid/GridSubPixelProblemWrappingTest.java b/uitest/src/com/vaadin/tests/components/grid/GridSubPixelProblemWrappingTest.java index 7aacfa8548..319cf3b8b8 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridSubPixelProblemWrappingTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridSubPixelProblemWrappingTest.java @@ -25,8 +25,10 @@ import com.vaadin.testbench.elements.ButtonElement; import com.vaadin.testbench.elements.GridElement; import com.vaadin.testbench.elements.GridElement.GridRowElement; import com.vaadin.testbench.parallel.Browser; +import com.vaadin.testbench.parallel.TestCategory; import com.vaadin.tests.tb3.MultiBrowserTest; +@TestCategory("grid") public class GridSubPixelProblemWrappingTest extends MultiBrowserTest { @Override diff --git a/uitest/src/com/vaadin/tests/components/grid/GridSwitchRenderersTest.java b/uitest/src/com/vaadin/tests/components/grid/GridSwitchRenderersTest.java index e3bab865c0..5989ba607f 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridSwitchRenderersTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridSwitchRenderersTest.java @@ -20,8 +20,10 @@ import org.junit.Test; import com.vaadin.testbench.elements.CheckBoxElement; import com.vaadin.testbench.elements.GridElement; +import com.vaadin.testbench.parallel.TestCategory; import com.vaadin.tests.tb3.MultiBrowserTest; +@TestCategory("grid") public class GridSwitchRenderersTest extends MultiBrowserTest { @Test diff --git a/uitest/src/com/vaadin/tests/components/grid/GridThemeChangeTest.java b/uitest/src/com/vaadin/tests/components/grid/GridThemeChangeTest.java index 5a21705b55..182bec04c9 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridThemeChangeTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridThemeChangeTest.java @@ -22,8 +22,10 @@ import org.junit.Test; import org.openqa.selenium.remote.DesiredCapabilities; import com.vaadin.testbench.elements.GridElement; +import com.vaadin.testbench.parallel.TestCategory; import com.vaadin.tests.tb3.MultiBrowserTest; +@TestCategory("grid") public class GridThemeChangeTest extends MultiBrowserTest { @Override public List getBrowsersToTest() { diff --git a/uitest/src/com/vaadin/tests/components/grid/GridWidthIncreaseTest.java b/uitest/src/com/vaadin/tests/components/grid/GridWidthIncreaseTest.java index 96b1a56fba..6f39253fb0 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridWidthIncreaseTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridWidthIncreaseTest.java @@ -25,8 +25,10 @@ import org.openqa.selenium.remote.DesiredCapabilities; import com.vaadin.testbench.elements.ButtonElement; import com.vaadin.testbench.elements.GridElement; import com.vaadin.testbench.parallel.BrowserUtil; +import com.vaadin.testbench.parallel.TestCategory; import com.vaadin.tests.tb3.MultiBrowserTest; +@TestCategory("grid") public class GridWidthIncreaseTest extends MultiBrowserTest { private static int INCREASE_COUNT = 3; diff --git a/uitest/src/com/vaadin/tests/components/grid/JavaScriptRenderersTest.java b/uitest/src/com/vaadin/tests/components/grid/JavaScriptRenderersTest.java index 96fd672ab1..b38178b156 100644 --- a/uitest/src/com/vaadin/tests/components/grid/JavaScriptRenderersTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/JavaScriptRenderersTest.java @@ -20,8 +20,10 @@ import org.junit.Test; import com.vaadin.testbench.elements.GridElement; import com.vaadin.testbench.elements.GridElement.GridCellElement; +import com.vaadin.testbench.parallel.TestCategory; import com.vaadin.tests.tb3.MultiBrowserTest; +@TestCategory("grid") public class JavaScriptRenderersTest extends MultiBrowserTest { @Test diff --git a/uitest/src/com/vaadin/tests/components/grid/ProgrammaticEditorControlTest.java b/uitest/src/com/vaadin/tests/components/grid/ProgrammaticEditorControlTest.java index 811bd03a64..efbc164e15 100644 --- a/uitest/src/com/vaadin/tests/components/grid/ProgrammaticEditorControlTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/ProgrammaticEditorControlTest.java @@ -21,8 +21,10 @@ import org.junit.Test; import com.vaadin.testbench.elements.ButtonElement; import com.vaadin.testbench.elements.GridElement; import com.vaadin.testbench.elements.TextFieldElement; +import com.vaadin.testbench.parallel.TestCategory; import com.vaadin.tests.tb3.SingleBrowserTest; +@TestCategory("grid") public class ProgrammaticEditorControlTest extends SingleBrowserTest { @Test diff --git a/uitest/src/com/vaadin/tests/components/grid/SelectDuringInitTest.java b/uitest/src/com/vaadin/tests/components/grid/SelectDuringInitTest.java index edfc8031a8..1ba223d71c 100644 --- a/uitest/src/com/vaadin/tests/components/grid/SelectDuringInitTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/SelectDuringInitTest.java @@ -19,8 +19,10 @@ import org.junit.Assert; import org.junit.Test; import com.vaadin.testbench.elements.GridElement; +import com.vaadin.testbench.parallel.TestCategory; import com.vaadin.tests.tb3.SingleBrowserTest; +@TestCategory("grid") public class SelectDuringInitTest extends SingleBrowserTest { @Test diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridClearContainerTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridClearContainerTest.java index fd35dac6fc..91b5d04ab6 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridClearContainerTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridClearContainerTest.java @@ -20,6 +20,7 @@ import org.junit.Test; import com.vaadin.testbench.elements.ButtonElement; import com.vaadin.testbench.elements.GridElement; +import com.vaadin.testbench.parallel.TestCategory; import com.vaadin.tests.tb3.MultiBrowserTest; /** @@ -28,6 +29,7 @@ import com.vaadin.tests.tb3.MultiBrowserTest; * * @author Vaadin Ltd */ +@TestCategory("grid") public class GridClearContainerTest extends MultiBrowserTest { private final String ERRORNOTE = "Unexpected cell contents."; -- cgit v1.2.3 From 4fce93896627b862587533e4bd3b71b0e7a3a6b2 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Wed, 8 Jul 2015 16:52:21 +0300 Subject: Close Grid editor on container item set change Also allow user sorting when in unbuffered mode. Change-Id: Ibe1c1770647529b63c6e3c7fc9509562449b54a4 --- client/src/com/vaadin/client/widgets/Grid.java | 5 +- server/src/com/vaadin/ui/Grid.java | 23 ++++++- .../grid/basicfeatures/GridBasicFeatures.java | 76 ++++++++++++---------- .../server/GridEditorBufferedTest.java | 10 +++ .../grid/basicfeatures/server/GridEditorTest.java | 18 +++++ .../server/GridEditorUnbufferedTest.java | 8 +++ .../basicfeatures/server/GridStructureTest.java | 2 +- 7 files changed, 103 insertions(+), 39 deletions(-) diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 5cbfd5ea75..a0b0b08aaa 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -6627,7 +6627,7 @@ public class Grid extends ResizeComposite implements return true; - } else if (editorIsActive && moveEvent) { + } else if (editorIsActive && !editor.isBuffered() && moveEvent) { cellFocusHandler.setCellFocus(eventCell); editor.editRow(eventCell.getRowIndex(), @@ -6644,7 +6644,8 @@ public class Grid extends ResizeComposite implements return true; } - return editorIsActive; + // Swallow events if editor is open and buffered (modal) + return editor.isBuffered() && editorIsActive; } private boolean handleRendererEvent(Event event, RowContainer container) { diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java index 80af88e32b..f7d49e6419 100644 --- a/server/src/com/vaadin/ui/Grid.java +++ b/server/src/com/vaadin/ui/Grid.java @@ -45,6 +45,9 @@ import com.google.gwt.thirdparty.guava.common.collect.Sets; import com.google.gwt.thirdparty.guava.common.collect.Sets.SetView; import com.vaadin.data.Container; import com.vaadin.data.Container.Indexed; +import com.vaadin.data.Container.ItemSetChangeEvent; +import com.vaadin.data.Container.ItemSetChangeListener; +import com.vaadin.data.Container.ItemSetChangeNotifier; import com.vaadin.data.Container.PropertySetChangeEvent; import com.vaadin.data.Container.PropertySetChangeListener; import com.vaadin.data.Container.PropertySetChangeNotifier; @@ -3608,6 +3611,13 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, } }; + private final ItemSetChangeListener editorClosingItemSetListener = new ItemSetChangeListener() { + @Override + public void containerItemSetChange(ItemSetChangeEvent event) { + cancelEditor(); + } + }; + private RpcDataProviderExtension datasourceExtension; /** @@ -4111,10 +4121,10 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, removeExtension(datasourceExtension); } - datasource = container; - resetEditor(); + datasource = container; + // // Adjust sort order // @@ -4161,6 +4171,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, ((PropertySetChangeNotifier) datasource) .addPropertySetChangeListener(propertyListener); } + /* * activeRowHandler will be updated by the client-side request that * occurs on container change - no need to actively re-insert any @@ -5886,6 +5897,10 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, f.markAsDirtyRecursive(); } + if (datasource instanceof ItemSetChangeNotifier) { + ((ItemSetChangeNotifier) datasource) + .addItemSetChangeListener(editorClosingItemSetListener); + } } private void setEditorField(Object propertyId, Field field) { @@ -5934,6 +5949,10 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, editorActive = false; editorFieldGroup.discard(); editorFieldGroup.setItemDataSource(null); + if (datasource instanceof ItemSetChangeNotifier) { + ((ItemSetChangeNotifier) datasource) + .removeItemSetChangeListener(editorClosingItemSetListener); + } } void resetEditor() { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index 35e39c9986..272ff1c9ae 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -387,46 +387,54 @@ public class GridBasicFeatures extends AbstractComponentTest { } private void addFilterActions() { - createClickAction("Column 1 starts with \"(23\"", "Filter", - new Command() { - @Override - public void execute(Grid grid, Void value, Object data) { - ds.addContainerFilter(new Filter() { + createBooleanAction("Column 1 starts with \"(23\"", "Filter", false, + new Command() { + Filter filter = new Filter() { + @Override + public boolean passesFilter(Object itemId, Item item) { + return item.getItemProperty("Column 1").getValue() + .toString().startsWith("(23"); + } - @Override - public boolean passesFilter(Object itemId, Item item) - throws UnsupportedOperationException { - return item.getItemProperty("Column 1") - .getValue().toString() - .startsWith("(23"); - } + @Override + public boolean appliesToProperty(Object propertyId) { + return propertyId.equals("Column 1"); + } + }; - @Override - public boolean appliesToProperty(Object propertyId) { - return propertyId.equals("Column 1"); - } - }); + @Override + public void execute(Grid grid, Boolean value, Object data) { + if (value) { + ds.addContainerFilter(filter); + } else { + ds.removeContainerFilter(filter); + } } - }, null); + }); - createClickAction("Add impassable filter", "Filter", - new Command() { - @Override - public void execute(Grid c, Void value, Object data) { - ds.addContainerFilter(new Filter() { - @Override - public boolean passesFilter(Object itemId, Item item) - throws UnsupportedOperationException { - return false; - } + createBooleanAction("Impassable filter", "Filter", false, + new Command() { + Filter filter = new Filter() { + @Override + public boolean passesFilter(Object itemId, Item item) { + return false; + } - @Override - public boolean appliesToProperty(Object propertyId) { - return true; - } - }); + @Override + public boolean appliesToProperty(Object propertyId) { + return true; + } + }; + + @Override + public void execute(Grid c, Boolean value, Object data) { + if (value) { + ds.addContainerFilter(filter); + } else { + ds.removeContainerFilter(filter); + } } - }, null); + }); } protected void createGridActions() { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java index 728c32af5d..0f2fe54696 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java @@ -230,4 +230,14 @@ public class GridEditorBufferedTest extends GridEditorTest { assertEquals("Editor should still edit row 5", "(5, 0)", getEditorWidgets().get(0).getAttribute("value")); } + + @Test + public void testUserSortDisabled() { + selectMenuPath(EDIT_ITEM_5); + + getGridElement().getHeaderCell(0, 0).click(); + + assertEditorOpen(); + assertEquals("(2, 0)", getGridElement().getCell(2, 0).getText()); + } } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java index dbb903ff98..3582038e61 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java @@ -269,6 +269,24 @@ public abstract class GridEditorTest extends GridBasicFeaturesTest { editorPos == editor.getLocation().getY()); } + @Test + public void testEditorClosedOnSort() { + selectMenuPath(EDIT_ITEM_5); + + selectMenuPath("Component", "State", "Sort by column", "Column 0, ASC"); + + assertEditorClosed(); + } + + @Test + public void testEditorClosedOnFilter() { + selectMenuPath(EDIT_ITEM_5); + + selectMenuPath("Component", "Filter", "Column 1 starts with \"(23\""); + + assertEditorClosed(); + } + protected WebElement getSaveButton() { return getDriver().findElement(BY_EDITOR_SAVE); } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java index 87c6cc805d..1058fe2d74 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java @@ -194,4 +194,12 @@ public class GridEditorUnbufferedTest extends GridEditorTest { "Modified", getEditorWidgets().get(2).getAttribute("value")); } + @Test + public void testEditorClosedOnUserSort() { + selectMenuPath(EDIT_ITEM_5); + + getGridElement().getHeaderCell(0, 0).click(); + + assertEditorClosed(); + } } \ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStructureTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStructureTest.java index 5d72d481c7..f44f39689c 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStructureTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridStructureTest.java @@ -274,7 +274,7 @@ public class GridStructureTest extends GridBasicFeaturesTest { @Test public void testBareItemSetChangeRemovingAllRows() throws Exception { openTestURL(); - selectMenuPath("Component", "Filter", "Add impassable filter"); + selectMenuPath("Component", "Filter", "Impassable filter"); assertFalse("A notification shouldn't have been displayed", $(NotificationElement.class).exists()); assertTrue("No body cells should've been found", getGridElement() -- cgit v1.2.3 From 40dcbc3cfaa438c9b879720c9012331dd85ca694 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Thu, 2 Jul 2015 17:34:27 +0300 Subject: Refactor RpcDataProviderExtension to use DataGenerators Change-Id: I8c809b6fac827df730c6622fb6790410c6c5bd81 --- .../vaadin/client/connectors/GridConnector.java | 33 +--- server/src/com/vaadin/data/DataGenerator.java | 49 +++++ .../com/vaadin/data/RpcDataProviderExtension.java | 220 +++++++-------------- server/src/com/vaadin/ui/Grid.java | 147 +++++++++++++- .../vaadin/tests/server/renderer/RendererTest.java | 26 +-- .../src/com/vaadin/shared/ui/grid/GridState.java | 5 - 6 files changed, 281 insertions(+), 199 deletions(-) create mode 100644 server/src/com/vaadin/data/DataGenerator.java diff --git a/client/src/com/vaadin/client/connectors/GridConnector.java b/client/src/com/vaadin/client/connectors/GridConnector.java index 052d8ee368..bee9cedc43 100644 --- a/client/src/com/vaadin/client/connectors/GridConnector.java +++ b/client/src/com/vaadin/client/connectors/GridConnector.java @@ -38,7 +38,6 @@ import com.vaadin.client.ComponentConnector; import com.vaadin.client.ConnectorHierarchyChangeEvent; import com.vaadin.client.DeferredWorker; import com.vaadin.client.MouseEventDetailsBuilder; -import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.connectors.RpcDataSourceConnector.DetailsListener; import com.vaadin.client.connectors.RpcDataSourceConnector.RpcDataSource; @@ -119,8 +118,8 @@ import elemental.json.JsonValue; public class GridConnector extends AbstractHasComponentsConnector implements SimpleManagedLayout, DeferredWorker { - private static final class CustomCellStyleGenerator implements - CellStyleGenerator { + private static final class CustomStyleGenerator implements + CellStyleGenerator, RowStyleGenerator { @Override public String getStyle(CellReference cellReference) { JsonObject row = cellReference.getRow(); @@ -146,10 +145,6 @@ public class GridConnector extends AbstractHasComponentsConnector implements } } - } - - private static final class CustomRowStyleGenerator implements - RowStyleGenerator { @Override public String getStyle(RowReference rowReference) { JsonObject row = rowReference.getRow(); @@ -159,7 +154,6 @@ public class GridConnector extends AbstractHasComponentsConnector implements return null; } } - } /** @@ -734,6 +728,7 @@ public class GridConnector extends AbstractHasComponentsConnector implements private String lastKnownTheme = null; private final CustomDetailsGenerator customDetailsGenerator = new CustomDetailsGenerator(); + private final CustomStyleGenerator styleGenerator = new CustomStyleGenerator(); private final DetailsConnectorFetcher detailsConnectorFetcher = new DetailsConnectorFetcher( getRpcProxy(GridServerRpc.class)); @@ -873,6 +868,10 @@ public class GridConnector extends AbstractHasComponentsConnector implements getWidget().addBodyClickHandler(itemClickHandler); getWidget().addBodyDoubleClickHandler(itemClickHandler); + /* Style Generators */ + getWidget().setCellStyleGenerator(styleGenerator); + getWidget().setRowStyleGenerator(styleGenerator); + getWidget().addSortHandler(new SortHandler() { @Override public void sort(SortEvent event) { @@ -1289,24 +1288,6 @@ public class GridConnector extends AbstractHasComponentsConnector implements } } - @OnStateChange("hasCellStyleGenerator") - private void onCellStyleGeneratorChange() { - if (getState().hasCellStyleGenerator) { - getWidget().setCellStyleGenerator(new CustomCellStyleGenerator()); - } else { - getWidget().setCellStyleGenerator(null); - } - } - - @OnStateChange("hasRowStyleGenerator") - private void onRowStyleGeneratorChange() { - if (getState().hasRowStyleGenerator) { - getWidget().setRowStyleGenerator(new CustomRowStyleGenerator()); - } else { - getWidget().setRowStyleGenerator(null); - } - } - private void updateSelectionFromState() { boolean changed = false; diff --git a/server/src/com/vaadin/data/DataGenerator.java b/server/src/com/vaadin/data/DataGenerator.java new file mode 100644 index 0000000000..f025623a3e --- /dev/null +++ b/server/src/com/vaadin/data/DataGenerator.java @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.data; + +import java.io.Serializable; + +import com.vaadin.ui.Grid.AbstractGridExtension; +import com.vaadin.ui.Grid.AbstractRenderer; + +import elemental.json.JsonObject; + +/** + * Interface for {@link AbstractGridExtension}s that allows adding data to row + * objects being sent to client by the {@link RpcDataProviderExtension}. + *

+ * {@link AbstractRenderer} implements this interface to provide encoded data to + * client for {@link Renderer}s automatically. + * + * @since + * @author Vaadin Ltd + */ +public interface DataGenerator extends Serializable { + + /** + * Adds data to row object for given item and item id being sent to client. + * + * @param itemId + * item id of item + * @param item + * item being sent to client + * @param rowData + * row object being sent to client + */ + public void generateData(Object itemId, Item item, JsonObject rowData); + +} diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java index 9d18736ba8..71b597ff1d 100644 --- a/server/src/com/vaadin/data/RpcDataProviderExtension.java +++ b/server/src/com/vaadin/data/RpcDataProviderExtension.java @@ -23,11 +23,9 @@ import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import java.util.logging.Logger; import com.google.gwt.thirdparty.guava.common.collect.BiMap; import com.google.gwt.thirdparty.guava.common.collect.HashBiMap; @@ -43,10 +41,8 @@ import com.vaadin.data.Container.ItemSetChangeNotifier; import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.data.Property.ValueChangeNotifier; -import com.vaadin.data.util.converter.Converter; import com.vaadin.server.AbstractExtension; import com.vaadin.server.ClientConnector; -import com.vaadin.server.KeyMapper; import com.vaadin.shared.data.DataProviderRpc; import com.vaadin.shared.data.DataRequestRpc; import com.vaadin.shared.ui.grid.DetailsConnectorChange; @@ -56,13 +52,9 @@ import com.vaadin.shared.ui.grid.Range; import com.vaadin.shared.util.SharedUtil; import com.vaadin.ui.Component; import com.vaadin.ui.Grid; -import com.vaadin.ui.Grid.CellReference; -import com.vaadin.ui.Grid.CellStyleGenerator; import com.vaadin.ui.Grid.Column; import com.vaadin.ui.Grid.DetailsGenerator; import com.vaadin.ui.Grid.RowReference; -import com.vaadin.ui.Grid.RowStyleGenerator; -import com.vaadin.ui.renderers.Renderer; import elemental.json.Json; import elemental.json.JsonArray; @@ -93,7 +85,7 @@ public class RpcDataProviderExtension extends AbstractExtension { * itemId ⇆ key mapping is not needed anymore. In other words, this * doesn't leak memory. */ - public class DataProviderKeyMapper implements Serializable { + public class DataProviderKeyMapper implements Serializable, DataGenerator { private final BiMap itemIdToKey = HashBiMap.create(); private Set pinnedItemIds = new HashSet(); private long rollingIndex = 0; @@ -125,7 +117,7 @@ public class RpcDataProviderExtension extends AbstractExtension { for (Object itemId : itemSet) { itemIdToKey.put(itemId, getKey(itemId)); - if (visibleDetails.contains(itemId)) { + if (detailComponentManager.visibleDetails.contains(itemId)) { detailComponentManager.createDetails(itemId, indexOf(itemId)); } @@ -280,6 +272,16 @@ public class RpcDataProviderExtension extends AbstractExtension { public boolean isPinned(Object itemId) { return pinnedItemIds.contains(itemId); } + + /** + * {@inheritDoc} + * + * @since + */ + @Override + public void generateData(Object itemId, Item item, JsonObject rowData) { + rowData.put(GridState.JSONKEY_ROWKEY, getKey(itemId)); + } } /** @@ -601,7 +603,7 @@ public class RpcDataProviderExtension extends AbstractExtension { * @since 7.5.0 * @author Vaadin Ltd */ - public static final class DetailComponentManager implements Serializable { + public static final class DetailComponentManager implements DataGenerator { /** * This map represents all the components that have been requested for * each item id. @@ -649,6 +651,12 @@ public class RpcDataProviderExtension extends AbstractExtension { */ private final Map emptyDetails = Maps.newHashMap(); + /** + * This map represents all the details that are user-defined as visible. + * This does not reflect the status in the DOM. + */ + private Set visibleDetails = new HashSet(); + private Grid grid; /** @@ -856,6 +864,18 @@ public class RpcDataProviderExtension extends AbstractExtension { } this.grid = grid; } + + /** + * {@inheritDoc} + * + * @since + */ + @Override + public void generateData(Object itemId, Item item, JsonObject rowData) { + if (visibleDetails.contains(itemId)) { + rowData.put(GridState.JSONKEY_DETAILS_VISIBLE, true); + } + } } private final Indexed container; @@ -939,14 +959,9 @@ public class RpcDataProviderExtension extends AbstractExtension { private final DataProviderKeyMapper keyMapper = new DataProviderKeyMapper(); - private KeyMapper columnKeys; - /** RpcDataProvider should send the current cache again. */ private boolean refreshCache = false; - private RowReference rowReference; - private CellReference cellReference; - /** Set of updated item ids */ private Set updatedItemIds = new LinkedHashSet(); @@ -959,14 +974,10 @@ public class RpcDataProviderExtension extends AbstractExtension { /** Size possibly changed with a bare ItemSetChangeEvent */ private boolean bareItemSetTriggeredSizeChange = false; - /** - * This map represents all the details that are user-defined as visible. - * This does not reflect the status in the DOM. - */ - private Set visibleDetails = new HashSet(); - private final DetailComponentManager detailComponentManager = new DetailComponentManager(); + private Set dataGenerators = new LinkedHashSet(); + /** * Creates a new data provider using the given container. * @@ -1006,6 +1017,8 @@ public class RpcDataProviderExtension extends AbstractExtension { .addItemSetChangeListener(itemListener); } + addDataGenerator(keyMapper); + addDataGenerator(detailComponentManager); } /** @@ -1090,73 +1103,14 @@ public class RpcDataProviderExtension extends AbstractExtension { private JsonValue getRowData(Collection columns, Object itemId) { Item item = container.getItem(itemId); - JsonObject rowData = Json.createObject(); - - Grid grid = getGrid(); - - for (Column column : columns) { - Object propertyId = column.getPropertyId(); - - Object propertyValue = item.getItemProperty(propertyId).getValue(); - JsonValue encodedValue = encodeValue(propertyValue, - column.getRenderer(), column.getConverter(), - grid.getLocale()); - - rowData.put(columnKeys.key(propertyId), encodedValue); - } - final JsonObject rowObject = Json.createObject(); - rowObject.put(GridState.JSONKEY_DATA, rowData); - rowObject.put(GridState.JSONKEY_ROWKEY, keyMapper.getKey(itemId)); - - if (visibleDetails.contains(itemId)) { - rowObject.put(GridState.JSONKEY_DETAILS_VISIBLE, true); - } - - rowReference.set(itemId); - - CellStyleGenerator cellStyleGenerator = grid.getCellStyleGenerator(); - if (cellStyleGenerator != null) { - setGeneratedCellStyles(cellStyleGenerator, rowObject, columns); - } - RowStyleGenerator rowStyleGenerator = grid.getRowStyleGenerator(); - if (rowStyleGenerator != null) { - setGeneratedRowStyles(rowStyleGenerator, rowObject); + for (DataGenerator dg : dataGenerators) { + dg.generateData(itemId, item, rowObject); } return rowObject; } - private void setGeneratedCellStyles(CellStyleGenerator generator, - JsonObject rowObject, Collection columns) { - JsonObject cellStyles = null; - for (Column column : columns) { - Object propertyId = column.getPropertyId(); - cellReference.set(propertyId); - String style = generator.getStyle(cellReference); - if (style != null && !style.isEmpty()) { - if (cellStyles == null) { - cellStyles = Json.createObject(); - } - - String columnKey = columnKeys.key(propertyId); - cellStyles.put(columnKey, style); - } - } - if (cellStyles != null) { - rowObject.put(GridState.JSONKEY_CELLSTYLES, cellStyles); - } - - } - - private void setGeneratedRowStyles(RowStyleGenerator generator, - JsonObject rowObject) { - String rowStyle = generator.getStyle(rowReference); - if (rowStyle != null && !rowStyle.isEmpty()) { - rowObject.put(GridState.JSONKEY_ROWSTYLE, rowStyle); - } - } - /** * Makes the data source available to the given {@link Grid} component. * @@ -1165,12 +1119,37 @@ public class RpcDataProviderExtension extends AbstractExtension { * @param columnKeys * the key mapper for columns */ - public void extend(Grid component, KeyMapper columnKeys) { - this.columnKeys = columnKeys; + public void extend(Grid component) { detailComponentManager.setGrid(component); super.extend(component); } + /** + * Adds a {@link DataGenerator} for this {@code RpcDataProviderExtension}. + * DataGenerators are called when sending row data to client. If given + * DataGenerator is already added, this method does nothing. + * + * @since + * @param generator + * generator to add + */ + public void addDataGenerator(DataGenerator generator) { + dataGenerators.add(generator); + } + + /** + * Removes a {@link DataGenerator} from this + * {@code RpcDataProviderExtension}. If given DataGenerator is not added to + * this data provider, this method does nothing. + * + * @since + * @param generator + * generator to remove + */ + public void removeDataGenerator(DataGenerator generator) { + dataGenerators.remove(generator); + } + /** * Informs the client side that new rows have been inserted into the data * source. @@ -1281,11 +1260,7 @@ public class RpcDataProviderExtension extends AbstractExtension { .removeItemSetChangeListener(itemListener); } - } else if (parent instanceof Grid) { - Grid grid = (Grid) parent; - rowReference = new RowReference(grid); - cellReference = new CellReference(rowReference); - } else { + } else if (!(parent instanceof Grid)) { throw new IllegalStateException( "Grid is the only accepted parent type"); } @@ -1321,62 +1296,6 @@ public class RpcDataProviderExtension extends AbstractExtension { return (Grid) getParent(); } - /** - * Converts and encodes the given data model property value using the given - * converter and renderer. This method is public only for testing purposes. - * - * @param renderer - * the renderer to use - * @param converter - * the converter to use - * @param modelValue - * the value to convert and encode - * @param locale - * the locale to use in conversion - * @return an encoded value ready to be sent to the client - */ - public static JsonValue encodeValue(Object modelValue, - Renderer renderer, Converter converter, Locale locale) { - Class presentationType = renderer.getPresentationType(); - T presentationValue; - - if (converter == null) { - try { - presentationValue = presentationType.cast(modelValue); - } catch (ClassCastException e) { - if (presentationType == String.class) { - // If there is no converter, just fallback to using - // toString(). - // modelValue can't be null as Class.cast(null) will always - // succeed - presentationValue = (T) modelValue.toString(); - } else { - throw new Converter.ConversionException( - "Unable to convert value of type " - + modelValue.getClass().getName() - + " to presentation type " - + presentationType.getName() - + ". No converter is set and the types are not compatible."); - } - } - } else { - assert presentationType.isAssignableFrom(converter - .getPresentationType()); - @SuppressWarnings("unchecked") - Converter safeConverter = (Converter) converter; - presentationValue = safeConverter.convertToPresentation(modelValue, - safeConverter.getPresentationType(), locale); - } - - JsonValue encodedValue = renderer.encode(presentationValue); - - return encodedValue; - } - - private static Logger getLogger() { - return Logger.getLogger(RpcDataProviderExtension.class.getName()); - } - /** * Marks a row's details to be visible or hidden. *

@@ -1394,7 +1313,7 @@ public class RpcDataProviderExtension extends AbstractExtension { final boolean modified; if (visible) { - modified = visibleDetails.add(itemId); + modified = detailComponentManager.visibleDetails.add(itemId); /* * We don't want to create the component here, since the component @@ -1405,7 +1324,7 @@ public class RpcDataProviderExtension extends AbstractExtension { */ } else { - modified = visibleDetails.remove(itemId); + modified = detailComponentManager.visibleDetails.remove(itemId); /* * Here we can try to destroy the component no matter what. The @@ -1435,7 +1354,7 @@ public class RpcDataProviderExtension extends AbstractExtension { * visible in the DOM */ public boolean isDetailsVisible(Object itemId) { - return visibleDetails.contains(itemId); + return detailComponentManager.visibleDetails.contains(itemId); } /** @@ -1444,7 +1363,8 @@ public class RpcDataProviderExtension extends AbstractExtension { * @since 7.5.0 */ public void refreshDetails() { - for (Object itemId : ImmutableSet.copyOf(visibleDetails)) { + for (Object itemId : ImmutableSet + .copyOf(detailComponentManager.visibleDetails)) { detailComponentManager.refresh(itemId); } } diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java index f7d49e6419..af89064411 100644 --- a/server/src/com/vaadin/ui/Grid.java +++ b/server/src/com/vaadin/ui/Grid.java @@ -31,6 +31,7 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; @@ -52,6 +53,7 @@ import com.vaadin.data.Container.PropertySetChangeEvent; import com.vaadin.data.Container.PropertySetChangeListener; import com.vaadin.data.Container.PropertySetChangeNotifier; import com.vaadin.data.Container.Sortable; +import com.vaadin.data.DataGenerator; import com.vaadin.data.Item; import com.vaadin.data.Property; import com.vaadin.data.RpcDataProviderExtension; @@ -1547,6 +1549,60 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, public String getStyle(CellReference cellReference); } + /** + * Class for generating all row and cell related data for the essential + * parts of Grid. + */ + private class RowDataGenerator implements DataGenerator { + + @Override + public void generateData(Object itemId, Item item, JsonObject rowData) { + RowReference r = new RowReference(Grid.this); + r.set(itemId); + + if (rowStyleGenerator != null) { + String style = rowStyleGenerator.getStyle(r); + if (style != null && !style.isEmpty()) { + rowData.put(GridState.JSONKEY_ROWSTYLE, style); + } + } + + JsonObject cellStyles = Json.createObject(); + JsonObject cellData = Json.createObject(); + for (Column column : getColumns()) { + Object propertyId = column.getPropertyId(); + String columnId = columnKeys.key(propertyId); + + cellData.put(columnId, getRendererData(column, item)); + + if (cellStyleGenerator != null) { + CellReference c = new CellReference(r); + c.set(propertyId); + + String style = cellStyleGenerator.getStyle(c); + if (style != null && !style.isEmpty()) { + cellStyles.put(columnId, style); + } + } + } + + if (cellStyleGenerator != null && cellStyles.keys().length > 0) { + rowData.put(GridState.JSONKEY_CELLSTYLES, cellStyles); + } + rowData.put(GridState.JSONKEY_DATA, cellData); + } + + private JsonValue getRendererData(Column column, Item item) { + Converter converter = column.getConverter(); + Object propertyId = column.getPropertyId(); + Object modelValue = item.getItemProperty(propertyId).getValue(); + Renderer renderer = column.getRenderer(); + + return AbstractRenderer.encodeValue(modelValue, renderer, + converter, getLocale()); + } + } + /** * Abstract base class for Grid header and footer sections. * @@ -3462,10 +3518,67 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, return JsonCodec.encode(value, null, type, getUI().getConnectorTracker()).getEncodedValue(); } + + /** + * Converts and encodes the given data model property value using the + * given converter and renderer. This method is public only for testing + * purposes. + * + * @param renderer + * the renderer to use + * @param converter + * the converter to use + * @param modelValue + * the value to convert and encode + * @param locale + * the locale to use in conversion + * @return an encoded value ready to be sent to the client + */ + public static JsonValue encodeValue(Object modelValue, + Renderer renderer, Converter converter, Locale locale) { + Class presentationType = renderer.getPresentationType(); + T presentationValue; + + if (converter == null) { + try { + presentationValue = presentationType.cast(modelValue); + } catch (ClassCastException e) { + if (presentationType == String.class) { + // If there is no converter, just fallback to using + // toString(). modelValue can't be null as + // Class.cast(null) will always succeed + presentationValue = (T) modelValue.toString(); + } else { + throw new Converter.ConversionException( + "Unable to convert value of type " + + modelValue.getClass().getName() + + " to presentation type " + + presentationType.getName() + + ". No converter is set and the types are not compatible."); + } + } + } else { + assert presentationType.isAssignableFrom(converter + .getPresentationType()); + @SuppressWarnings("unchecked") + Converter safeConverter = (Converter) converter; + presentationValue = safeConverter + .convertToPresentation(modelValue, + safeConverter.getPresentationType(), locale); + } + + JsonValue encodedValue = renderer.encode(presentationValue); + + return encodedValue; + } } /** * An abstract base class for server-side Grid extensions. + *

+ * Note: If the extension is an instance of {@link DataGenerator} it will + * automatically register itself to {@link RpcDataProviderExtension} of + * extended Grid. On remove this registration is automatically removed. * * @since 7.5 */ @@ -3490,6 +3603,26 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, extend(grid); } + @Override + protected void extend(AbstractClientConnector target) { + super.extend(target); + + if (this instanceof DataGenerator) { + getParentGrid().datasourceExtension + .addDataGenerator((DataGenerator) this); + } + } + + @Override + public void remove() { + if (this instanceof DataGenerator) { + getParentGrid().datasourceExtension + .removeDataGenerator((DataGenerator) this); + } + + super.remove(); + } + /** * Gets the item id for a row key. *

@@ -3531,9 +3664,14 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, if (getParent() instanceof Grid) { Grid grid = (Grid) getParent(); return grid; + } else if (getParent() == null) { + throw new IllegalStateException( + "Renderer is not attached to any parent"); } else { throw new IllegalStateException( - "Renderers can be used only with Grid"); + "Renderers can be used only with Grid. Extended " + + getParent().getClass().getSimpleName() + + " instead"); } } } @@ -4153,7 +4291,8 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, } datasourceExtension = new RpcDataProviderExtension(container); - datasourceExtension.extend(this, columnKeys); + datasourceExtension.extend(this); + datasourceExtension.addDataGenerator(new RowDataGenerator()); detailComponentManager = datasourceExtension .getDetailComponentManager(); @@ -5620,8 +5759,6 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, */ public void setCellStyleGenerator(CellStyleGenerator cellStyleGenerator) { this.cellStyleGenerator = cellStyleGenerator; - getState().hasCellStyleGenerator = (cellStyleGenerator != null); - datasourceExtension.refreshCache(); } @@ -5644,8 +5781,6 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, */ public void setRowStyleGenerator(RowStyleGenerator rowStyleGenerator) { this.rowStyleGenerator = rowStyleGenerator; - getState().hasRowStyleGenerator = (rowStyleGenerator != null); - datasourceExtension.refreshCache(); } diff --git a/server/tests/src/com/vaadin/tests/server/renderer/RendererTest.java b/server/tests/src/com/vaadin/tests/server/renderer/RendererTest.java index eb07fae07f..cea8df0ba6 100644 --- a/server/tests/src/com/vaadin/tests/server/renderer/RendererTest.java +++ b/server/tests/src/com/vaadin/tests/server/renderer/RendererTest.java @@ -15,8 +15,17 @@ */ package com.vaadin.tests.server.renderer; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; + +import java.util.Date; +import java.util.Locale; + +import org.junit.Before; +import org.junit.Test; + import com.vaadin.data.Item; -import com.vaadin.data.RpcDataProviderExtension; import com.vaadin.data.util.IndexedContainer; import com.vaadin.data.util.converter.Converter; import com.vaadin.data.util.converter.StringToIntegerConverter; @@ -24,22 +33,15 @@ import com.vaadin.server.VaadinSession; import com.vaadin.tests.server.component.grid.TestGrid; import com.vaadin.tests.util.AlwaysLockedVaadinSession; import com.vaadin.ui.Grid; +import com.vaadin.ui.Grid.AbstractRenderer; import com.vaadin.ui.Grid.Column; import com.vaadin.ui.renderers.ButtonRenderer; import com.vaadin.ui.renderers.DateRenderer; import com.vaadin.ui.renderers.HtmlRenderer; import com.vaadin.ui.renderers.NumberRenderer; import com.vaadin.ui.renderers.TextRenderer; -import elemental.json.JsonValue; -import org.junit.Before; -import org.junit.Test; - -import java.util.Date; -import java.util.Locale; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; +import elemental.json.JsonValue; public class RendererTest { @@ -259,7 +261,7 @@ public class RendererTest { } private JsonValue render(Column column, Object value) { - return RpcDataProviderExtension.encodeValue(value, - column.getRenderer(), column.getConverter(), grid.getLocale()); + return AbstractRenderer.encodeValue(value, column.getRenderer(), + column.getConverter(), grid.getLocale()); } } diff --git a/shared/src/com/vaadin/shared/ui/grid/GridState.java b/shared/src/com/vaadin/shared/ui/grid/GridState.java index c4121cbf45..c455ffe23b 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridState.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridState.java @@ -160,11 +160,6 @@ public class GridState extends TabIndexState { @DelegateToWidget public boolean editorBuffered = true; - /** Whether row data might contain generated row styles */ - public boolean hasRowStyleGenerator; - /** Whether row data might contain generated cell styles */ - public boolean hasCellStyleGenerator; - /** The caption for the save button in the editor */ @DelegateToWidget public String editorSaveCaption = GridConstants.DEFAULT_SAVE_CAPTION; -- cgit v1.2.3 From 4113062fc3c447debf7b7ea10c22b886dcf651c2 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Mon, 13 Jul 2015 17:26:20 +0300 Subject: Convert OutOfSyncTest from TB2 to TB4 This behaviour was changed in patch for #12909 Change-Id: If39839456608dff94125456c283ee2eec39f15c3 --- .../src/com/vaadin/tests/components/OutOfSync.java | 55 +++++++++++++ .../com/vaadin/tests/components/OutOfSyncTest.java | 89 ++++++++++------------ .../com/vaadin/tests/components/OutOfSyncTest.html | 38 --------- 3 files changed, 96 insertions(+), 86 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/OutOfSync.java delete mode 100644 uitest/tb2/com/vaadin/tests/components/OutOfSyncTest.html diff --git a/uitest/src/com/vaadin/tests/components/OutOfSync.java b/uitest/src/com/vaadin/tests/components/OutOfSync.java new file mode 100644 index 0000000000..8cefffc9d1 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/OutOfSync.java @@ -0,0 +1,55 @@ +package com.vaadin.tests.components; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Notification; + +public class OutOfSync extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + Button b = new Button("Click me after 1s to be out of sync"); + b.addClickListener(new ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + Notification.show("This code will never be reached"); + } + }); + setContent(b); + Thread t = new Thread(new Runnable() { + + @Override + public void run() { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + // Remove button but prevent repaint -> causes out of sync + // issues + getSession().lock(); + try { + setContent(null); + getConnectorTracker().markClean(OutOfSync.this); + } finally { + getSession().unlock(); + } + } + }); + t.start(); + } + + @Override + protected String getTestDescription() { + return "Click the button after 1s when it has been removed server side (causing synchronization problems)"; + } + + @Override + protected Integer getTicketNumber() { + return 10780; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/OutOfSyncTest.java b/uitest/src/com/vaadin/tests/components/OutOfSyncTest.java index 0efb519e8d..c6bab3c9b9 100644 --- a/uitest/src/com/vaadin/tests/components/OutOfSyncTest.java +++ b/uitest/src/com/vaadin/tests/components/OutOfSyncTest.java @@ -1,55 +1,48 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ package com.vaadin.tests.components; -import com.vaadin.server.VaadinRequest; -import com.vaadin.ui.Button; -import com.vaadin.ui.Button.ClickEvent; -import com.vaadin.ui.Button.ClickListener; -import com.vaadin.ui.Notification; - -public class OutOfSyncTest extends AbstractTestUI { - - @Override - protected void setup(VaadinRequest request) { - Button b = new Button("Click me after 1s to be out of sync"); - b.addClickListener(new ClickListener() { - - @Override - public void buttonClick(ClickEvent event) { - Notification.show("This code will never be reached"); - } - }); - setContent(b); - Thread t = new Thread(new Runnable() { - - @Override - public void run() { - try { - Thread.sleep(500); - } catch (InterruptedException e) { - e.printStackTrace(); - } - // Remove button but prevent repaint -> causes out of sync - // issues - getSession().lock(); - try { - setContent(null); - getConnectorTracker().markClean(OutOfSyncTest.this); - } finally { - getSession().unlock(); - } - } - }); - t.start(); - } +import org.junit.Assert; +import org.junit.Test; - @Override - protected String getTestDescription() { - return "Click the button after 1s when it has been removed server side (causing synchronization problems)"; - } +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class OutOfSyncTest extends MultiBrowserTest { + + @Test + public void testClientResync() throws InterruptedException { + openTestURL(); + + // Wait for server to get rid of the Button + sleep(1000); + + // On the first round-trip after the component has been removed, the + // server assumes the client will remove the button. How ever (to force + // it to be out of sync) the test UI calls markClean() on the Button to + // make it not update with the response. + $(ButtonElement.class).first().click(); + Assert.assertTrue( + "Button should not have disappeared on the first click.", + $(ButtonElement.class).exists()); - @Override - protected Integer getTicketNumber() { - return 10780; + // Truly out of sync, full resync is forced. + $(ButtonElement.class).first().click(); + Assert.assertFalse("Button should disappear with the second click.", + $(ButtonElement.class).exists()); } } diff --git a/uitest/tb2/com/vaadin/tests/components/OutOfSyncTest.html b/uitest/tb2/com/vaadin/tests/components/OutOfSyncTest.html deleted file mode 100644 index 4828069e2a..0000000000 --- a/uitest/tb2/com/vaadin/tests/components/OutOfSyncTest.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - -New Test - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
New Test
open/run/OutOfSyncTest?restartApplication
pause1000
clickvaadin=runOutOfSyncTest::/VButton[0]/domChild[0]/domChild[0]
assertElementNotPresentvaadin=runOutOfSyncTest::/VButton[0]
- - -- cgit v1.2.3 From 3ddace2ca21d5e495a6fcab9b361baf772212801 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Mon, 18 May 2015 14:59:39 +0300 Subject: Read debug window settings when all entry points have run (#17882) Change-Id: I09d612d784f978ba483d243b6938697893e1eac4 --- .../vaadin/client/debug/internal/VDebugWindow.java | 38 ++++++---- .../debug/PreserveCustomDebugSectionOpen.java | 33 +++++++++ .../debug/PreserveCustomDebugSectionOpenTest.java | 47 ++++++++++++ .../tests/widgetset/TestingWidgetSet.gwt.xml | 3 +- .../client/TestingWidgetsetEntryPoint.java | 83 ++++++++++++++++++++++ 5 files changed, 190 insertions(+), 14 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/debug/PreserveCustomDebugSectionOpen.java create mode 100644 uitest/src/com/vaadin/tests/debug/PreserveCustomDebugSectionOpenTest.java create mode 100644 uitest/src/com/vaadin/tests/widgetset/client/TestingWidgetsetEntryPoint.java diff --git a/client/src/com/vaadin/client/debug/internal/VDebugWindow.java b/client/src/com/vaadin/client/debug/internal/VDebugWindow.java index b543c23e4d..fbc838f861 100644 --- a/client/src/com/vaadin/client/debug/internal/VDebugWindow.java +++ b/client/src/com/vaadin/client/debug/internal/VDebugWindow.java @@ -19,6 +19,8 @@ import java.util.ArrayList; import java.util.Date; import com.google.gwt.core.client.Duration; +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.core.shared.GWT; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.NativeEvent; @@ -698,22 +700,32 @@ public final class VDebugWindow extends VOverlay { public void init() { show(); - readStoredState(); - Window.addResizeHandler(new com.google.gwt.event.logical.shared.ResizeHandler() { + /* + * Finalize initialization when all entry points have had the chance to + * e.g. register new sections. + */ + Scheduler.get().scheduleFinally(new ScheduledCommand() { + @Override + public void execute() { + readStoredState(); - Timer t = new Timer() { - @Override - public void run() { - applyPositionAndSize(); - } - }; + Window.addResizeHandler(new com.google.gwt.event.logical.shared.ResizeHandler() { - @Override - public void onResize(ResizeEvent event) { - t.cancel(); - // TODO less - t.schedule(1000); + Timer t = new Timer() { + @Override + public void run() { + applyPositionAndSize(); + } + }; + + @Override + public void onResize(ResizeEvent event) { + t.cancel(); + // TODO less + t.schedule(1000); + } + }); } }); } diff --git a/uitest/src/com/vaadin/tests/debug/PreserveCustomDebugSectionOpen.java b/uitest/src/com/vaadin/tests/debug/PreserveCustomDebugSectionOpen.java new file mode 100644 index 0000000000..0ac2e87510 --- /dev/null +++ b/uitest/src/com/vaadin/tests/debug/PreserveCustomDebugSectionOpen.java @@ -0,0 +1,33 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.debug; + +import com.vaadin.annotations.Widgetset; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.tests.widgetset.TestingWidgetSet; +import com.vaadin.ui.Label; + +@Widgetset(TestingWidgetSet.NAME) +public class PreserveCustomDebugSectionOpen extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + addComponent(new Label( + "UI for testing that a custom debug window section remains open after refreshging.")); + } + +} diff --git a/uitest/src/com/vaadin/tests/debug/PreserveCustomDebugSectionOpenTest.java b/uitest/src/com/vaadin/tests/debug/PreserveCustomDebugSectionOpenTest.java new file mode 100644 index 0000000000..01b73ded92 --- /dev/null +++ b/uitest/src/com/vaadin/tests/debug/PreserveCustomDebugSectionOpenTest.java @@ -0,0 +1,47 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.debug; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class PreserveCustomDebugSectionOpenTest extends SingleBrowserTest { + @Test + public void testPreserveSection() { + setDebug(true); + openTestURL(); + + findElement( + By.cssSelector(".v-debugwindow-tabs button[title=\"Dummy debug window section\"]")) + .click(); + + WebElement content = findElement(By + .cssSelector(".v-debugwindow-content")); + + // Sanity check + Assert.assertEquals("Dummy debug window section", content.getText()); + + // Open page again, should still have the same section open + openTestURL(); + + content = findElement(By.cssSelector(".v-debugwindow-content")); + Assert.assertEquals("Dummy debug window section", content.getText()); + } +} diff --git a/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml b/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml index 8a02d91d2c..3878e85193 100644 --- a/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml +++ b/uitest/src/com/vaadin/tests/widgetset/TestingWidgetSet.gwt.xml @@ -23,5 +23,6 @@ - + + diff --git a/uitest/src/com/vaadin/tests/widgetset/client/TestingWidgetsetEntryPoint.java b/uitest/src/com/vaadin/tests/widgetset/client/TestingWidgetsetEntryPoint.java new file mode 100644 index 0000000000..7268d02993 --- /dev/null +++ b/uitest/src/com/vaadin/tests/widgetset/client/TestingWidgetsetEntryPoint.java @@ -0,0 +1,83 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.widgetset.client; + +import com.google.gwt.core.client.EntryPoint; +import com.google.gwt.user.client.Window.Location; +import com.google.gwt.user.client.ui.Label; +import com.google.gwt.user.client.ui.Widget; +import com.vaadin.client.ApplicationConnection; +import com.vaadin.client.ValueMap; +import com.vaadin.client.debug.internal.DebugButton; +import com.vaadin.client.debug.internal.Icon; +import com.vaadin.client.debug.internal.Section; +import com.vaadin.client.debug.internal.VDebugWindow; + +public class TestingWidgetsetEntryPoint implements EntryPoint { + + @Override + public void onModuleLoad() { + if (Location.getPath().contains("PreserveCustomDebugSectionOpen")) { + addDummyDebugWindowSection(); + } + } + + private void addDummyDebugWindowSection() { + VDebugWindow.get().addSection(new Section() { + private final DebugButton tabButton = new DebugButton(Icon.ERROR, + "Dummy debug window section"); + private final Label controls = new Label(""); + private final Label contents = new Label( + "Dummy debug window section"); + + @Override + public DebugButton getTabButton() { + return tabButton; + } + + @Override + public Widget getControls() { + return controls; + } + + @Override + public Widget getContent() { + return contents; + } + + @Override + public void show() { + // nop + } + + @Override + public void hide() { + // nop + } + + @Override + public void meta(ApplicationConnection ac, ValueMap meta) { + // nop + } + + @Override + public void uidl(ApplicationConnection ac, ValueMap uidl) { + // nop + } + }); + } + +} -- cgit v1.2.3 From dc4946d3c65ff37926b12ed3cd2fe370b99aa445 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Tue, 14 Jul 2015 13:33:38 +0300 Subject: Stabilize TB4 tests with IE 11 Change-Id: I2570af5f7767f8275fb2e1c19c862974bf9e2eb2 --- .../com/vaadin/tests/application/VaadinSessionAttribute.java | 10 +++++++--- .../popupview/PopupViewShortcutActionHandlerTest.java | 12 +++++++++++- .../src/com/vaadin/tests/fieldgroup/BasicPersonFormTest.java | 10 ++++++++-- uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java | 4 ++-- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/uitest/src/com/vaadin/tests/application/VaadinSessionAttribute.java b/uitest/src/com/vaadin/tests/application/VaadinSessionAttribute.java index ddef40b2d0..c8fc96f596 100644 --- a/uitest/src/com/vaadin/tests/application/VaadinSessionAttribute.java +++ b/uitest/src/com/vaadin/tests/application/VaadinSessionAttribute.java @@ -35,9 +35,13 @@ public class VaadinSessionAttribute extends AbstractTestUI { new Button.ClickListener() { @Override public void buttonClick(ClickEvent event) { - Notification.show(getSession().getAttribute(ATTR_NAME) - + " & " - + getSession().getAttribute(Integer.class)); + Notification notification = new Notification( + getSession().getAttribute(ATTR_NAME) + + " & " + + getSession().getAttribute( + Integer.class)); + notification.setDelayMsec(Notification.DELAY_FOREVER); + notification.show(getPage()); } })); } diff --git a/uitest/src/com/vaadin/tests/components/popupview/PopupViewShortcutActionHandlerTest.java b/uitest/src/com/vaadin/tests/components/popupview/PopupViewShortcutActionHandlerTest.java index 3005365c47..6155820990 100644 --- a/uitest/src/com/vaadin/tests/components/popupview/PopupViewShortcutActionHandlerTest.java +++ b/uitest/src/com/vaadin/tests/components/popupview/PopupViewShortcutActionHandlerTest.java @@ -15,13 +15,15 @@ */ package com.vaadin.tests.components.popupview; -import com.vaadin.tests.tb3.MultiBrowserTest; import org.junit.Assert; import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.Keys; import org.openqa.selenium.WebElement; +import com.vaadin.testbench.parallel.BrowserUtil; +import com.vaadin.tests.tb3.MultiBrowserTest; + /** * Check availability of shortcut action listener in the popup view. * @@ -29,6 +31,14 @@ import org.openqa.selenium.WebElement; */ public class PopupViewShortcutActionHandlerTest extends MultiBrowserTest { + @Override + protected boolean requireWindowFocusForIE() { + if (BrowserUtil.isIE8(getDesiredCapabilities())) { + return false; + } + return true; + } + @Test public void testShortcutHandling() { openTestURL(); diff --git a/uitest/src/com/vaadin/tests/fieldgroup/BasicPersonFormTest.java b/uitest/src/com/vaadin/tests/fieldgroup/BasicPersonFormTest.java index f611325719..f5d78029c9 100644 --- a/uitest/src/com/vaadin/tests/fieldgroup/BasicPersonFormTest.java +++ b/uitest/src/com/vaadin/tests/fieldgroup/BasicPersonFormTest.java @@ -31,7 +31,14 @@ import com.vaadin.tests.tb3.MultiBrowserTest; public abstract class BasicPersonFormTest extends MultiBrowserTest { private static final String BEAN_VALUES = "Person [firstName=John, lastName=Doe, email=john@doe.com, age=64, sex=Male, address=Address [streetAddress=John street, postalCode=11223, city=John's town, country=USA], deceased=false, salary=null, salaryDouble=null, rent=null]"; - private int logCounter = 0; + private int logCounter; + + @Override + public void setup() throws Exception { + super.setup(); + + logCounter = 0; + } @Override protected Class getUIClass() { @@ -169,5 +176,4 @@ public abstract class BasicPersonFormTest extends MultiBrowserTest { assertSelectedSex(Sex.MALE); assertDeceasedValue("NAAAAAH"); } - } diff --git a/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java b/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java index a678009d85..c53209d1dc 100644 --- a/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java +++ b/uitest/src/com/vaadin/tests/tb3/MultiBrowserTest.java @@ -89,6 +89,8 @@ public abstract class MultiBrowserTest extends PrivateTB3Configuration { @Override public void setDesiredCapabilities(DesiredCapabilities desiredCapabilities) { + super.setDesiredCapabilities(desiredCapabilities); + if (BrowserUtil.isIE(desiredCapabilities)) { if (requireWindowFocusForIE()) { desiredCapabilities.setCapability( @@ -108,8 +110,6 @@ public abstract class MultiBrowserTest extends PrivateTB3Configuration { "name", String.format("%s.%s", getClass().getCanonicalName(), testName.getMethodName())); - - super.setDesiredCapabilities(desiredCapabilities); } @Override -- cgit v1.2.3 From ed02ddb86ea3c59b34a07661fdfd36eae937b060 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 16 Apr 2015 10:10:42 +0300 Subject: Do not initialize Atmosphere for websocket servlet in Websphere (#16354) Change-Id: I6f32668d357c2f2af75a2d53de37708f6c449b44 --- .../vaadin/server/communication/JSR356WebsocketInitializer.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/server/src/com/vaadin/server/communication/JSR356WebsocketInitializer.java b/server/src/com/vaadin/server/communication/JSR356WebsocketInitializer.java index f36d403dd5..6d2843a4fc 100644 --- a/server/src/com/vaadin/server/communication/JSR356WebsocketInitializer.java +++ b/server/src/com/vaadin/server/communication/JSR356WebsocketInitializer.java @@ -181,8 +181,13 @@ public class JSR356WebsocketInitializer implements ServletContextListener { */ protected boolean isVaadinServlet(ServletRegistration servletRegistration) { try { - Class servletClass = Class.forName(servletRegistration - .getClassName()); + String servletClassName = servletRegistration.getClassName(); + if (servletClassName.equals("com.ibm.ws.wsoc.WsocServlet")) { + // Websphere servlet which implements websocket endpoints, + // dynamically added + return false; + } + Class servletClass = Class.forName(servletClassName); return VaadinServlet.class.isAssignableFrom(servletClass); } catch (Exception e) { // This will fail in OSGi environments, assume everything is a -- cgit v1.2.3 From 00d622a0dd81ecd131705a1d1359f554de7e1430 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Tue, 14 Jul 2015 15:00:53 +0300 Subject: Move demo links from release report to staging report Change-Id: I4c38f787a44856a8420e1f9bda3ae6a1d889588f --- scripts/GenerateBuildReport.py | 8 +------- scripts/GenerateStagingReport.py | 7 ++++++- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/scripts/GenerateBuildReport.py b/scripts/GenerateBuildReport.py index 8ee2472133..13438f2233 100644 --- a/scripts/GenerateBuildReport.py +++ b/scripts/GenerateBuildReport.py @@ -33,13 +33,7 @@ except subprocess.CalledProcessError as e: else: raise e -content += "Try demos

    " - -for demo in demos: - content += "
  • {demoName}
  • \n".format(url=args.deployUrl, demoName=demo, version=args.version) - -content += """
-Build result page (See test results, pin and tag build and dependencies) +content += """Build result page (See test results, pin and tag build and dependencies) """.format(url=args.buildResultUrl) diff --git a/scripts/GenerateStagingReport.py b/scripts/GenerateStagingReport.py index fdcdc93fdb..7c2aeda9e0 100644 --- a/scripts/GenerateStagingReport.py +++ b/scripts/GenerateStagingReport.py @@ -17,7 +17,12 @@ content = """ """ -content += "\n + +
Try archetype demos
    " +content += "
Try demos
    " + +for demo in demos: + content += "
  • {demoName}
  • \n".format(url=args.deployUrl, demoName=demo, version=args.version) + +content += "
Try archetype demos
    " for archetype in archetypes: content += "
  • {demo}
  • \n".format(url=args.deployUrl, demo=archetype, context=getDeploymentContext(archetype, args.version)) -- cgit v1.2.3 From b9c0971afe9596329bd1a7e12f2cca1e647a80d4 Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Mon, 6 Jul 2015 11:59:00 +0300 Subject: Fixes scrollToLine while resizing Grid via split position (#18424) Change-Id: I5ecd8a91bd1ebea809d04a54307fcd752fbe3f39 --- .../src/com/vaadin/client/widgets/Escalator.java | 99 ++++++++++++---------- .../grid/GridScrollToLineWhileResizing.java | 73 ++++++++++++++++ .../grid/GridScrollToLineWhileResizingTest.java | 49 +++++++++++ 3 files changed, 177 insertions(+), 44 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/grid/GridScrollToLineWhileResizing.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/GridScrollToLineWhileResizingTest.java diff --git a/client/src/com/vaadin/client/widgets/Escalator.java b/client/src/com/vaadin/client/widgets/Escalator.java index 436b512294..a6247aee12 100644 --- a/client/src/com/vaadin/client/widgets/Escalator.java +++ b/client/src/com/vaadin/client/widgets/Escalator.java @@ -6022,10 +6022,14 @@ public class Escalator extends Widget implements RequiresResize, public void scrollToRow(final int rowIndex, final ScrollDestination destination, final int padding) throws IndexOutOfBoundsException, IllegalArgumentException { - validateScrollDestination(destination, padding); - verifyValidRowIndex(rowIndex); - - scroller.scrollToRow(rowIndex, destination, padding); + Scheduler.get().scheduleDeferred(new ScheduledCommand() { + @Override + public void execute() { + validateScrollDestination(destination, padding); + verifyValidRowIndex(rowIndex); + scroller.scrollToRow(rowIndex, destination, padding); + } + }); } private void verifyValidRowIndex(final int rowIndex) { @@ -6086,55 +6090,62 @@ public class Escalator extends Widget implements RequiresResize, * {@code destination == null}; or if {@code rowIndex == -1} and * there is no spacer open at that index. */ - public void scrollToRowAndSpacer(int rowIndex, - ScrollDestination destination, int padding) + public void scrollToRowAndSpacer(final int rowIndex, + final ScrollDestination destination, final int padding) throws IllegalArgumentException { - validateScrollDestination(destination, padding); - if (rowIndex != -1) { - verifyValidRowIndex(rowIndex); - } + Scheduler.get().scheduleDeferred(new ScheduledCommand() { + @Override + public void execute() { + validateScrollDestination(destination, padding); + if (rowIndex != -1) { + verifyValidRowIndex(rowIndex); + } - // row range - final Range rowRange; - if (rowIndex != -1) { - int rowTop = (int) Math.floor(body.getRowTop(rowIndex)); - int rowHeight = (int) Math.ceil(body.getDefaultRowHeight()); - rowRange = Range.withLength(rowTop, rowHeight); - } else { - rowRange = Range.withLength(0, 0); - } + // row range + final Range rowRange; + if (rowIndex != -1) { + int rowTop = (int) Math.floor(body.getRowTop(rowIndex)); + int rowHeight = (int) Math.ceil(body.getDefaultRowHeight()); + rowRange = Range.withLength(rowTop, rowHeight); + } else { + rowRange = Range.withLength(0, 0); + } - // get spacer - final SpacerContainer.SpacerImpl spacer = body.spacerContainer - .getSpacer(rowIndex); + // get spacer + final SpacerContainer.SpacerImpl spacer = body.spacerContainer + .getSpacer(rowIndex); - if (rowIndex == -1 && spacer == null) { - throw new IllegalArgumentException("Cannot scroll to row index " - + "-1, as there is no spacer open at that index."); - } + if (rowIndex == -1 && spacer == null) { + throw new IllegalArgumentException( + "Cannot scroll to row index " + + "-1, as there is no spacer open at that index."); + } - // make into target range - final Range targetRange; - if (spacer != null) { - final int spacerTop = (int) Math.floor(spacer.getTop()); - final int spacerHeight = (int) Math.ceil(spacer.getHeight()); - Range spacerRange = Range.withLength(spacerTop, spacerHeight); + // make into target range + final Range targetRange; + if (spacer != null) { + final int spacerTop = (int) Math.floor(spacer.getTop()); + final int spacerHeight = (int) Math.ceil(spacer.getHeight()); + Range spacerRange = Range.withLength(spacerTop, + spacerHeight); - targetRange = rowRange.combineWith(spacerRange); - } else { - targetRange = rowRange; - } + targetRange = rowRange.combineWith(spacerRange); + } else { + targetRange = rowRange; + } - // get params - int targetStart = targetRange.getStart(); - int targetEnd = targetRange.getEnd(); - double viewportStart = getScrollTop(); - double viewportEnd = viewportStart + body.getHeightOfSection(); + // get params + int targetStart = targetRange.getStart(); + int targetEnd = targetRange.getEnd(); + double viewportStart = getScrollTop(); + double viewportEnd = viewportStart + body.getHeightOfSection(); - double scrollPos = getScrollPos(destination, targetStart, targetEnd, - viewportStart, viewportEnd, padding); + double scrollPos = getScrollPos(destination, targetStart, + targetEnd, viewportStart, viewportEnd, padding); - setScrollTop(scrollPos); + setScrollTop(scrollPos); + } + }); } private static void validateScrollDestination( diff --git a/uitest/src/com/vaadin/tests/components/grid/GridScrollToLineWhileResizing.java b/uitest/src/com/vaadin/tests/components/grid/GridScrollToLineWhileResizing.java new file mode 100644 index 0000000000..194a9a3acc --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/GridScrollToLineWhileResizing.java @@ -0,0 +1,73 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.grid; + +import com.vaadin.data.Item; +import com.vaadin.data.util.IndexedContainer; +import com.vaadin.event.SelectionEvent; +import com.vaadin.event.SelectionEvent.SelectionListener; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Grid; +import com.vaadin.ui.Grid.SelectionMode; +import com.vaadin.ui.VerticalSplitPanel; + +public class GridScrollToLineWhileResizing extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + + final VerticalSplitPanel vsp = new VerticalSplitPanel(); + vsp.setWidth(500, Unit.PIXELS); + vsp.setHeight(500, Unit.PIXELS); + vsp.setSplitPosition(100, Unit.PERCENTAGE); + addComponent(vsp); + + IndexedContainer indexedContainer = new IndexedContainer(); + indexedContainer.addContainerProperty("column1", String.class, ""); + + for (int i = 0; i < 100; i++) { + Item addItem = indexedContainer.addItem(i); + addItem.getItemProperty("column1").setValue("cell" + i); + } + + final Grid grid = new Grid(indexedContainer); + grid.setSizeFull(); + + grid.setSelectionMode(SelectionMode.SINGLE); + grid.addSelectionListener(new SelectionListener() { + + @Override + public void select(SelectionEvent event) { + vsp.setSplitPosition(50, Unit.PERCENTAGE); + grid.scrollTo(event.getSelected().iterator().next()); + } + }); + + vsp.setFirstComponent(grid); + } + + @Override + protected String getTestDescription() { + return "Tests scrollToLine while moving SplitPanel split position to resize the Grid on the same round-trip."; + } + + @Override + protected Integer getTicketNumber() { + return null; + } + +} diff --git a/uitest/src/com/vaadin/tests/components/grid/GridScrollToLineWhileResizingTest.java b/uitest/src/com/vaadin/tests/components/grid/GridScrollToLineWhileResizingTest.java new file mode 100644 index 0000000000..aee1db7a85 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/GridScrollToLineWhileResizingTest.java @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.grid; + +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.elements.GridElement; +import com.vaadin.testbench.parallel.TestCategory; +import com.vaadin.tests.tb3.MultiBrowserTest; + +@TestCategory("grid") +public class GridScrollToLineWhileResizingTest extends MultiBrowserTest { + + @Test + public void testScrollToLineWorksWhileMovingSplitProgrammatically() { + openTestURL(); + + $(GridElement.class).first().getCell(21, 0).click(); + + List cells = findElements(By.className("v-grid-cell")); + boolean foundCell21 = false; + for (WebElement cell : cells) { + if ("cell21".equals(cell.getText())) { + foundCell21 = true; + } + } + + assertTrue(foundCell21); + } +} \ No newline at end of file -- cgit v1.2.3 From a33772e3f5932cf913ac2c67ce0bcda991dd8fc2 Mon Sep 17 00:00:00 2001 From: Taras Hupalo Date: Sun, 25 Jan 2015 05:46:41 +0200 Subject: Replaced HashMaps with TreeMaps to keep the same order (#14736) Change-Id: Ia2d8b6a2189e0bb7673f28b3606120d77628afb4 --- .../AcceptCriteriaFactoryGenerator.java | 6 +- .../ConnectorBundleLoaderFactory.java | 6 +- .../widgetsetutils/metadata/ConnectorBundle.java | 111 ++++++++++++++++----- .../server/widgetsetutils/metadata/Property.java | 16 ++- 4 files changed, 111 insertions(+), 28 deletions(-) diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/AcceptCriteriaFactoryGenerator.java b/client-compiler/src/com/vaadin/server/widgetsetutils/AcceptCriteriaFactoryGenerator.java index b7850e6370..2d08329e9a 100644 --- a/client-compiler/src/com/vaadin/server/widgetsetutils/AcceptCriteriaFactoryGenerator.java +++ b/client-compiler/src/com/vaadin/server/widgetsetutils/AcceptCriteriaFactoryGenerator.java @@ -16,6 +16,7 @@ package com.vaadin.server.widgetsetutils; import java.io.PrintWriter; +import java.util.Arrays; import java.util.Date; import com.google.gwt.core.ext.Generator; @@ -29,6 +30,7 @@ import com.google.gwt.user.rebind.ClassSourceFileComposerFactory; import com.google.gwt.user.rebind.SourceWriter; import com.vaadin.client.ui.dd.VAcceptCriterion; import com.vaadin.client.ui.dd.VAcceptCriterionFactory; +import com.vaadin.server.widgetsetutils.metadata.ConnectorBundle; import com.vaadin.shared.ui.dd.AcceptCriterion; /** @@ -114,7 +116,9 @@ public class AcceptCriteriaFactoryGenerator extends Generator { JClassType criteriaType = context.getTypeOracle().findType( VAcceptCriterion.class.getName()); - for (JClassType clientClass : criteriaType.getSubtypes()) { + JClassType[] subtypes = criteriaType.getSubtypes(); + Arrays.sort(subtypes, ConnectorBundle.jClassComparator); + for (JClassType clientClass : subtypes) { AcceptCriterion annotation = clientClass .getAnnotation(AcceptCriterion.class); if (annotation != null) { diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java b/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java index 884852f7c8..2b8ccc87d0 100644 --- a/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java +++ b/client-compiler/src/com/vaadin/server/widgetsetutils/ConnectorBundleLoaderFactory.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.TreeMap; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.RunAsyncCallback; @@ -1185,10 +1186,11 @@ public class ConnectorBundleLoaderFactory extends Generator { JClassType[] types = serverConnectorType.getSubtypes(); - Map mappings = new HashMap(); + Map mappings = new TreeMap(); // Keep track of what has happened to avoid logging intermediate state - Map> replaced = new HashMap>(); + Map> replaced = new TreeMap>( + ConnectorBundle.jClassComparator); for (JClassType type : types) { Connect connectAnnotation = type.getAnnotation(Connect.class); diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java index fedc86fbf6..b4531eb08e 100644 --- a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java +++ b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/ConnectorBundle.java @@ -19,12 +19,16 @@ import java.io.Serializable; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.TreeLogger.Type; @@ -37,7 +41,6 @@ import com.google.gwt.core.ext.typeinfo.JParameterizedType; import com.google.gwt.core.ext.typeinfo.JType; import com.google.gwt.core.ext.typeinfo.NotFoundException; import com.google.gwt.core.ext.typeinfo.TypeOracle; -import com.google.gwt.thirdparty.guava.common.collect.Sets; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.ComponentConnector; import com.vaadin.client.ServerConnector; @@ -54,6 +57,22 @@ import elemental.json.JsonValue; public class ConnectorBundle { private static final String FAIL_IF_NOT_SERIALIZABLE = "vFailIfNotSerializable"; + public static final Comparator jClassComparator = new Comparator() { + @Override + public int compare(JClassType o1, JClassType o2) { + return o1.getQualifiedSourceName().compareTo( + o2.getQualifiedSourceName()); + } + }; + + public static final Comparator jMethodComparator = new Comparator() { + @Override + public int compare(JMethod o1, JMethod o2) { + return o1.getReadableDeclaration().compareTo( + o2.getReadableDeclaration()); + } + }; + private final String name; private final ConnectorBundle previousBundle; private final Collection visitors; @@ -61,24 +80,42 @@ public class ConnectorBundle { private final Set hasSerializeSupport = new HashSet(); private final Set needsSerializeSupport = new HashSet(); - private final Map serializers = new HashMap(); - private final Map presentationTypes = new HashMap(); - private final Set needsSuperClass = new HashSet(); - private final Set needsGwtConstructor = new HashSet(); + private final Map serializers = new TreeMap( + new Comparator() { + @Override + public int compare(JType o1, JType o2) { + return o1.toString().compareTo(o2.toString()); + } + }); + + private final Map>> methodAttributes = new TreeMap>>( + jClassComparator); + private final Set needsSuperClass = new TreeSet( + jClassComparator); + private final Set needsGwtConstructor = new TreeSet( + jClassComparator); private final Set visitedTypes = new HashSet(); - private final Set needsProxySupport = new HashSet(); - private final Map> identifiers = new HashMap>(); - private final Map> needsReturnType = new HashMap>(); - private final Map> needsInvoker = new HashMap>(); - private final Map> needsParamTypes = new HashMap>(); - private final Map> needsOnStateChange = new HashMap>(); - - private final Map>> methodAttributes = new HashMap>>(); - - private final Set needsProperty = new HashSet(); - private final Map> needsDelegateToWidget = new HashMap>(); + private final Set needsProxySupport = new TreeSet( + jClassComparator); + + private final Map presentationTypes = new TreeMap( + jClassComparator); + private final Map> identifiers = new TreeMap>( + jClassComparator); + private final Map> needsReturnType = new TreeMap>( + jClassComparator); + private final Map> needsInvoker = new TreeMap>( + jClassComparator); + private final Map> needsParamTypes = new TreeMap>( + jClassComparator); + private final Map> needsOnStateChange = new TreeMap>( + jClassComparator); + + private final Set needsProperty = new TreeSet(); + private final Map> needsDelegateToWidget = new TreeMap>( + jClassComparator); private ConnectorBundle(String name, ConnectorBundle previousBundle, Collection visitors, @@ -369,7 +406,7 @@ public class ConnectorBundle { } public Collection getProperties(JClassType type) { - HashSet properties = new HashSet(); + Set properties = new TreeSet(); properties.addAll(MethodProperty.findProperties(type)); properties.addAll(FieldProperty.findProperties(type)); @@ -463,10 +500,19 @@ public class ConnectorBundle { } } - private void addMapping(Map> map, K key, V value) { - Set set = map.get(key); + private void addMapping(Map> map, K key, String value) { + Set set = map.get(key); + if (set == null) { + set = new TreeSet(); + map.put(key, set); + } + set.add(value); + } + + private void addMapping(Map> map, K key, JMethod value) { + Set set = map.get(key); if (set == null) { - set = new HashSet(); + set = new TreeSet(jMethodComparator); map.put(key, set); } set.add(value); @@ -533,11 +579,26 @@ public class ConnectorBundle { Map> typeData = methodAttributes .get(type); if (typeData == null) { - typeData = new HashMap>(); + typeData = new TreeMap>( + jMethodComparator); methodAttributes.put(type, typeData); } - addMapping(typeData, method, methodAttribute); + Map> methods = methodAttributes + .get(type); + if (methods == null) { + methods = new TreeMap>( + jMethodComparator); + methodAttributes.put(type, methods); + } + + Set attributes = methods.get(method); + if (attributes == null) { + attributes = new TreeSet(); + methods.put(method, attributes); + } + + attributes.add(methodAttribute); } } @@ -564,7 +625,7 @@ public class ConnectorBundle { } } - private static Set> frameworkHandledTypes = new HashSet>(); + private static Set> frameworkHandledTypes = new LinkedHashSet>(); { frameworkHandledTypes.add(String.class); frameworkHandledTypes.add(Boolean.class); @@ -611,7 +672,9 @@ public class ConnectorBundle { public void setNeedsDelegateToWidget(Property property, JClassType type) { if (!isNeedsDelegateToWidget(type)) { - needsDelegateToWidget.put(type, Sets.newHashSet(property)); + TreeSet set = new TreeSet(); + set.add(property); + needsDelegateToWidget.put(type, set); } else if (!needsDelegateToWidget.get(type).contains(property)) { needsDelegateToWidget.get(type).add(property); } diff --git a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/Property.java b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/Property.java index f07b1c29fd..0c849bead5 100644 --- a/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/Property.java +++ b/client-compiler/src/com/vaadin/server/widgetsetutils/metadata/Property.java @@ -24,7 +24,7 @@ import com.google.gwt.core.ext.typeinfo.JPrimitiveType; import com.google.gwt.core.ext.typeinfo.JType; import com.google.gwt.user.rebind.SourceWriter; -public abstract class Property { +public abstract class Property implements Comparable { private final String name; private final JClassType beanType; private final JType propertyType; @@ -107,6 +107,20 @@ public abstract class Property { + getName().hashCode(); } + @Override + public int compareTo(Property o) { + int comp = getName().compareTo(o.getName()); + if (comp == 0) { + comp = getBeanType().getQualifiedSourceName().compareTo( + o.getBeanType().getQualifiedSourceName()); + } + if (comp == 0) { + comp = getClass().getCanonicalName().compareTo( + o.getClass().getCanonicalName()); + } + return comp; + } + public abstract T getAnnotation( Class annotationClass); -- cgit v1.2.3 From a1978dfa16dbb35ee7ac7ab9026af27624158be7 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Tue, 14 Jul 2015 15:31:17 +0300 Subject: Convert EmbeddedWithNullSource test to TB4 Change-Id: I495e3b25282aaf7a3122b8503f08bb339a772560 --- .../EmbeddedWithNullSourceTest.java | 46 ++++++++++++++++++++++ .../abstractembedded/EmbeddedWithNullSource.html | 27 ------------- 2 files changed, 46 insertions(+), 27 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/abstractembedded/EmbeddedWithNullSourceTest.java delete mode 100644 uitest/tb2/com/vaadin/tests/components/abstractembedded/EmbeddedWithNullSource.html diff --git a/uitest/src/com/vaadin/tests/components/abstractembedded/EmbeddedWithNullSourceTest.java b/uitest/src/com/vaadin/tests/components/abstractembedded/EmbeddedWithNullSourceTest.java new file mode 100644 index 0000000000..649ee42986 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/abstractembedded/EmbeddedWithNullSourceTest.java @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.abstractembedded; + +import java.io.IOException; +import java.util.List; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.remote.DesiredCapabilities; + +import com.vaadin.testbench.parallel.Browser; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class EmbeddedWithNullSourceTest extends MultiBrowserTest { + + @Override + public List getBrowsersToTest() { + // No Flash on PhantomJS, IE 11 has a timeout issue, looks like a + // IEDriver problem, not reproduced running locally. + return getBrowserCapabilities(Browser.IE8, Browser.IE9, Browser.IE10, + Browser.CHROME, Browser.FIREFOX); + } + + @Test + public void testEmbeddedWithNullSource() throws IOException { + openTestURL(); + + waitForElementPresent(By.className("v-image")); + + compareScreen("nullSources"); + } +} diff --git a/uitest/tb2/com/vaadin/tests/components/abstractembedded/EmbeddedWithNullSource.html b/uitest/tb2/com/vaadin/tests/components/abstractembedded/EmbeddedWithNullSource.html deleted file mode 100644 index 37186bd901..0000000000 --- a/uitest/tb2/com/vaadin/tests/components/abstractembedded/EmbeddedWithNullSource.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - -EmbeddedWithNullSource - - - - - - - - - - - - - - - - - -
    EmbeddedWithNullSource
    open/run/EmbeddedWithNullSource?restartApplication
    screenCapture
    - - -- cgit v1.2.3 From ef79e1aa98b6460e43bfc63672b862513c1e9404 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Mon, 13 Jul 2015 16:36:55 +0300 Subject: Allow using only hostname with ?superdevmode Change-Id: Ib88062d13fc3a22970b526a7fc56a22ba860637f --- client/src/com/vaadin/client/SuperDevMode.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/client/src/com/vaadin/client/SuperDevMode.java b/client/src/com/vaadin/client/SuperDevMode.java index c72cd73939..f664244715 100644 --- a/client/src/com/vaadin/client/SuperDevMode.java +++ b/client/src/com/vaadin/client/SuperDevMode.java @@ -189,7 +189,11 @@ public class SuperDevMode { if (serverUrl == null || "".equals(serverUrl)) { serverUrl = "http://localhost:9876/"; } else { - serverUrl = "http://" + serverUrl + "/"; + if (serverUrl.contains(":")) { + serverUrl = "http://" + serverUrl + "/"; + } else { + serverUrl = "http://" + serverUrl + ":9876/"; + } } if (hasSession(SKIP_RECOMPILE)) { -- cgit v1.2.3 From 0e085a9ddbf75b7052d521ade84cd08c986e3469 Mon Sep 17 00:00:00 2001 From: Sauli Tähkäpää Date: Fri, 13 Mar 2015 22:29:59 +0200 Subject: Increase Tooltip z-index to be larger than the default overlay z-index. (#14854) Change-Id: Ib6a2f77aadc9cb1afe8a8e43be9916de3d2eaf44 --- client/src/com/vaadin/client/VTooltip.java | 3 ++ .../com/vaadin/tests/tooltip/MenuBarTooltip.java | 34 ++++++++++++++++ .../vaadin/tests/tooltip/MenuBarTooltipTest.java | 46 ++++++++++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 uitest/src/com/vaadin/tests/tooltip/MenuBarTooltip.java create mode 100644 uitest/src/com/vaadin/tests/tooltip/MenuBarTooltipTest.java diff --git a/client/src/com/vaadin/client/VTooltip.java b/client/src/com/vaadin/client/VTooltip.java index 4e59040298..f3d65cd20a 100644 --- a/client/src/com/vaadin/client/VTooltip.java +++ b/client/src/com/vaadin/client/VTooltip.java @@ -89,6 +89,9 @@ public class VTooltip extends VOverlay { LiveValue.ASSERTIVE); Roles.getTooltipRole().setAriaRelevantProperty(getElement(), RelevantValue.ADDITIONS); + + // Tooltip needs to be on top of other VOverlay elements. + setZIndex(VOverlay.Z_INDEX + 1); } /** diff --git a/uitest/src/com/vaadin/tests/tooltip/MenuBarTooltip.java b/uitest/src/com/vaadin/tests/tooltip/MenuBarTooltip.java new file mode 100644 index 0000000000..ff470336f5 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tooltip/MenuBarTooltip.java @@ -0,0 +1,34 @@ +package com.vaadin.tests.tooltip; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.MenuBar; + +public class MenuBarTooltip extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + MenuBar menubar = new MenuBar(); + + MenuBar.MenuItem menuitem = menubar.addItem("Menu item", null, null); + menuitem.setDescription("Menu item description"); + + MenuBar.MenuItem submenuitem1 = menuitem.addItem("Submenu item 1", null, null); + submenuitem1.setDescription("Submenu item 1 description"); + + MenuBar.MenuItem submenuitem2 = menuitem.addItem("Submenu item 2", null, null); + submenuitem2.setDescription("Submenu item 2 description"); + + addComponent(menubar); + } + + @Override + protected Integer getTicketNumber() { + return 14854; + } + + @Override + protected String getTestDescription() { + return "MenuItem tooltip should have a larger z-index than MenuBar/MenuItem."; + } +} diff --git a/uitest/src/com/vaadin/tests/tooltip/MenuBarTooltipTest.java b/uitest/src/com/vaadin/tests/tooltip/MenuBarTooltipTest.java new file mode 100644 index 0000000000..9b2f7d13d6 --- /dev/null +++ b/uitest/src/com/vaadin/tests/tooltip/MenuBarTooltipTest.java @@ -0,0 +1,46 @@ +package com.vaadin.tests.tooltip; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.greaterThan; + +import org.junit.Test; +import org.openqa.selenium.By; + +import com.vaadin.testbench.elements.MenuBarElement; +import com.vaadin.tests.tb3.MultiBrowserTest; +import com.vaadin.ui.themes.ChameleonTheme; +import com.vaadin.ui.themes.Reindeer; +import com.vaadin.ui.themes.Runo; +import com.vaadin.ui.themes.ValoTheme; + +public class MenuBarTooltipTest extends MultiBrowserTest { + + @Test + public void toolTipShouldBeOnTopOfMenuItem() { + String[] themes = new String[] { + ValoTheme.THEME_NAME, + Reindeer.THEME_NAME, + Runo.THEME_NAME, + ChameleonTheme.THEME_NAME + }; + + for(String theme : themes) { + assertZIndices(theme); + } + } + + public void assertZIndices(String theme) { + openTestURL("theme=" + theme); + + $(MenuBarElement.class).first().clickItem("Menu item"); + + assertThat(String.format("Invalid z-index for theme %s.", theme), + getZIndex("v-tooltip"), greaterThan(getZIndex("v-menubar-popup"))); + } + + private int getZIndex(String className) { + return Integer.parseInt( + findElement(By.className(className)).getCssValue("z-index")); + } + +} \ No newline at end of file -- cgit v1.2.3 From 3b05685493d17e89404025e3cdd81d47e511b0ce Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Wed, 15 Jul 2015 09:57:41 +0300 Subject: Use FixedNotificationElement in BasicPersonFormTest This makes tests more stable with IE browsers Change-Id: I9f02180614e860d41f1b9bc90ec4cc4a5d243f0e --- uitest/src/com/vaadin/tests/fieldgroup/BasicPersonFormTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uitest/src/com/vaadin/tests/fieldgroup/BasicPersonFormTest.java b/uitest/src/com/vaadin/tests/fieldgroup/BasicPersonFormTest.java index f5d78029c9..2562412480 100644 --- a/uitest/src/com/vaadin/tests/fieldgroup/BasicPersonFormTest.java +++ b/uitest/src/com/vaadin/tests/fieldgroup/BasicPersonFormTest.java @@ -20,13 +20,13 @@ import org.junit.Assert; import com.vaadin.testbench.TestBenchElement; import com.vaadin.testbench.elements.ButtonElement; import com.vaadin.testbench.elements.CheckBoxElement; -import com.vaadin.testbench.elements.NotificationElement; import com.vaadin.testbench.elements.TableElement; import com.vaadin.testbench.elements.TableRowElement; import com.vaadin.testbench.elements.TextAreaElement; import com.vaadin.testbench.elements.TextFieldElement; import com.vaadin.tests.data.bean.Sex; import com.vaadin.tests.tb3.MultiBrowserTest; +import com.vaadin.tests.tb3.newelements.FixedNotificationElement; public abstract class BasicPersonFormTest extends MultiBrowserTest { @@ -82,7 +82,7 @@ public abstract class BasicPersonFormTest extends MultiBrowserTest { } protected void closeNotification() { - $(NotificationElement.class).first().close(); + $(FixedNotificationElement.class).first().close(); } protected CheckBoxElement getPostCommitFailsCheckBox() { -- cgit v1.2.3 From 0f9d0b0bf1cd5fb58f47f22bd6d52a9fac31c530 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Thu, 9 Jul 2015 14:51:30 +0300 Subject: Support frozen columns in Grid editor (#16727) Change-Id: Iff797c3bf90a6021099a3ed4082cfca3a6fb3540 --- WebContent/VAADIN/themes/base/grid/grid.scss | 10 +++ client/src/com/vaadin/client/widgets/Grid.java | 43 ++++++++++-- .../components/grid/GridEditorFrozenColumnsUI.java | 43 ++++++++++++ .../grid/GridEditorFrozenColumnsUITest.java | 78 ++++++++++++++++++++++ .../vaadin/tests/components/grid/GridEditorUI.java | 6 +- .../tests/components/grid/GridEditorUITest.java | 2 +- .../basicfeatures/client/GridEditorClientTest.java | 6 +- .../grid/basicfeatures/server/GridEditorTest.java | 2 +- 8 files changed, 178 insertions(+), 12 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/grid/GridEditorFrozenColumnsUI.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/GridEditorFrozenColumnsUITest.java diff --git a/WebContent/VAADIN/themes/base/grid/grid.scss b/WebContent/VAADIN/themes/base/grid/grid.scss index 1653032703..31403428cd 100644 --- a/WebContent/VAADIN/themes/base/grid/grid.scss +++ b/WebContent/VAADIN/themes/base/grid/grid.scss @@ -199,6 +199,12 @@ $v-grid-details-border-bottom-stripe: 1px solid darken($v-grid-row-background-co border-left: none; } } + + .#{$primaryStyleName}-editor-cells.frozen > div { + @include box-shadow(1px 0 2px rgba(0,0,0,.1)); + border-right: $v-grid-cell-vertical-border; + border-left: none; + } .#{$primaryStyleName}-row-stripe > td { background-color: $v-grid-row-stripe-background-color; @@ -342,6 +348,10 @@ $v-grid-details-border-bottom-stripe: 1px solid darken($v-grid-row-background-co .#{$primaryStyleName}-editor-cells { position: relative; white-space: nowrap; + + &.frozen { + z-index: 2; + } > div { display: inline-block; diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 58fc532a77..232d67c1d4 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -1135,6 +1135,8 @@ public class Grid extends ResizeComposite implements private DivElement editorOverlay = DivElement.as(DOM.createDiv()); private DivElement cellWrapper = DivElement.as(DOM.createDiv()); + private DivElement frozenCellWrapper = DivElement.as(DOM.createDiv()); + private DivElement messageAndButtonsWrapper = DivElement.as(DOM .createDiv()); @@ -1530,15 +1532,31 @@ public class Grid extends ResizeComposite implements }); gridElement.appendChild(editorOverlay); + editorOverlay.appendChild(frozenCellWrapper); editorOverlay.appendChild(cellWrapper); editorOverlay.appendChild(messageAndButtonsWrapper); + int frozenColumns = grid.getVisibleFrozenColumnCount(); + double frozenColumnsWidth = 0; + double cellHeight = 0; + for (int i = 0; i < tr.getCells().getLength(); i++) { Element cell = createCell(tr.getCells().getItem(i)); - - cellWrapper.appendChild(cell); + cellHeight = Math.max(cellHeight, WidgetUtil + .getRequiredHeightBoundingClientRectDouble(tr + .getCells().getItem(i))); Column column = grid.getVisibleColumn(i); + + if (i < frozenColumns) { + frozenCellWrapper.appendChild(cell); + frozenColumnsWidth += WidgetUtil + .getRequiredWidthBoundingClientRectDouble(tr + .getCells().getItem(i)); + } else { + cellWrapper.appendChild(cell); + } + if (column.isEditable()) { Widget editor = getHandler().getWidget(column); @@ -1560,6 +1578,10 @@ public class Grid extends ResizeComposite implements } } + setBounds(frozenCellWrapper, 0, 0, frozenColumnsWidth, 0); + setBounds(cellWrapper, frozenColumnsWidth, 0, tr.getOffsetWidth() + - frozenColumnsWidth, cellHeight); + // Only add these elements once if (!messageAndButtonsWrapper.isOrHasChild(messageWrapper)) { messageAndButtonsWrapper.appendChild(messageWrapper); @@ -1624,6 +1646,7 @@ public class Grid extends ResizeComposite implements editorOverlay.removeAllChildren(); cellWrapper.removeAllChildren(); + frozenCellWrapper.removeAllChildren(); editorOverlay.removeFromParent(); scrollHandler.removeHandler(); @@ -1636,6 +1659,7 @@ public class Grid extends ResizeComposite implements editorOverlay.removeClassName(styleName); cellWrapper.removeClassName(styleName + "-cells"); + frozenCellWrapper.removeClassName(styleName + "-cells"); messageAndButtonsWrapper.removeClassName(styleName + "-footer"); messageWrapper.removeClassName(styleName + "-message"); @@ -1648,6 +1672,7 @@ public class Grid extends ResizeComposite implements editorOverlay.setClassName(styleName); cellWrapper.setClassName(styleName + "-cells"); + frozenCellWrapper.setClassName(styleName + "-cells frozen"); messageAndButtonsWrapper.setClassName(styleName + "-footer"); messageWrapper.setClassName(styleName + "-message"); @@ -1698,7 +1723,8 @@ public class Grid extends ResizeComposite implements private void updateHorizontalScrollPosition() { double scrollLeft = grid.getScrollLeft(); - cellWrapper.getStyle().setLeft(-scrollLeft, Unit.PX); + cellWrapper.getStyle().setLeft( + frozenCellWrapper.getOffsetWidth() - scrollLeft, Unit.PX); } protected void setGridEnabled(boolean enabled) { @@ -6051,7 +6077,12 @@ public class Grid extends ResizeComposite implements } private void updateFrozenColumns() { - int numberOfColumns = frozenColumnCount; + escalator.getColumnConfiguration().setFrozenColumnCount( + getVisibleFrozenColumnCount()); + } + + private int getVisibleFrozenColumnCount() { + int numberOfColumns = getFrozenColumnCount(); // for the escalator the hidden columns are not in the frozen column // count, but for grid they are. thus need to convert the index @@ -6066,9 +6097,7 @@ public class Grid extends ResizeComposite implements } else if (selectionColumn != null) { numberOfColumns++; } - - escalator.getColumnConfiguration() - .setFrozenColumnCount(numberOfColumns); + return numberOfColumns; } /** diff --git a/uitest/src/com/vaadin/tests/components/grid/GridEditorFrozenColumnsUI.java b/uitest/src/com/vaadin/tests/components/grid/GridEditorFrozenColumnsUI.java new file mode 100644 index 0000000000..d2414a8c40 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/GridEditorFrozenColumnsUI.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.grid; + +import com.vaadin.tests.util.PersonContainer; +import com.vaadin.ui.Grid; + +public class GridEditorFrozenColumnsUI extends GridEditorUI { + + @Override + protected Grid createGrid(PersonContainer container) { + Grid grid = super.createGrid(container); + + grid.setFrozenColumnCount(2); + + grid.setWidth("600px"); + + return grid; + } + + @Override + protected Integer getTicketNumber() { + return 16727; + } + + @Override + protected String getTestDescription() { + return "Frozen columns should also freeze cells in editor."; + } +} diff --git a/uitest/src/com/vaadin/tests/components/grid/GridEditorFrozenColumnsUITest.java b/uitest/src/com/vaadin/tests/components/grid/GridEditorFrozenColumnsUITest.java new file mode 100644 index 0000000000..75d71a3c40 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/GridEditorFrozenColumnsUITest.java @@ -0,0 +1,78 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.grid; + +import java.io.IOException; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.WebElement; +import org.openqa.selenium.interactions.Actions; + +import com.vaadin.testbench.elements.GridElement; +import com.vaadin.testbench.elements.GridElement.GridCellElement; +import com.vaadin.testbench.parallel.TestCategory; +import com.vaadin.tests.tb3.MultiBrowserTest; + +@TestCategory("grid") +public class GridEditorFrozenColumnsUITest extends MultiBrowserTest { + + @Test + public void testEditorWithFrozenColumns() throws IOException { + openTestURL(); + + openEditor(10); + + compareScreen("noscroll"); + + scrollGridHorizontallyTo(100); + + compareScreen("scrolled"); + } + + private void openEditor(int rowIndex) { + GridElement grid = $(GridElement.class).first(); + + GridCellElement cell = grid.getCell(rowIndex, 1); + + new Actions(driver).moveToElement(cell).doubleClick().build().perform(); + } + + private void scrollGridHorizontallyTo(double px) { + executeScript("arguments[0].scrollLeft = " + px, + getGridHorizontalScrollbar()); + } + + private Object executeScript(String script, WebElement element) { + final WebDriver driver = getDriver(); + if (driver instanceof JavascriptExecutor) { + final JavascriptExecutor je = (JavascriptExecutor) driver; + return je.executeScript(script, element); + } else { + throw new IllegalStateException("current driver " + + getDriver().getClass().getName() + " is not a " + + JavascriptExecutor.class.getSimpleName()); + } + } + + private WebElement getGridHorizontalScrollbar() { + return getDriver() + .findElement( + By.xpath("//div[contains(@class, \"v-grid-scroller-horizontal\")]")); + } +} diff --git a/uitest/src/com/vaadin/tests/components/grid/GridEditorUI.java b/uitest/src/com/vaadin/tests/components/grid/GridEditorUI.java index 60e241bae3..0a302967e8 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridEditorUI.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridEditorUI.java @@ -28,6 +28,10 @@ public class GridEditorUI extends AbstractTestUI { protected void setup(VaadinRequest request) { PersonContainer container = PersonContainer.createWithTestData(); + addComponent(createGrid(container)); + } + + protected Grid createGrid(PersonContainer container) { Grid grid = new Grid(container); // Don't use address since there's no converter @@ -43,7 +47,7 @@ public class GridEditorUI extends AbstractTestUI { grid.getColumn("phoneNumber").getEditorField().setReadOnly(true); - addComponent(grid); + return grid; } } diff --git a/uitest/src/com/vaadin/tests/components/grid/GridEditorUITest.java b/uitest/src/com/vaadin/tests/components/grid/GridEditorUITest.java index 47dc90e33a..3d0b3bb071 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridEditorUITest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridEditorUITest.java @@ -45,7 +45,7 @@ public class GridEditorUITest extends MultiBrowserTest { openEditor(10); - assertTrue("Edtor should be opened with a password field", + assertTrue("Editor should be opened with a password field", isElementPresent(PasswordFieldElement.class)); assertFalse("Notification was present", diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java index f437589a39..43fe29bc02 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java @@ -134,10 +134,12 @@ public class GridEditorClientTest extends GridBasicClientFeaturesTest { @Test public void testWithSelectionColumn() throws Exception { selectMenuPath("Component", "State", "Selection mode", "multi"); + selectMenuPath("Component", "State", "Frozen column count", + "-1 columns"); selectMenuPath(EDIT_ROW_5); - WebElement editorCells = findElement(By - .className("v-grid-editor-cells")); + WebElement editorCells = findElements( + By.className("v-grid-editor-cells")).get(1); List selectorDivs = editorCells.findElements(By .cssSelector("div")); diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java index 0c39b3e509..b77cc41946 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java @@ -361,7 +361,7 @@ public class GridEditorTest extends GridBasicFeaturesTest { assertEquals( "Not editable cell did not contain correct classname", "not-editable", - editor.findElement(By.className("v-grid-editor-cells")) + editor.findElements(By.className("v-grid-editor-cells")).get(1) .findElements(By.xpath("./div")).get(3) .getAttribute("class")); -- cgit v1.2.3 From b5365d5cca1a25efdb0b80855d28d20da71111d1 Mon Sep 17 00:00:00 2001 From: elmot Date: Fri, 10 Jul 2015 12:09:52 +0300 Subject: StringToBooleanConverter API improved (#18466) Added simple customization for text representation Added API for locale-specific conversion Change-Id: I866b37bb085e85ef3d67e9d5e6db82b22e9bc464 --- .../util/converter/StringToBooleanConverter.java | 83 +++++++++++++++++----- .../converter/StringToBooleanConverterTest.java | 34 +++++++++ 2 files changed, 99 insertions(+), 18 deletions(-) diff --git a/server/src/com/vaadin/data/util/converter/StringToBooleanConverter.java b/server/src/com/vaadin/data/util/converter/StringToBooleanConverter.java index 0e802da879..dafcf8dac2 100644 --- a/server/src/com/vaadin/data/util/converter/StringToBooleanConverter.java +++ b/server/src/com/vaadin/data/util/converter/StringToBooleanConverter.java @@ -19,20 +19,43 @@ package com.vaadin.data.util.converter; import java.util.Locale; /** - * A converter that converts from {@link String} to {@link Boolean} and back. - * The String representation is given by Boolean.toString(). - *

    - * Leading and trailing white spaces are ignored when converting from a String. - *

    - * + * A converter that converts from {@link String} to {@link Boolean} and back. The String representation is given by + * {@link Boolean#toString()} or provided in constructor {@link #StringToBooleanConverter(String, String)}. + *

    Leading and trailing white spaces are ignored when converting from a String.

    + *

    For language-dependent representation, subclasses should overwrite {@link #getFalseString(Locale)} and {@link #getTrueString(Locale)}

    + * * @author Vaadin Ltd * @since 7.0 */ public class StringToBooleanConverter implements Converter { + private final String trueString; + + private final String falseString; + + /** + * Creates converter with default string representations - "true" and "false" + * + */ + public StringToBooleanConverter() { + this(Boolean.TRUE.toString(), Boolean.FALSE.toString()); + } + + /** + * Creates converter with custom string representation. + * + * @since + * @param falseString string representation for false + * @param trueString string representation for true + */ + public StringToBooleanConverter(String trueString, String falseString) { + this.trueString = trueString; + this.falseString = falseString; + } + /* * (non-Javadoc) - * + * * @see * com.vaadin.data.util.converter.Converter#convertToModel(java.lang.Object, * java.lang.Class, java.util.Locale) @@ -59,26 +82,26 @@ public class StringToBooleanConverter implements Converter { } /** - * Gets the string representation for true. Default is "true". - * + * Gets the string representation for true. Default is "true", if not set in constructor. + * * @return the string representation for true */ protected String getTrueString() { - return Boolean.TRUE.toString(); + return trueString; } /** - * Gets the string representation for false. Default is "false". - * + * Gets the string representation for false. Default is "false", if not set in constructor. + * * @return the string representation for false */ protected String getFalseString() { - return Boolean.FALSE.toString(); + return falseString; } /* * (non-Javadoc) - * + * * @see * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang * .Object, java.lang.Class, java.util.Locale) @@ -91,15 +114,39 @@ public class StringToBooleanConverter implements Converter { return null; } if (value) { - return getTrueString(); + return getTrueString(locale); } else { - return getFalseString(); + return getFalseString(locale); } } + /** + * Gets the locale-depended string representation for false. + * Default is locale-independent value provided by {@link #getFalseString()} + * + * @since + * @param locale to be used + * @return the string representation for false + */ + protected String getFalseString(Locale locale) { + return getFalseString(); + } + + /** + * Gets the locale-depended string representation for true. + * Default is locale-independent value provided by {@link #getTrueString()} + * + * @since + * @param locale to be used + * @return the string representation for true + */ + protected String getTrueString(Locale locale) { + return getTrueString(); + } + /* * (non-Javadoc) - * + * * @see com.vaadin.data.util.converter.Converter#getModelType() */ @Override @@ -109,7 +156,7 @@ public class StringToBooleanConverter implements Converter { /* * (non-Javadoc) - * + * * @see com.vaadin.data.util.converter.Converter#getPresentationType() */ @Override diff --git a/server/tests/src/com/vaadin/tests/data/converter/StringToBooleanConverterTest.java b/server/tests/src/com/vaadin/tests/data/converter/StringToBooleanConverterTest.java index f734d76633..6e81af97a3 100644 --- a/server/tests/src/com/vaadin/tests/data/converter/StringToBooleanConverterTest.java +++ b/server/tests/src/com/vaadin/tests/data/converter/StringToBooleanConverterTest.java @@ -4,9 +4,25 @@ import junit.framework.TestCase; import com.vaadin.data.util.converter.StringToBooleanConverter; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + public class StringToBooleanConverterTest extends TestCase { StringToBooleanConverter converter = new StringToBooleanConverter(); + StringToBooleanConverter yesNoConverter = new StringToBooleanConverter("yes","no"); + StringToBooleanConverter localeConverter = new StringToBooleanConverter() { + @Override + public String getFalseString(Locale locale) { + return SimpleDateFormat.getDateInstance(SimpleDateFormat.LONG,locale).format(new Date(3000000000000L)); + } + + @Override + public String getTrueString(Locale locale) { + return SimpleDateFormat.getDateInstance(SimpleDateFormat.LONG,locale).format(new Date(2000000000000L)); + } + }; public void testNullConversion() { assertEquals(null, converter.convertToModel(null, Boolean.class, null)); @@ -20,4 +36,22 @@ public class StringToBooleanConverterTest extends TestCase { assertTrue(converter.convertToModel("true", Boolean.class, null)); assertFalse(converter.convertToModel("false", Boolean.class, null)); } + + public void testYesNoValueConversion() { + assertTrue(yesNoConverter.convertToModel("yes", Boolean.class, null)); + assertFalse(yesNoConverter.convertToModel("no", Boolean.class, null)); + + assertEquals("yes", yesNoConverter.convertToPresentation(true, String.class, null)); + assertEquals("no", yesNoConverter.convertToPresentation(false, String.class, null)); + } + + + public void testLocale() { + assertEquals("May 18, 2033", localeConverter.convertToPresentation(true, String.class, Locale.US)); + assertEquals("January 24, 2065", localeConverter.convertToPresentation(false, String.class, Locale.US)); + + assertEquals("18. Mai 2033", localeConverter.convertToPresentation(true, String.class, Locale.GERMANY)); + assertEquals("24. Januar 2065", localeConverter.convertToPresentation(false, String.class, Locale.GERMANY)); + } + } -- cgit v1.2.3 From e288b0d159e4116b863836c4486a7bf289da16eb Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Fri, 10 Jul 2015 15:19:36 +0300 Subject: Prevent Grid editor move in unbuffered mode if validation errors in fields Change-Id: I37f3c21f4464c8f83308a741ed51485f7bd0375a --- client/src/com/vaadin/client/widgets/Grid.java | 68 +++++++++++++--------- server/src/com/vaadin/ui/Grid.java | 39 ++++++++----- .../grid/basicfeatures/GridBasicFeatures.java | 1 + .../server/GridEditorBufferedTest.java | 31 ++++++++-- .../grid/basicfeatures/server/GridEditorTest.java | 3 +- .../server/GridEditorUnbufferedTest.java | 32 +++++++--- 6 files changed, 117 insertions(+), 57 deletions(-) diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 86d2ed5f00..0555df3c1f 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -1159,8 +1159,17 @@ public class Grid extends ResizeComposite implements private int columnIndex = -1; private String styleName = null; + /* + * Used to track Grid horizontal scrolling + */ private HandlerRegistration scrollHandler; + /* + * Used to open editor once Grid has vertically scrolled to the proper + * position and data is available + */ + private HandlerRegistration dataAvailableHandler; + private final Button saveButton; private final Button cancelButton; @@ -1223,9 +1232,7 @@ public class Grid extends ResizeComposite implements state = State.ACTIVE; bindTimeout.cancel(); - assert rowIndex == request.getRowIndex() : "Request row index " - + request.getRowIndex() - + " did not match the saved row index " + rowIndex; + rowIndex = request.getRowIndex(); showOverlay(); } } @@ -1233,16 +1240,17 @@ public class Grid extends ResizeComposite implements @Override public void onError(EditorRequest request) { if (state == State.BINDING) { - state = State.INACTIVE; + if (rowIndex == -1) { + doCancel(); + } else { + state = State.ACTIVE; + } bindTimeout.cancel(); // TODO show something in the DOM as well? getLogger().warning( "An error occurred while trying to show the " + "Grid editor"); - grid.getEscalator().setScrollLocked(Direction.VERTICAL, - false); - updateSelectionCheckboxesAsNeeded(true); } } }; @@ -1337,7 +1345,7 @@ public class Grid extends ResizeComposite implements * * @since 7.5 */ - public void editRow(int rowIndex, int columnIndex) { + public void editRow(final int rowIndex, int columnIndex) { if (!enabled) { throw new IllegalStateException( "Cannot edit row: editor is not enabled"); @@ -1349,14 +1357,23 @@ public class Grid extends ResizeComposite implements } } - this.rowIndex = rowIndex; this.columnIndex = columnIndex; - state = State.ACTIVATING; if (grid.getEscalator().getVisibleRowRange().contains(rowIndex)) { - show(); + show(rowIndex); } else { + hideOverlay(); + dataAvailableHandler = grid + .addDataAvailableHandler(new DataAvailableHandler() { + @Override + public void onDataAvailable(DataAvailableEvent event) { + if (event.getAvailableRows().contains(rowIndex)) { + show(rowIndex); + dataAvailableHandler.removeHandler(); + } + } + }); grid.scrollToRow(rowIndex, ScrollDestination.MIDDLE); } } @@ -1379,13 +1396,16 @@ public class Grid extends ResizeComposite implements throw new IllegalStateException( "Cannot cancel edit: editor is not in edit mode"); } - hideOverlay(); - grid.getEscalator().setScrollLocked(Direction.VERTICAL, false); + handler.cancel(new EditorRequestImpl(grid, rowIndex, null)); + doCancel(); + } - EditorRequest request = new EditorRequestImpl(grid, rowIndex, - null); - handler.cancel(request); + private void doCancel() { + hideOverlay(); state = State.INACTIVE; + rowIndex = -1; + columnIndex = -1; + grid.getEscalator().setScrollLocked(Direction.VERTICAL, false); updateSelectionCheckboxesAsNeeded(true); grid.fireEvent(new EditorCloseEvent(grid.eventCell)); } @@ -1480,7 +1500,7 @@ public class Grid extends ResizeComposite implements this.enabled = enabled; } - protected void show() { + protected void show(int rowIndex) { if (state == State.ACTIVATING) { state = State.BINDING; bindTimeout.schedule(BIND_TIMEOUT_MS); @@ -1498,15 +1518,6 @@ public class Grid extends ResizeComposite implements assert this.grid == null : "Can only attach editor to Grid once"; this.grid = grid; - - grid.addDataAvailableHandler(new DataAvailableHandler() { - @Override - public void onDataAvailable(DataAvailableEvent event) { - if (event.getAvailableRows().contains(rowIndex)) { - show(); - } - } - }); } protected State getState() { @@ -6616,6 +6627,7 @@ public class Grid extends ResizeComposite implements && key == Editor.KEYCODE_HIDE; if (!editorIsActive && editor.isEnabled() && openEvent) { + editor.editRow(eventCell.getRowIndex(), eventCell.getColumnIndexDOM()); fireEvent(new EditorOpenEvent(eventCell)); @@ -6624,16 +6636,16 @@ public class Grid extends ResizeComposite implements return true; } else if (editorIsActive && !editor.isBuffered() && moveEvent) { - cellFocusHandler.setCellFocus(eventCell); + cellFocusHandler.setCellFocus(eventCell); editor.editRow(eventCell.getRowIndex(), eventCell.getColumnIndexDOM()); - fireEvent(new EditorMoveEvent(eventCell)); return true; } else if (editorIsActive && closeEvent) { + editor.cancel(); FocusUtil.setFocus(this, true); diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java index 251ec0f678..f025b6e1c0 100644 --- a/server/src/com/vaadin/ui/Grid.java +++ b/server/src/com/vaadin/ui/Grid.java @@ -4129,28 +4129,37 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, @Override public void bind(int rowIndex) { - Exception exception = null; try { Object id = getContainerDataSource().getIdByIndex(rowIndex); - if (!isEditorBuffered() || editedItemId == null) { - editedItemId = id; - } - if (editedItemId.equals(id)) { - doEditItem(); + final boolean opening = editedItemId == null; + + final boolean moving = !opening && !editedItemId.equals(id); + + final boolean allowMove = !isEditorBuffered() + && getEditorFieldGroup().isValid(); + + if (opening || !moving || allowMove) { + doBind(id); + } else { + failBind(null); } } catch (Exception e) { - exception = e; + failBind(e); } + } - if (exception != null) { - handleError(exception); - doCancelEditor(); - getEditorRpc().confirmBind(false); - } else { - doEditItem(); - getEditorRpc().confirmBind(true); + private void doBind(Object id) { + editedItemId = id; + doEditItem(); + getEditorRpc().confirmBind(true); + } + + private void failBind(Exception e) { + if (e != null) { + handleError(e); } + getEditorRpc().confirmBind(false); } @Override @@ -6004,7 +6013,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, if (!isEditorEnabled()) { throw new IllegalStateException("Item editor is not enabled"); } else if (isEditorBuffered() && editedItemId != null) { - throw new IllegalStateException("Editing item + " + itemId + throw new IllegalStateException("Editing item " + itemId + " failed. Item editor is already editing item " + editedItemId); } else if (!getContainerDataSource().containsId(itemId)) { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index 272ff1c9ae..3154fd2a85 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -298,6 +298,7 @@ public class GridBasicFeatures extends AbstractComponentTest { new NumberRenderer(new DecimalFormat("0,000.00", DecimalFormatSymbols.getInstance(new Locale("fi", "FI"))))); + grid.getColumn(getColumnProperty(col++)).setRenderer( new DateRenderer(new SimpleDateFormat("dd.MM.yy HH:mm"))); grid.getColumn(getColumnProperty(col++)).setRenderer( diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java index 0f2fe54696..57f4b877df 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorBufferedTest.java @@ -163,7 +163,7 @@ public class GridEditorBufferedTest extends GridEditorTest { } @Test - public void testNoScrollAfterEditByAPI() { + public void testScrollDisabledOnProgrammaticOpen() { int originalScrollPos = getGridVerticalScrollPos(); selectMenuPath(EDIT_ITEM_5); @@ -175,7 +175,7 @@ public class GridEditorBufferedTest extends GridEditorTest { } @Test - public void testNoScrollAfterEditByMouse() { + public void testScrollDisabledOnMouseOpen() { int originalScrollPos = getGridVerticalScrollPos(); GridCellElement cell_5_0 = getGridElement().getCell(5, 0); @@ -188,7 +188,7 @@ public class GridEditorBufferedTest extends GridEditorTest { } @Test - public void testNoScrollAfterEditByKeyboard() { + public void testScrollDisabledOnKeyboardOpen() { int originalScrollPos = getGridVerticalScrollPos(); GridCellElement cell_5_0 = getGridElement().getCell(5, 0); @@ -216,7 +216,28 @@ public class GridEditorBufferedTest extends GridEditorTest { } @Test - public void testProgrammaticOpeningWhenOpen() { + public void testMouseOpeningDisabledWhenOpen() { + selectMenuPath(EDIT_ITEM_5); + + getGridElement().getCell(4, 0).doubleClick(); + + assertEquals("Editor should still edit row 5", "(5, 0)", + getEditorWidgets().get(0).getAttribute("value")); + } + + @Test + public void testKeyboardOpeningDisabledWhenOpen() { + selectMenuPath(EDIT_ITEM_5); + + new Actions(getDriver()).click(getGridElement().getCell(4, 0)) + .sendKeys(Keys.ENTER).perform(); + + assertEquals("Editor should still edit row 5", "(5, 0)", + getEditorWidgets().get(0).getAttribute("value")); + } + + @Test + public void testProgrammaticOpeningDisabledWhenOpen() { selectMenuPath(EDIT_ITEM_5); assertEditorOpen(); assertEquals("Editor should edit row 5", "(5, 0)", getEditorWidgets() @@ -232,7 +253,7 @@ public class GridEditorBufferedTest extends GridEditorTest { } @Test - public void testUserSortDisabled() { + public void testUserSortDisabledWhenOpen() { selectMenuPath(EDIT_ITEM_5); getGridElement().getHeaderCell(0, 0).click(); diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java index 3582038e61..e7eb78c35e 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java @@ -123,7 +123,6 @@ public abstract class GridEditorTest extends GridBasicFeaturesTest { } protected void assertEditorOpen() { - assertNotNull("Editor is supposed to be open", getEditor()); assertEquals("Unexpected number of widgets", GridBasicFeatures.EDITABLE_COLUMNS, getEditorWidgets().size()); } @@ -133,7 +132,7 @@ public abstract class GridEditorTest extends GridBasicFeaturesTest { } protected List getEditorWidgets() { - assertNotNull(getEditor()); + assertNotNull("Editor is supposed to be open", getEditor()); return getEditor().findElements(By.className("v-textfield")); } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java index 1058fe2d74..08094b57e3 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorUnbufferedTest.java @@ -72,14 +72,32 @@ public class GridEditorUnbufferedTest extends GridEditorTest { String firstFieldValue = getEditorWidgets().get(0) .getAttribute("value"); - assertTrue("Editor is not at correct row index (5)", - "(5, 0)".equals(firstFieldValue)); + assertEquals("Editor should be at row 5", "(5, 0)", firstFieldValue); getGridElement().getCell(10, 0).click(); firstFieldValue = getEditorWidgets().get(0).getAttribute("value"); - assertTrue("Editor is not at correct row index (10)", - "(10, 0)".equals(firstFieldValue)); + assertEquals("Editor should be at row 10", "(10, 0)", firstFieldValue); + } + + @Test + public void testValidationErrorPreventsMove() { + // Because of "out of view" issues, we need to move this for easy access + selectMenuPath("Component", "Columns", "Column 7", "Column 7 Width", + "50px"); + for (int i = 0; i < 6; ++i) { + selectMenuPath("Component", "Columns", "Column 7", "Move left"); + } + + selectMenuPath(EDIT_ITEM_5); + + getEditorWidgets().get(1).click(); + getEditorWidgets().get(1).sendKeys("not a number"); + + getGridElement().getCell(10, 0).click(); + + assertEquals("Editor should not move from row 5", "(5, 0)", + getEditorWidgets().get(0).getAttribute("value")); } @Test @@ -96,7 +114,7 @@ public class GridEditorUnbufferedTest extends GridEditorTest { } @Test - public void testScrollAfterEditByAPI() { + public void testScrollEnabledOnProgrammaticOpen() { int originalScrollPos = getGridVerticalScrollPos(); selectMenuPath(EDIT_ITEM_5); @@ -108,7 +126,7 @@ public class GridEditorUnbufferedTest extends GridEditorTest { } @Test - public void testScrollAfterEditByMouse() { + public void testScrollEnabledOnMouseOpen() { int originalScrollPos = getGridVerticalScrollPos(); GridCellElement cell_5_0 = getGridElement().getCell(5, 0); @@ -121,7 +139,7 @@ public class GridEditorUnbufferedTest extends GridEditorTest { } @Test - public void testScrollAfterEditByKeyboard() { + public void testScrollEnabledOnKeyboardOpen() { int originalScrollPos = getGridVerticalScrollPos(); GridCellElement cell_5_0 = getGridElement().getCell(5, 0); -- cgit v1.2.3 From 9734bc5dfa5d919e3214dc17581d3da3ad1a3ebd Mon Sep 17 00:00:00 2001 From: elmot Date: Tue, 30 Jun 2015 17:40:30 +0300 Subject: Grid sidebar menu design changed. See design document and comments at trac ticket. (#18325) Change-Id: I6686d131f015cf0b7b9a6b43ce43284218d5dd63 --- WebContent/VAADIN/themes/base/grid/grid.scss | 10 ++++++---- .../VAADIN/themes/chameleon/components/components.scss | 2 ++ .../VAADIN/themes/chameleon/components/grid/grid.scss | 12 ++++++++++++ WebContent/VAADIN/themes/reindeer/grid/grid.scss | 6 ++++++ WebContent/VAADIN/themes/runo/grid/grid.scss | 15 +++++++-------- WebContent/VAADIN/themes/valo/components/_grid.scss | 3 --- client/src/com/vaadin/client/widgets/Grid.java | 1 - .../grid/basicfeatures/server/GridSidebarThemeTest.java | 12 ++++++------ 8 files changed, 39 insertions(+), 22 deletions(-) create mode 100644 WebContent/VAADIN/themes/chameleon/components/grid/grid.scss diff --git a/WebContent/VAADIN/themes/base/grid/grid.scss b/WebContent/VAADIN/themes/base/grid/grid.scss index 31403428cd..f587dfef4f 100644 --- a/WebContent/VAADIN/themes/base/grid/grid.scss +++ b/WebContent/VAADIN/themes/base/grid/grid.scss @@ -108,6 +108,7 @@ $v-grid-details-border-bottom-stripe: 1px solid darken($v-grid-row-background-co outline: none; padding: 0 4px; text-align: right; + line-height: 1; &::-moz-focus-inner { border: 0; @@ -128,10 +129,10 @@ $v-grid-details-border-bottom-stripe: 1px solid darken($v-grid-row-background-co &.open { .#{$primaryStyleName}-sidebar-button { width: 100%; - + &:after { - content: "\00d7"; - font-size: 16px; + content: "\f0c9"; + font-size: $v-grid-header-font-size; line-height: 1; } } @@ -142,11 +143,12 @@ $v-grid-details-border-bottom-stripe: 1px solid darken($v-grid-row-background-co } .v-ie8 &.open .#{$primaryStyleName}-sidebar-button:after { + vertical-align: middle; + text-align: center; display: inline; } .#{$primaryStyleName}-sidebar-content { - border-top: $v-grid-border; padding: 4px 0; .gwt-MenuBar { diff --git a/WebContent/VAADIN/themes/chameleon/components/components.scss b/WebContent/VAADIN/themes/chameleon/components/components.scss index 9c8a56b33d..578ea23bf3 100644 --- a/WebContent/VAADIN/themes/chameleon/components/components.scss +++ b/WebContent/VAADIN/themes/chameleon/components/components.scss @@ -1,6 +1,7 @@ @import "accordion/accordion.scss"; @import "button/button.scss"; @import "colorpicker/colorpicker.scss"; +@import "grid/grid.scss"; @import "label/label.scss"; @import "menubar/menubar.scss"; @import "notification/notification.scss"; @@ -24,6 +25,7 @@ @include chameleon-accordion; @include chameleon-button; @include chameleon-colorpicker; + @include chameleon-grid; @include chameleon-label; @include chameleon-menubar; @include chameleon-notification; diff --git a/WebContent/VAADIN/themes/chameleon/components/grid/grid.scss b/WebContent/VAADIN/themes/chameleon/components/grid/grid.scss new file mode 100644 index 0000000000..5007ad6619 --- /dev/null +++ b/WebContent/VAADIN/themes/chameleon/components/grid/grid.scss @@ -0,0 +1,12 @@ +@mixin chameleon-grid($primaryStyleName: v-grid) { + + // Sidebar + .#{$primaryStyleName}-sidebar.v-contextmenu { + + .v-on:before, .v-off:before { + content: none; + font-size: 0; + margin-right: 0; + } + } +} diff --git a/WebContent/VAADIN/themes/reindeer/grid/grid.scss b/WebContent/VAADIN/themes/reindeer/grid/grid.scss index 7ae0f402aa..cb5e9d454e 100644 --- a/WebContent/VAADIN/themes/reindeer/grid/grid.scss +++ b/WebContent/VAADIN/themes/reindeer/grid/grid.scss @@ -40,6 +40,12 @@ .#{$primaryStyleName}-sidebar-content { background-color: #f8f8f9; } + + .v-on:before, .v-off:before { + content: none; + font-size: 0; + margin-right: 0; + } } // Sort indicators diff --git a/WebContent/VAADIN/themes/runo/grid/grid.scss b/WebContent/VAADIN/themes/runo/grid/grid.scss index aca9821c53..1f049c5fb0 100644 --- a/WebContent/VAADIN/themes/runo/grid/grid.scss +++ b/WebContent/VAADIN/themes/runo/grid/grid.scss @@ -30,14 +30,7 @@ // Sidebar .#{$primaryStyleName}-sidebar.v-contextmenu { - &.open { - .#{$primaryStyleName}-sidebar-button { - &:after { - font-size: 22px; - } - } - } - + .#{$primaryStyleName}-sidebar-content { background-color: transparent; @@ -45,6 +38,12 @@ border: none; } } + + .v-on:before, .v-off:before { + content: none; + font-size: 0; + margin-right: 0; + } } // Sort indicators diff --git a/WebContent/VAADIN/themes/valo/components/_grid.scss b/WebContent/VAADIN/themes/valo/components/_grid.scss index 27d421b9f2..d00ddf30a4 100644 --- a/WebContent/VAADIN/themes/valo/components/_grid.scss +++ b/WebContent/VAADIN/themes/valo/components/_grid.scss @@ -203,9 +203,6 @@ $v-grid-details-border-bottom-stripe: $v-grid-cell-horizontal-border !default; // Sidebar .#{$primary-stylename}-sidebar.v-contextmenu { &.open { - .#{$primary-stylename}-sidebar-button:after { - font-size: 20px; - } .#{$primary-stylename}-sidebar-content { margin: 0 0 2px; diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 232d67c1d4..377943ed61 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -3248,7 +3248,6 @@ public class Grid extends ResizeComposite implements clickOutsideToCloseHandlerRegistration = Event .addNativePreviewHandler(clickOutsideToCloseHandler); } - openCloseButton.setHeight(""); } /** diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSidebarThemeTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSidebarThemeTest.java index 0e5dd32989..238b470feb 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSidebarThemeTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSidebarThemeTest.java @@ -45,15 +45,15 @@ public class GridSidebarThemeTest extends GridBasicFeaturesTest { private void runTestSequence(String theme) throws IOException { openTestURL("theme=" + theme); - compareScreen(theme + "_SidebarClosed"); + compareScreen(theme + "-SidebarClosed"); getSidebarOpenButton().click(); - compareScreen(theme + "_SidebarOpen"); + compareScreen(theme + "-SidebarOpen"); new Actions(getDriver()).moveToElement(getColumnHidingToggle(2), 5, 5) .perform(); - compareScreen(theme + "_OnMouseOverNotHiddenToggle"); + compareScreen(theme + "-OnMouseOverNotHiddenToggle"); getColumnHidingToggle(2).click(); getColumnHidingToggle(3).click(); @@ -63,17 +63,17 @@ public class GridSidebarThemeTest extends GridBasicFeaturesTest { .perform(); ; - compareScreen(theme + "_TogglesTriggered"); + compareScreen(theme + "-TogglesTriggered"); new Actions(getDriver()).moveToElement(getColumnHidingToggle(2)) .perform(); ; - compareScreen(theme + "_OnMouseOverHiddenToggle"); + compareScreen(theme + "-OnMouseOverHiddenToggle"); getSidebarOpenButton().click(); - compareScreen(theme + "_SidebarClosed2"); + compareScreen(theme + "-SidebarClosed2"); } @Override -- cgit v1.2.3 From 80058d9429940c376c63c086b1cf79848fe1a699 Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Thu, 2 Jul 2015 16:37:01 +0300 Subject: Add row and cell description generators to Grid (#18481) Change-Id: I940399d986eb6970df687880645fafc157dab432 --- .../vaadin/client/connectors/GridConnector.java | 40 ++++ client/src/com/vaadin/client/widgets/Grid.java | 22 +++ server/src/com/vaadin/ui/Grid.java | 217 +++++++++++++++++---- .../src/com/vaadin/shared/ui/grid/GridState.java | 17 ++ .../grid/basicfeatures/GridBasicFeatures.java | 43 ++++ .../GridDescriptionGeneratorTest.java | 74 +++++++ 6 files changed, 380 insertions(+), 33 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridDescriptionGeneratorTest.java diff --git a/client/src/com/vaadin/client/connectors/GridConnector.java b/client/src/com/vaadin/client/connectors/GridConnector.java index d42041670e..3c83fb2c24 100644 --- a/client/src/com/vaadin/client/connectors/GridConnector.java +++ b/client/src/com/vaadin/client/connectors/GridConnector.java @@ -31,6 +31,7 @@ import java.util.logging.Logger; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; +import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.Widget; @@ -38,6 +39,7 @@ import com.vaadin.client.ComponentConnector; import com.vaadin.client.ConnectorHierarchyChangeEvent; import com.vaadin.client.DeferredWorker; import com.vaadin.client.MouseEventDetailsBuilder; +import com.vaadin.client.TooltipInfo; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.connectors.RpcDataSourceConnector.DetailsListener; import com.vaadin.client.connectors.RpcDataSourceConnector.RpcDataSource; @@ -1456,4 +1458,42 @@ public class GridConnector extends AbstractHasComponentsConnector implements public DetailsListener getDetailsListener() { return detailsListener; } + + @Override + public boolean hasTooltip() { + return getState().hasDescriptions || super.hasTooltip(); + } + + @Override + public TooltipInfo getTooltipInfo(Element element) { + CellReference cell = getWidget().getCellReference(element); + + if (cell != null) { + JsonObject row = cell.getRow(); + if (row == null) { + return null; + } + + Column column = cell.getColumn(); + if (!(column instanceof CustomGridColumn)) { + // Selection checkbox column + return null; + } + CustomGridColumn c = (CustomGridColumn) column; + + JsonObject cellDescriptions = row + .getObject(GridState.JSONKEY_CELLDESCRIPTION); + + if (cellDescriptions != null && cellDescriptions.hasKey(c.id)) { + return new TooltipInfo(cellDescriptions.getString(c.id)); + } else if (row.hasKey(GridState.JSONKEY_ROWDESCRIPTION)) { + return new TooltipInfo( + row.getString(GridState.JSONKEY_ROWDESCRIPTION)); + } else { + return null; + } + } + + return super.getTooltipInfo(element); + } } diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 0555df3c1f..cf05e7e53a 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -8173,4 +8173,26 @@ public class Grid extends ResizeComposite implements public EventCellReference getEventCell() { return eventCell; } + + /** + * Returns a CellReference for the cell to which the given element belongs + * to. + * + * @since + * @param element + * Element to find from the cell's content. + * @return CellReference or null if cell was not found. + */ + public CellReference getCellReference(Element element) { + RowContainer container = getEscalator().findRowContainer(element); + if (container != null) { + Cell cell = container.getCell(element); + if (cell != null) { + EventCellReference cellRef = new EventCellReference(this); + cellRef.set(cell, getSectionFromContainer(container)); + return cellRef; + } + } + return null; + } } diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java index f025b6e1c0..ab4236fdf0 100644 --- a/server/src/com/vaadin/ui/Grid.java +++ b/server/src/com/vaadin/ui/Grid.java @@ -1514,39 +1514,88 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, } /** - * Callback interface for generating custom style names for data rows + * A callback interface for generating custom style names for Grid rows. * * @see Grid#setRowStyleGenerator(RowStyleGenerator) */ public interface RowStyleGenerator extends Serializable { /** - * Called by Grid to generate a style name for a row + * Called by Grid to generate a style name for a row. * - * @param rowReference - * The row to generate a style for + * @param row + * the row to generate a style for * @return the style name to add to this row, or {@code null} to not set * any style */ - public String getStyle(RowReference rowReference); + public String getStyle(RowReference row); } /** - * Callback interface for generating custom style names for cells + * A callback interface for generating custom style names for Grid cells. * * @see Grid#setCellStyleGenerator(CellStyleGenerator) */ public interface CellStyleGenerator extends Serializable { /** - * Called by Grid to generate a style name for a column + * Called by Grid to generate a style name for a column. * - * @param cellReference - * The cell to generate a style for + * @param cell + * the cell to generate a style for * @return the style name to add to this cell, or {@code null} to not * set any style */ - public String getStyle(CellReference cellReference); + public String getStyle(CellReference cell); + } + + /** + * A callback interface for generating optional descriptions (tooltips) for + * Grid rows. If a description is generated for a row, it is used for all + * the cells in the row for which a {@link CellDescriptionGenerator cell + * description} is not generated. + * + * @see Grid#setRowDescriptionGenerator(CellDescriptionGenerator) + * + * @since + */ + public interface RowDescriptionGenerator extends Serializable { + + /** + * Called by Grid to generate a description (tooltip) for a row. The + * description may contain HTML which is rendered directly; if this is + * not desired the returned string must be escaped by the implementing + * method. + * + * @param row + * the row to generate a description for + * @return the row description or {@code null} for no description + */ + public String getDescription(RowReference row); + } + + /** + * A callback interface for generating optional descriptions (tooltips) for + * Grid cells. If a cell has both a {@link RowDescriptionGenerator row + * description} and a cell description, the latter has precedence. + * + * @see Grid#setCellDescriptionGenerator(CellDescriptionGenerator) + * + * @since + */ + public interface CellDescriptionGenerator extends Serializable { + + /** + * Called by Grid to generate a description (tooltip) for a cell. The + * description may contain HTML which is rendered directly; if this is + * not desired the returned string must be escaped by the implementing + * method. + * + * @param cell + * the cell to generate a description for + * @return the cell description or {@code null} for no description + */ + public String getDescription(CellReference cell); } /** @@ -1555,51 +1604,83 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, */ private class RowDataGenerator implements DataGenerator { + private void put(String key, String value, JsonObject object) { + if (value != null && !value.isEmpty()) { + object.put(key, value); + } + } + @Override public void generateData(Object itemId, Item item, JsonObject rowData) { - RowReference r = new RowReference(Grid.this); - r.set(itemId); + RowReference row = new RowReference(Grid.this); + row.set(itemId); if (rowStyleGenerator != null) { - String style = rowStyleGenerator.getStyle(r); - if (style != null && !style.isEmpty()) { - rowData.put(GridState.JSONKEY_ROWSTYLE, style); - } + String style = rowStyleGenerator.getStyle(row); + put(GridState.JSONKEY_ROWSTYLE, style, rowData); + } + + if (rowDescriptionGenerator != null) { + String description = rowDescriptionGenerator + .getDescription(row); + put(GridState.JSONKEY_ROWDESCRIPTION, description, rowData); + } JsonObject cellStyles = Json.createObject(); JsonObject cellData = Json.createObject(); - for (Column column : getColumns()) { - Object propertyId = column.getPropertyId(); - String columnId = columnKeys.key(propertyId); + JsonObject cellDescriptions = Json.createObject(); - cellData.put(columnId, getRendererData(column, item)); + CellReference cell = new CellReference(row); - if (cellStyleGenerator != null) { - CellReference c = new CellReference(r); - c.set(propertyId); + for (Column column : getColumns()) { + cell.set(column.getPropertyId()); - String style = cellStyleGenerator.getStyle(c); - if (style != null && !style.isEmpty()) { - cellStyles.put(columnId, style); - } - } + writeData(cell, cellData); + writeStyles(cell, cellStyles); + writeDescriptions(cell, cellDescriptions); + } + + if (cellDescriptionGenerator != null + && cellDescriptions.keys().length > 0) { + rowData.put(GridState.JSONKEY_CELLDESCRIPTION, cellDescriptions); } if (cellStyleGenerator != null && cellStyles.keys().length > 0) { rowData.put(GridState.JSONKEY_CELLSTYLES, cellStyles); } + rowData.put(GridState.JSONKEY_DATA, cellData); } - private JsonValue getRendererData(Column column, Item item) { + private void writeStyles(CellReference cell, JsonObject styles) { + if (cellStyleGenerator != null) { + String style = cellStyleGenerator.getStyle(cell); + put(columnKeys.key(cell.getPropertyId()), style, styles); + } + } + + private void writeDescriptions(CellReference cell, + JsonObject descriptions) { + if (cellDescriptionGenerator != null) { + String description = cellDescriptionGenerator + .getDescription(cell); + put(columnKeys.key(cell.getPropertyId()), description, + descriptions); + } + } + + private void writeData(CellReference cell, JsonObject data) { + Column column = getColumn(cell.getPropertyId()); Converter converter = column.getConverter(); - Object propertyId = column.getPropertyId(); - Object modelValue = item.getItemProperty(propertyId).getValue(); Renderer renderer = column.getRenderer(); - return AbstractRenderer.encodeValue(modelValue, renderer, - converter, getLocale()); + Item item = cell.getItem(); + Object modelValue = item.getItemProperty(cell.getPropertyId()) + .getValue(); + + data.put(columnKeys.key(cell.getPropertyId()), AbstractRenderer + .encodeValue(modelValue, renderer, converter, getLocale())); } } @@ -3781,6 +3862,9 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, private CellStyleGenerator cellStyleGenerator; private RowStyleGenerator rowStyleGenerator; + private CellDescriptionGenerator cellDescriptionGenerator; + private RowDescriptionGenerator rowDescriptionGenerator; + /** * true if Grid is using the internal IndexedContainer created * in Grid() constructor, or false if the user has set their @@ -5759,6 +5843,73 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, return getRpcProxy(EditorClientRpc.class); } + /** + * Sets the {@code CellDescriptionGenerator} instance for generating + * optional descriptions (tooltips) for individual Grid cells. If a + * {@link RowDescriptionGenerator} is also set, the row description it + * generates is displayed for cells for which {@code generator} returns + * null. + * + * @param generator + * the description generator to use or {@code null} to remove a + * previously set generator if any + * + * @see #setRowDescriptionGenerator(RowDescriptionGenerator) + * + * @since + */ + public void setCellDescriptionGenerator(CellDescriptionGenerator generator) { + cellDescriptionGenerator = generator; + getState().hasDescriptions = (generator != null || rowDescriptionGenerator != null); + datasourceExtension.refreshCache(); + } + + /** + * Returns the {@code CellDescriptionGenerator} instance used to generate + * descriptions (tooltips) for Grid cells. + * + * @return the description generator or {@code null} if no generator is set + * + * @since + */ + public CellDescriptionGenerator getCellDescriptionGenerator() { + return cellDescriptionGenerator; + } + + /** + * Sets the {@code RowDescriptionGenerator} instance for generating optional + * descriptions (tooltips) for Grid rows. If a + * {@link CellDescriptionGenerator} is also set, the row description + * generated by {@code generator} is used for cells for which the cell + * description generator returns null. + * + * + * @param generator + * the description generator to use or {@code null} to remove a + * previously set generator if any + * + * @see #setCellDescriptionGenerator(CellDescriptionGenerator) + * + * @since + */ + public void setRowDescriptionGenerator(RowDescriptionGenerator generator) { + rowDescriptionGenerator = generator; + getState().hasDescriptions = (generator != null || cellDescriptionGenerator != null); + datasourceExtension.refreshCache(); + } + + /** + * Returns the {@code RowDescriptionGenerator} instance used to generate + * descriptions (tooltips) for Grid rows + * + * @return the description generator or {@code} null if no generator is set + * + * @since + */ + public RowDescriptionGenerator getRowDescriptionGenerator() { + return rowDescriptionGenerator; + } + /** * Sets the style generator that is used for generating styles for cells * diff --git a/shared/src/com/vaadin/shared/ui/grid/GridState.java b/shared/src/com/vaadin/shared/ui/grid/GridState.java index c455ffe23b..0d0a5d3e9f 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridState.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridState.java @@ -102,6 +102,20 @@ public class GridState extends TabIndexState { */ public static final String JSONKEY_CELLSTYLES = "cs"; + /** + * The key in which a row's description can be found + * + * @see com.vaadin.shared.data.DataProviderRpc#setRowData(int, String) + */ + public static final String JSONKEY_ROWDESCRIPTION = "rd"; + + /** + * The key in which a cell's description can be found + * + * @see com.vaadin.shared.data.DataProviderRpc#setRowData(int, String) + */ + public static final String JSONKEY_CELLDESCRIPTION = "cd"; + /** * The key that tells whether details are visible for the row. * @@ -160,6 +174,9 @@ public class GridState extends TabIndexState { @DelegateToWidget public boolean editorBuffered = true; + /** Whether rows and/or cells have generated descriptions (tooltips) */ + public boolean hasDescriptions; + /** The caption for the save button in the editor */ @DelegateToWidget public String editorSaveCaption = GridConstants.DEFAULT_SAVE_CAPTION; diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index 3154fd2a85..33a54b1c9a 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -52,6 +52,7 @@ import com.vaadin.ui.Component; import com.vaadin.ui.CssLayout; import com.vaadin.ui.Field; import com.vaadin.ui.Grid; +import com.vaadin.ui.Grid.CellDescriptionGenerator; import com.vaadin.ui.Grid.CellReference; import com.vaadin.ui.Grid.CellStyleGenerator; import com.vaadin.ui.Grid.Column; @@ -68,6 +69,7 @@ import com.vaadin.ui.Grid.FooterCell; import com.vaadin.ui.Grid.HeaderCell; import com.vaadin.ui.Grid.HeaderRow; import com.vaadin.ui.Grid.MultiSelectionModel; +import com.vaadin.ui.Grid.RowDescriptionGenerator; import com.vaadin.ui.Grid.RowReference; import com.vaadin.ui.Grid.RowStyleGenerator; import com.vaadin.ui.Grid.SelectionMode; @@ -130,6 +132,27 @@ public class GridBasicFeatures extends AbstractComponentTest { } }; + private RowDescriptionGenerator rowDescriptionGenerator = new RowDescriptionGenerator() { + + @Override + public String getDescription(RowReference row) { + return "Row tooltip for row " + row.getItemId(); + } + }; + + private CellDescriptionGenerator cellDescriptionGenerator = new CellDescriptionGenerator() { + + @Override + public String getDescription(CellReference cell) { + if ("Column 0".equals(cell.getPropertyId())) { + return "Cell tooltip for row " + cell.getItemId() + + ", column 0"; + } else { + return null; + } + } + }; + private ItemClickListener editorOpeningItemClickListener = new ItemClickListener() { @Override @@ -629,6 +652,25 @@ public class GridBasicFeatures extends AbstractComponentTest { } }); + createBooleanAction("Row description generator", "State", false, + new Command() { + + @Override + public void execute(Grid c, Boolean value, Object data) { + c.setRowDescriptionGenerator(value ? rowDescriptionGenerator + : null); + } + }); + + createBooleanAction("Cell description generator", "State", false, + new Command() { + @Override + public void execute(Grid c, Boolean value, Object data) { + c.setCellDescriptionGenerator(value ? cellDescriptionGenerator + : null); + } + }); + LinkedHashMap frozenOptions = new LinkedHashMap(); for (int i = -1; i <= COLUMNS; i++) { frozenOptions.put(String.valueOf(i), Integer.valueOf(i)); @@ -673,6 +715,7 @@ public class GridBasicFeatures extends AbstractComponentTest { } }); + createBooleanAction("EditorOpeningItemClickListener", "State", false, new Command() { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridDescriptionGeneratorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridDescriptionGeneratorTest.java new file mode 100644 index 0000000000..ed712361a6 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridDescriptionGeneratorTest.java @@ -0,0 +1,74 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.grid.basicfeatures; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.openqa.selenium.By; + +public class GridDescriptionGeneratorTest extends GridBasicFeaturesTest { + + @Test + public void testCellDescription() { + openTestURL(); + selectMenuPath("Component", "State", "Cell description generator"); + + getGridElement().getCell(1, 0).showTooltip(); + String tooltipText = findElement(By.className("v-tooltip-text")) + .getText(); + assertEquals("Tooltip text", "Cell tooltip for row 1, column 0", + tooltipText); + + getGridElement().getCell(1, 1).showTooltip(); + assertTrue("Tooltip should not be present in cell (1, 1) ", + findElement(By.className("v-tooltip-text")).getText().isEmpty()); + } + + @Test + public void testRowDescription() { + openTestURL(); + selectMenuPath("Component", "State", "Row description generator"); + + getGridElement().getCell(5, 3).showTooltip(); + String tooltipText = findElement(By.className("v-tooltip-text")) + .getText(); + assertEquals("Tooltip text", "Row tooltip for row 5", tooltipText); + + getGridElement().getCell(15, 3).showTooltip(); + tooltipText = findElement(By.className("v-tooltip-text")).getText(); + assertEquals("Tooltip text", "Row tooltip for row 15", tooltipText); + } + + @Test + public void testRowAndCellDescription() { + openTestURL(); + selectMenuPath("Component", "State", "Row description generator"); + selectMenuPath("Component", "State", "Cell description generator"); + + getGridElement().getCell(5, 0).showTooltip(); + String tooltipText = findElement(By.className("v-tooltip-text")) + .getText(); + assertEquals("Tooltip text", "Cell tooltip for row 5, column 0", + tooltipText); + + getGridElement().getCell(5, 3).showTooltip(); + tooltipText = findElement(By.className("v-tooltip-text")).getText(); + assertEquals("Tooltip text", "Row tooltip for row 5", tooltipText); + } + +} -- cgit v1.2.3 From 4c25c54d43a79a4c7d9ce315dd8d59c82d3a0ec2 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Wed, 15 Jul 2015 18:38:46 +0300 Subject: Add missing import to staging report generator Change-Id: I2ceaac45b34b69a7dddaab4d60f2f0f7db1c5602 --- scripts/GenerateStagingReport.py | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/GenerateStagingReport.py b/scripts/GenerateStagingReport.py index 7c2aeda9e0..cf53928379 100644 --- a/scripts/GenerateStagingReport.py +++ b/scripts/GenerateStagingReport.py @@ -1,6 +1,7 @@ #coding=UTF-8 from BuildArchetypes import archetypes, getDeploymentContext +from BuildDemos import demos import argparse, cgi parser = argparse.ArgumentParser(description="Build report generator") -- cgit v1.2.3 From 546616b0667441997f5537c175c281e5f841effb Mon Sep 17 00:00:00 2001 From: Sauli Tähkäpää Date: Thu, 9 Jul 2015 13:27:49 +0300 Subject: Select last item only if filtered items exist. (#18441) Change-Id: I1b601f7bcddd3a62edcd97651a3270b79dacc7fd --- client/src/com/vaadin/client/ui/VFilterSelect.java | 4 ++- .../ComboBoxEmptyItemsKeyboardNavigation.java | 15 +++++++++++ .../ComboBoxEmptyItemsKeyboardNavigationTest.java | 30 ++++++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 uitest/src/com/vaadin/tests/components/combobox/ComboBoxEmptyItemsKeyboardNavigation.java create mode 100644 uitest/src/com/vaadin/tests/components/combobox/ComboBoxEmptyItemsKeyboardNavigationTest.java diff --git a/client/src/com/vaadin/client/ui/VFilterSelect.java b/client/src/com/vaadin/client/ui/VFilterSelect.java index 7951759fa2..1e474d3a1f 100644 --- a/client/src/com/vaadin/client/ui/VFilterSelect.java +++ b/client/src/com/vaadin/client/ui/VFilterSelect.java @@ -417,7 +417,9 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, selectPrevPage(); } else { - selectItem(menu.getItems().get(menu.getItems().size() - 1)); + if(!menu.getItems().isEmpty()) { + selectLastItem(); + } } } diff --git a/uitest/src/com/vaadin/tests/components/combobox/ComboBoxEmptyItemsKeyboardNavigation.java b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxEmptyItemsKeyboardNavigation.java new file mode 100644 index 0000000000..2f96724db1 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxEmptyItemsKeyboardNavigation.java @@ -0,0 +1,15 @@ +package com.vaadin.tests.components.combobox; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.ComboBox; + +public class ComboBoxEmptyItemsKeyboardNavigation extends AbstractTestUI { + @Override + protected void setup(VaadinRequest request) { + ComboBox comboBox = new ComboBox(); + comboBox.addItems("foo", "bar"); + + addComponent(comboBox); + } +} diff --git a/uitest/src/com/vaadin/tests/components/combobox/ComboBoxEmptyItemsKeyboardNavigationTest.java b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxEmptyItemsKeyboardNavigationTest.java new file mode 100644 index 0000000000..c5cbc5eea6 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxEmptyItemsKeyboardNavigationTest.java @@ -0,0 +1,30 @@ +package com.vaadin.tests.components.combobox; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.collection.IsEmptyCollection.empty; + +import java.util.List; + +import org.junit.Test; +import org.openqa.selenium.Keys; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.By; +import com.vaadin.tests.tb3.MultiBrowserTest; +import com.vaadin.tests.tb3.newelements.ComboBoxElement; + +public class ComboBoxEmptyItemsKeyboardNavigationTest extends MultiBrowserTest { + + @Test + public void navigatingUpOnAnEmptyMenuDoesntThrowErrors() { + setDebug(true); + openTestURL(); + + ComboBoxElement combobox = $(ComboBoxElement.class).first(); + combobox.sendKeys("a", Keys.ARROW_UP); + + List errors = findElements(By.className("SEVERE")); + + assertThat(errors, empty()); + } +} \ No newline at end of file -- cgit v1.2.3 From 0a7a9e87ef95511c0e54d128be573c83124898e7 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Sat, 11 Jul 2015 01:48:50 +0300 Subject: Workaround for IE10 invalid min-height calculations (#15169) Change-Id: I22b0e56549c19432626dea8c2dd43509c07c0de4 --- client/src/com/vaadin/client/ui/VScrollTable.java | 6 +++ .../table/TableColumnWidthsAndSorting.java | 50 +++++++++++++++++++++ .../table/TableColumnWidthsAndSortingTest.java | 52 ++++++++++++++++++++++ 3 files changed, 108 insertions(+) create mode 100644 uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndSorting.java create mode 100644 uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndSortingTest.java diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java index 6bb3199b08..e036725ceb 100644 --- a/client/src/com/vaadin/client/ui/VScrollTable.java +++ b/client/src/com/vaadin/client/ui/VScrollTable.java @@ -3628,6 +3628,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets, } } else { c.setText(caption); + if (BrowserInfo.get().isIE10()) { + // IE10 can some times define min-height to include + // padding when setting the text... + // See https://dev.vaadin.com/ticket/15169 + WidgetUtil.forceIERedraw(c.getElement()); + } } c.setSorted(false); diff --git a/uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndSorting.java b/uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndSorting.java new file mode 100644 index 0000000000..8f0a8803f3 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndSorting.java @@ -0,0 +1,50 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.table; + +import com.vaadin.annotations.Theme; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.tests.fieldgroup.ComplexPerson; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.Table; + +@Theme("valo") +public class TableColumnWidthsAndSorting extends AbstractTestUIWithLog { + + @Override + protected void setup(VaadinRequest request) { + final Table t = new Table(); + t.setContainerDataSource(ComplexPerson.createContainer(100)); + t.setVisibleColumns("firstName", "lastName", "age", "gender", "salary"); + t.setColumnWidth("firstName", 200); + t.setColumnWidth("lastName", 200); + t.setSelectable(true); + addComponent(t); + + Button b = new Button("Sort according to gender", new ClickListener() { + + @Override + public void buttonClick(ClickEvent event) { + t.sort(new Object[] { "gender" }, new boolean[] { true }); + } + }); + + addComponent(b); + } +} diff --git a/uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndSortingTest.java b/uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndSortingTest.java new file mode 100644 index 0000000000..9c49b3d0b6 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/TableColumnWidthsAndSortingTest.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.table; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.testbench.elements.TableElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class TableColumnWidthsAndSortingTest extends MultiBrowserTest { + + @Test + public void testHeaderHeight() { + openTestURL(); + TableElement t = $(TableElement.class).first(); + + assertHeaderCellHeight(t); + + // Sort according to age + t.getHeaderCell(2).click(); + assertHeaderCellHeight(t); + + // Sort again according to age + t.getHeaderCell(2).click(); + assertHeaderCellHeight(t); + + } + + private void assertHeaderCellHeight(TableElement t) { + // Assert all headers are correct height (37px according to default + // Valo) + for (int i = 0; i < 5; i++) { + Assert.assertEquals("Height of header cell " + i + " is wrong", 37, + t.getHeaderCell(0).getSize().getHeight()); + } + + } +} -- cgit v1.2.3 From debb65e46c9b1f8628878ad2232502bf58f260de Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Thu, 16 Jul 2015 16:23:38 +0300 Subject: Fix IE8 window shadows with undefined height (#18487) Change-Id: Ia6b937749c318e9048c2dd34f3f892b44f384d25 --- client/src/com/vaadin/client/ui/VOverlay.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/client/src/com/vaadin/client/ui/VOverlay.java b/client/src/com/vaadin/client/ui/VOverlay.java index 3649afc74f..e823e8ee80 100644 --- a/client/src/com/vaadin/client/ui/VOverlay.java +++ b/client/src/com/vaadin/client/ui/VOverlay.java @@ -22,6 +22,8 @@ import java.util.logging.Logger; import com.google.gwt.animation.client.Animation; import com.google.gwt.aria.client.Roles; import com.google.gwt.core.client.JavaScriptObject; +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.IFrameElement; @@ -471,7 +473,17 @@ public class VOverlay extends PopupPanel implements CloseHandler { if (isAnimationEnabled()) { new ResizeAnimation().run(POPUP_PANEL_ANIMATION_DURATION); } else { - positionOrSizeUpdated(1.0); + if (BrowserInfo.get().isIE8()) { + Scheduler.get().scheduleFinally(new ScheduledCommand() { + + @Override + public void execute() { + positionOrSizeUpdated(1.0); + } + }); + } else { + positionOrSizeUpdated(1.0); + } } current = null; } -- cgit v1.2.3 From 1c463a0229c408cb627da5dbee4660d4a5e50217 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Thu, 16 Jul 2015 17:31:54 +0300 Subject: Fix IE8 icons in tree expand regression (#18488) Change-Id: I6b7ee8776818e59a1607f55a93344209a2dfecc2 --- client/src/com/vaadin/client/ui/VTree.java | 15 +++++++++++++-- client/src/com/vaadin/client/ui/tree/TreeConnector.java | 6 +++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/client/src/com/vaadin/client/ui/VTree.java b/client/src/com/vaadin/client/ui/VTree.java index 8729de4a43..846b16d0cb 100644 --- a/client/src/com/vaadin/client/ui/VTree.java +++ b/client/src/com/vaadin/client/ui/VTree.java @@ -179,7 +179,7 @@ public class VTree extends FocusElementPanel implements VHasDropHandler, @Override public void execute() { - Util.notifyParentOfSizeChange(VTree.this, true); + doLayout(); } }); @@ -969,7 +969,7 @@ public class VTree extends FocusElementPanel implements VHasDropHandler, open = state; if (!rendering) { - Util.notifyParentOfSizeChange(VTree.this, false); + doLayout(); } } @@ -2239,4 +2239,15 @@ public class VTree extends FocusElementPanel implements VHasDropHandler, com.google.gwt.user.client.Element captionElement) { AriaHelper.bindCaption(body, captionElement); } + + /** + * Tell LayoutManager that a layout is needed later for this VTree + */ + private void doLayout() { + // IE8 needs a hack to measure the tree again after update + WidgetUtil.forceIE8Redraw(getElement()); + + // This calls LayoutManager setNeedsMeasure and layoutNow + Util.notifyParentOfSizeChange(this, false); + } } diff --git a/client/src/com/vaadin/client/ui/tree/TreeConnector.java b/client/src/com/vaadin/client/ui/tree/TreeConnector.java index fc3e6ca0fc..23091d0ad5 100644 --- a/client/src/com/vaadin/client/ui/tree/TreeConnector.java +++ b/client/src/com/vaadin/client/ui/tree/TreeConnector.java @@ -27,8 +27,8 @@ import com.vaadin.client.BrowserInfo; import com.vaadin.client.Paintable; import com.vaadin.client.TooltipInfo; import com.vaadin.client.UIDL; -import com.vaadin.client.WidgetUtil; import com.vaadin.client.VConsole; +import com.vaadin.client.WidgetUtil; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.ui.AbstractComponentConnector; import com.vaadin.client.ui.VTree; @@ -62,6 +62,10 @@ public class TreeConnector extends AbstractComponentConnector implements if (uidl.hasAttribute("partialUpdate")) { handleUpdate(uidl); + + // IE8 needs a hack to measure the tree again after update + WidgetUtil.forceIE8Redraw(getWidget().getElement()); + getWidget().rendering = false; return; } -- cgit v1.2.3 From 23abf1d905eca80ad36e20d2de13203b98e23ac7 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Thu, 16 Jul 2015 18:04:20 +0300 Subject: Stabilize Grid tests on IE11 Change-Id: I1e16dfe54a369c5ed18dedd8755ff479bc1617a1 --- .../tests/components/grid/basicfeatures/GridColumnHidingTest.java | 5 ++++- .../grid/basicfeatures/client/GridDetailsClientTest.java | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnHidingTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnHidingTest.java index a307aaca16..0717cd84d0 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnHidingTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridColumnHidingTest.java @@ -870,7 +870,10 @@ public class GridColumnHidingTest extends GridBasicClientFeaturesTest { selectMenuPath("Component", "Columns", "Column 0", "Hidable"); getSidebarOpenButton().click(); verifySidebarOpened(); - findElement(By.className("v-app")).click(); + // Click somewhere far from Grid. + new Actions(getDriver()) + .moveToElement(findElement(By.className("v-app")), 600, 600) + .click().perform(); verifySidebarClosed(); } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridDetailsClientTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridDetailsClientTest.java index 88158c7f6f..1e4b8a0062 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridDetailsClientTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridDetailsClientTest.java @@ -35,8 +35,8 @@ import com.vaadin.shared.ui.grid.ScrollDestination; import com.vaadin.testbench.By; import com.vaadin.testbench.ElementQuery; import com.vaadin.testbench.TestBenchElement; -import com.vaadin.testbench.elements.NotificationElement; import com.vaadin.tests.components.grid.basicfeatures.GridBasicClientFeaturesTest; +import com.vaadin.tests.tb3.newelements.FixedNotificationElement; public class GridDetailsClientTest extends GridBasicClientFeaturesTest { @@ -112,12 +112,12 @@ public class GridDetailsClientTest extends GridBasicClientFeaturesTest { @Test public void errorUpdaterShowsErrorNotification() { assertFalse("No notifications should've been at the start", - $(NotificationElement.class).exists()); + $(FixedNotificationElement.class).exists()); toggleDetailsFor(1); selectMenuPath(SET_FAULTY_GENERATOR); - ElementQuery notification = $(NotificationElement.class); + ElementQuery notification = $(FixedNotificationElement.class); assertTrue("Was expecting an error notification here", notification.exists()); notification.first().close(); @@ -131,7 +131,7 @@ public class GridDetailsClientTest extends GridBasicClientFeaturesTest { toggleDetailsFor(1); selectMenuPath(SET_FAULTY_GENERATOR); - $(NotificationElement.class).first().close(); + $(FixedNotificationElement.class).first().close(); selectMenuPath(SET_GENERATOR); assertNotEquals( -- cgit v1.2.3 From 929adacf733d5e685925f143061db7d0450d7b03 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Fri, 17 Jul 2015 11:52:17 +0300 Subject: Convert ComboBoxLargeIconsTest from TB2 to TB4 This patch also adds some subpart awareness as well as deferred worker interface to VFilterSelect to support running TB4 tests reliably. Change-Id: I41f2af38f7eba2194aa49c8d7a0d13073166cddf --- client/src/com/vaadin/client/ui/VFilterSelect.java | 21 ++- .../combobox/ComboBoxLargeIconsTest.java | 58 ++++++++ .../components/combobox/ComboBoxLargeIcons.html | 152 --------------------- 3 files changed, 74 insertions(+), 157 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/combobox/ComboBoxLargeIconsTest.java delete mode 100644 uitest/tb2/com/vaadin/tests/components/combobox/ComboBoxLargeIcons.html diff --git a/client/src/com/vaadin/client/ui/VFilterSelect.java b/client/src/com/vaadin/client/ui/VFilterSelect.java index 1e474d3a1f..8d9e30ac6e 100644 --- a/client/src/com/vaadin/client/ui/VFilterSelect.java +++ b/client/src/com/vaadin/client/ui/VFilterSelect.java @@ -65,6 +65,7 @@ import com.vaadin.client.BrowserInfo; import com.vaadin.client.ComponentConnector; import com.vaadin.client.ComputedStyle; import com.vaadin.client.ConnectorMap; +import com.vaadin.client.DeferredWorker; import com.vaadin.client.Focusable; import com.vaadin.client.UIDL; import com.vaadin.client.VConsole; @@ -90,7 +91,7 @@ import com.vaadin.shared.util.SharedUtil; public class VFilterSelect extends Composite implements Field, KeyDownHandler, KeyUpHandler, ClickHandler, FocusHandler, BlurHandler, Focusable, SubPartAware, HandlesAriaCaption, HandlesAriaInvalid, - HandlesAriaRequired { + HandlesAriaRequired, DeferredWorker { /** * Represents a suggestion in the suggestion popup box @@ -417,7 +418,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, selectPrevPage(); } else { - if(!menu.getItems().isEmpty()) { + if (!menu.getItems().isEmpty()) { selectLastItem(); } } @@ -2187,11 +2188,15 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, @Override public com.google.gwt.user.client.Element getSubPartElement(String subPart) { - if ("textbox".equals(subPart)) { + String[] parts = subPart.split("/"); + if ("textbox".equals(parts[0])) { return tb.getElement(); - } else if ("button".equals(subPart)) { + } else if ("button".equals(parts[0])) { return popupOpener.getElement(); - } else if ("popup".equals(subPart) && suggestionPopup.isAttached()) { + } else if ("popup".equals(parts[0]) && suggestionPopup.isAttached()) { + if (parts.length == 2) { + return suggestionPopup.menu.getSubPartElement(parts[1]); + } return suggestionPopup.getElement(); } return null; @@ -2235,4 +2240,10 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, selectPopupItemWhenResponseIsReceived = Select.NONE; } + @Override + public boolean isWorkPending() { + return waitingForFilteringResponse + || suggestionPopup.lazyPageScroller.isRunning(); + } + } diff --git a/uitest/src/com/vaadin/tests/components/combobox/ComboBoxLargeIconsTest.java b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxLargeIconsTest.java new file mode 100644 index 0000000000..407ab7aa04 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/combobox/ComboBoxLargeIconsTest.java @@ -0,0 +1,58 @@ +package com.vaadin.tests.components.combobox; + +import org.junit.Test; +import org.openqa.selenium.Keys; +import org.openqa.selenium.interactions.Actions; + +import com.vaadin.testbench.By; +import com.vaadin.testbench.elements.NativeSelectElement; +import com.vaadin.tests.tb3.MultiBrowserTest; +import com.vaadin.tests.tb3.newelements.ComboBoxElement; + +public class ComboBoxLargeIconsTest extends MultiBrowserTest { + @Override + protected Class getUIClass() { + return com.vaadin.tests.components.combobox.Comboboxes.class; + } + + @Test + public void testComboBoxIcons() throws Exception { + openTestURL(); + NativeSelectElement iconSelect = $(NativeSelectElement.class).first(); + iconSelect.selectByText("16x16"); + + ComboBoxElement cb = $(ComboBoxElement.class).caption( + "Undefined wide select with 50 items").first(); + cb.openPopup(); + compareScreen("icons-16x16-page1"); + cb.openNextPage(); + compareScreen("icons-16x16-page2"); + cb.findElement(By.vaadin("#popup/item0")).click(); + compareScreen("icons-16x16-selected-1-3-5-9"); + + iconSelect.selectByText("32x32"); + cb.openPopup(); + compareScreen("icons-32x32-page2"); + + // Closes the popup + cb.openPopup(); + + iconSelect.selectByText("64x64"); + + ComboBoxElement pageLength0cb = $(ComboBoxElement.class).caption( + "Pagelength 0").first(); + pageLength0cb.openPopup(); + pageLength0cb.findElement(By.vaadin("#popup/item1")).click(); + + ComboBoxElement cb200px = $(ComboBoxElement.class).caption( + "200px wide select with 50 items").first(); + cb200px.openPopup(); + cb200px.findElement(By.vaadin("#popup/item1")).click(); + + ComboBoxElement cb150px = $(ComboBoxElement.class).caption( + "150px wide select with 5 items").first(); + new Actions(driver).sendKeys(cb150px, Keys.DOWN).perform(); + + compareScreen("icons-64x64-page1-highlight-first"); + } +} diff --git a/uitest/tb2/com/vaadin/tests/components/combobox/ComboBoxLargeIcons.html b/uitest/tb2/com/vaadin/tests/components/combobox/ComboBoxLargeIcons.html deleted file mode 100644 index ff6c82dfdb..0000000000 --- a/uitest/tb2/com/vaadin/tests/components/combobox/ComboBoxLargeIcons.html +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - -New Test - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    New Test
    open/run/com.vaadin.tests.components.combobox.Comboboxes?restartApplication
    selectvaadin=runcomvaadintestscomponentscomboboxComboboxes::PID_Sselectaction-Icon/domChild[0]label=16x16
    mouseClickvaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VFilterSelect[0]/domChild[1]13,8
    mouseClickvaadin=runcomvaadintestscomponentscomboboxComboboxes::Root/VFilterSelect$SuggestionPopup[0]/domChild[0]/domChild[2]/domChild[0]116,6
    open/run/com.vaadin.tests.components.combobox.Comboboxes?restartApplication
    selectvaadin=runcomvaadintestscomponentscomboboxComboboxes::PID_Sselectaction-Icon/domChild[0]label=16x16
    mouseClickvaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VFilterSelect[0]/domChild[1]13,8
    screenCaptureicons-16x16-page1
    mouseClickvaadin=runcomvaadintestscomponentscomboboxComboboxes::Root/VFilterSelect$SuggestionPopup[0]/domChild[0]/domChild[2]/domChild[0]116,6
    screenCaptureicons-16x16-page2
    mouseClickvaadin=runcomvaadintestscomponentscomboboxComboboxes::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item0378,1
    screenCaptureicons-16x16-selected-1-3-5-9
    selectvaadin=runcomvaadintestscomponentscomboboxComboboxes::PID_Sselectaction-Icon/domChild[0]label=32x32
    mouseClickvaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VFilterSelect[0]/domChild[2]8,13
    screenCaptureicons-32x32-page2
    mouseClickvaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[1]409,27
    selectvaadin=runcomvaadintestscomponentscomboboxComboboxes::PID_Sselectaction-Icon/domChild[0]label=64x64
    mouseClickvaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[9]/VFilterSelect[0]/domChild[1]11,13
    mouseClickvaadin=runcomvaadintestscomponentscomboboxComboboxes::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item1213,57
    mouseClickvaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[4]535,43
    mouseClickvaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[8]/VFilterSelect[0]/domChild[1]7,12
    mouseClickvaadin=runcomvaadintestscomponentscomboboxComboboxes::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item1158,25
    mouseClickvaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VFilterSelect[0]/domChild[0]16,9
    mouseClickvaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VFilterSelect[0]/domChild[0]80,7
    pressSpecialKeyvaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[7]/VFilterSelect[0]/domChild[0]down
    screenCaptureicons-64x64-page1-highlight-first
    mouseClickvaadin=runcomvaadintestscomponentscomboboxComboboxes::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/domChild[6]/domChild[0]510,1
    - - -- cgit v1.2.3 From 4a10a70fbecdd52758ebc73512974501a02d5fdd Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Mon, 20 Jul 2015 09:21:39 +0300 Subject: Fix DetailsRow communication use connector IDs (#18493) Details are now initialized when they are made visible. The old way of requesting when seen caused a lot of problems when moving stuff around. Now uses less communication, but reserves a bit extra resources due to all details components being in the hierarchy. Change-Id: I1c1163bdc306f5b86e5e0f6e2bbf2801e65c2243 --- .../vaadin/client/connectors/GridConnector.java | 395 ++++++--------------- .../client/connectors/RpcDataSourceConnector.java | 13 - .../com/vaadin/data/RpcDataProviderExtension.java | 241 ++----------- server/src/com/vaadin/ui/Grid.java | 17 +- .../com/vaadin/shared/ui/grid/GridClientRpc.java | 17 - .../com/vaadin/shared/ui/grid/GridServerRpc.java | 17 - .../components/grid/GridDetailsDetachTest.java | 24 ++ .../server/GridDetailsServerTest.java | 6 +- 8 files changed, 167 insertions(+), 563 deletions(-) diff --git a/client/src/com/vaadin/client/connectors/GridConnector.java b/client/src/com/vaadin/client/connectors/GridConnector.java index ef52a429e7..4c2e8ab4e1 100644 --- a/client/src/com/vaadin/client/connectors/GridConnector.java +++ b/client/src/com/vaadin/client/connectors/GridConnector.java @@ -19,13 +19,13 @@ package com.vaadin.client.connectors; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.logging.Logger; @@ -38,6 +38,7 @@ import com.vaadin.client.ComponentConnector; import com.vaadin.client.ConnectorHierarchyChangeEvent; import com.vaadin.client.DeferredWorker; import com.vaadin.client.MouseEventDetailsBuilder; +import com.vaadin.client.ServerConnector; import com.vaadin.client.annotations.OnStateChange; import com.vaadin.client.communication.StateChangeEvent; import com.vaadin.client.connectors.RpcDataSourceConnector.DetailsListener; @@ -79,10 +80,8 @@ import com.vaadin.client.widgets.Grid.FooterCell; import com.vaadin.client.widgets.Grid.FooterRow; import com.vaadin.client.widgets.Grid.HeaderCell; import com.vaadin.client.widgets.Grid.HeaderRow; -import com.vaadin.shared.Connector; import com.vaadin.shared.data.sort.SortDirection; import com.vaadin.shared.ui.Connect; -import com.vaadin.shared.ui.grid.DetailsConnectorChange; import com.vaadin.shared.ui.grid.EditorClientRpc; import com.vaadin.shared.ui.grid.EditorServerRpc; import com.vaadin.shared.ui.grid.GridClientRpc; @@ -420,255 +419,107 @@ public class GridConnector extends AbstractHasComponentsConnector implements } }; - private static class CustomDetailsGenerator implements DetailsGenerator { + private class CustomDetailsGenerator implements DetailsGenerator { - private final Map indexToDetailsMap = new HashMap(); + private final Map idToDetailsMap = new HashMap(); + private final Map idToRowIndex = new HashMap(); @Override - @SuppressWarnings("boxing") public Widget getDetails(int rowIndex) { - ComponentConnector componentConnector = indexToDetailsMap - .get(rowIndex); - if (componentConnector != null) { - return componentConnector.getWidget(); - } else { - return null; - } - } - - public void setDetailsConnectorChanges( - Set changes) { - /* - * To avoid overwriting connectors while moving them about, we'll - * take all the affected connectors, first all remove those that are - * removed or moved, then we add back those that are moved or added. - */ + JsonObject row = getWidget().getDataSource().getRow(rowIndex); - /* Remove moved/removed connectors from bookkeeping */ - for (DetailsConnectorChange change : changes) { - Integer oldIndex = change.getOldIndex(); - Connector removedConnector = indexToDetailsMap.remove(oldIndex); - - Connector connector = change.getConnector(); - assert removedConnector == null || connector == null - || removedConnector.equals(connector) : "Index " - + oldIndex + " points to " + removedConnector - + " while " + connector + " was expected"; - } - - /* Add moved/added connectors to bookkeeping */ - for (DetailsConnectorChange change : changes) { - Integer newIndex = change.getNewIndex(); - ComponentConnector connector = (ComponentConnector) change - .getConnector(); - - if (connector != null) { - assert newIndex != null : "An existing connector has a missing new index."; - - ComponentConnector prevConnector = indexToDetailsMap.put( - newIndex, connector); - - assert prevConnector == null : "Connector collision at index " - + newIndex - + " between old " - + prevConnector - + " and new " + connector; - } + if (!row.hasKey(GridState.JSONKEY_DETAILS_VISIBLE) + || row.getString(GridState.JSONKEY_DETAILS_VISIBLE) + .isEmpty()) { + return null; } - } - } - - @SuppressWarnings("boxing") - private static class DetailsConnectorFetcher implements DeferredWorker { - private static final int FETCH_TIMEOUT_MS = 5000; + String id = row.getString(GridState.JSONKEY_DETAILS_VISIBLE); + ComponentConnector componentConnector = idToDetailsMap.get(id); + idToRowIndex.put(id, rowIndex); - public interface Listener { - void fetchHasBeenScheduled(int id); - - void fetchHasReturned(int id); + return componentConnector.getWidget(); } - /** A flag making sure that we don't call scheduleFinally many times. */ - private boolean fetcherHasBeenCalled = false; - - /** A rolling counter for unique values. */ - private int detailsFetchCounter = 0; - - /** A collection that tracks the amount of requests currently underway. */ - private Set pendingFetches = new HashSet(5); - - private final ScheduledCommand lazyDetailsFetcher = new ScheduledCommand() { - @Override - public void execute() { - int currentFetchId = detailsFetchCounter++; - pendingFetches.add(currentFetchId); - rpc.sendDetailsComponents(currentFetchId); - fetcherHasBeenCalled = false; - - if (listener != null) { - listener.fetchHasBeenScheduled(currentFetchId); + public void updateConnectorHierarchy(List children) { + Set connectorIds = new HashSet(); + for (ServerConnector child : children) { + if (child instanceof ComponentConnector) { + connectorIds.add(child.getConnectorId()); + idToDetailsMap.put(child.getConnectorId(), + (ComponentConnector) child); } - - assert assertRequestDoesNotTimeout(currentFetchId); - } - }; - - private DetailsConnectorFetcher.Listener listener = null; - - private final GridServerRpc rpc; - - public DetailsConnectorFetcher(GridServerRpc rpc) { - assert rpc != null : "RPC was null"; - this.rpc = rpc; - } - - public void schedule() { - if (!fetcherHasBeenCalled) { - Scheduler.get().scheduleFinally(lazyDetailsFetcher); - fetcherHasBeenCalled = true; } - } - public void responseReceived(int fetchId) { - - if (fetchId < 0) { - /* Ignore negative fetchIds (they're pushed, not fetched) */ - return; + Set removedDetails = new HashSet(); + for (Entry entry : idToDetailsMap + .entrySet()) { + ComponentConnector connector = entry.getValue(); + String id = connector.getConnectorId(); + if (!connectorIds.contains(id)) { + removedDetails.add(entry.getKey()); + if (idToRowIndex.containsKey(id)) { + getWidget().setDetailsVisible(idToRowIndex.get(id), + false); + } + } } - boolean success = pendingFetches.remove(fetchId); - assert success : "Received a response with an unidentified fetch id"; - - if (listener != null) { - listener.fetchHasReturned(fetchId); + for (String id : removedDetails) { + idToDetailsMap.remove(id); + idToRowIndex.remove(id); } } - - @Override - public boolean isWorkPending() { - return fetcherHasBeenCalled || !pendingFetches.isEmpty(); - } - - private boolean assertRequestDoesNotTimeout(final int fetchId) { - /* - * This method will not be compiled without asserts enabled. This - * only makes sure that any request does not time out. - * - * TODO Should this be an explicit check? Is it worth the overhead? - */ - new Timer() { - @Override - public void run() { - assert !pendingFetches.contains(fetchId) : "Fetch id " - + fetchId + " timed out."; - } - }.schedule(FETCH_TIMEOUT_MS); - return true; - } - - public void setListener(DetailsConnectorFetcher.Listener listener) { - // if more are needed, feel free to convert this into a collection. - this.listener = listener; - } } /** - * The functionality that makes sure that the scroll position is still kept - * up-to-date even if more details are being fetched lazily. + * Class for handling scrolling issues with open details. + * + * @since + * @author Vaadin Ltd */ - private class LazyDetailsScrollAdjuster implements DeferredWorker { + private class LazyDetailsScroller implements DeferredWorker { - private static final int SCROLL_TO_END_ID = -2; - private static final int NO_SCROLL_SCHEDULED = -1; - - private class ScrollStopChecker implements DeferredWorker { - private final ScheduledCommand checkCommand = new ScheduledCommand() { - @Override - public void execute() { - isScheduled = false; - if (queuedFetches.isEmpty()) { - currentRow = NO_SCROLL_SCHEDULED; - destination = null; - } - } - }; - - private boolean isScheduled = false; - - public void schedule() { - if (isScheduled) { - return; - } - Scheduler.get().scheduleDeferred(checkCommand); - isScheduled = true; - } - - @Override - public boolean isWorkPending() { - return isScheduled; - } - } - - private DetailsConnectorFetcher.Listener fetcherListener = new DetailsConnectorFetcher.Listener() { - @Override - @SuppressWarnings("boxing") - public void fetchHasBeenScheduled(int id) { - if (currentRow != NO_SCROLL_SCHEDULED) { - queuedFetches.add(id); - } - } + /* Timer value tested to work in our test cluster with slow IE8s. */ + private static final int DISABLE_LAZY_SCROLL_TIMEOUT = 1500; + /* + * Cancels details opening scroll after timeout. Avoids any unexpected + * scrolls via details opening. + */ + private Timer disableScroller = new Timer() { @Override - @SuppressWarnings("boxing") - public void fetchHasReturned(int id) { - if (currentRow == NO_SCROLL_SCHEDULED - || queuedFetches.isEmpty()) { - return; - } - - queuedFetches.remove(id); - if (currentRow == SCROLL_TO_END_ID) { - getWidget().scrollToEnd(); - } else { - getWidget().scrollToRow(currentRow, destination); - } - - /* - * Schedule a deferred call whether we should stop adjusting for - * scrolling. - * - * This is done deferredly just because we can't be absolutely - * certain whether this most recent scrolling won't cascade into - * further lazy details loading (perhaps deferredly). - */ - scrollStopChecker.schedule(); + public void run() { + targetRow = -1; } }; - private int currentRow = NO_SCROLL_SCHEDULED; - private final Set queuedFetches = new HashSet(); - private final ScrollStopChecker scrollStopChecker = new ScrollStopChecker(); - private ScrollDestination destination; - - public LazyDetailsScrollAdjuster() { - detailsConnectorFetcher.setListener(fetcherListener); - } + private Integer targetRow = -1; + private ScrollDestination destination = null; - public void adjustForEnd() { - currentRow = SCROLL_TO_END_ID; + public void scrollToRow(Integer row, ScrollDestination dest) { + targetRow = row; + destination = dest; + disableScroller.schedule(DISABLE_LAZY_SCROLL_TIMEOUT); } - public void adjustFor(int row, ScrollDestination destination) { - currentRow = row; - this.destination = destination; + /** + * Inform LazyDetailsScroller that a details row has opened on a row. + * + * @since + * @param rowIndex + * index of row with details now open + */ + public void detailsOpened(int rowIndex) { + if (targetRow == rowIndex) { + getWidget().scrollToRow(targetRow, destination); + disableScroller.run(); + } } @Override public boolean isWorkPending() { - return currentRow != NO_SCROLL_SCHEDULED - || !queuedFetches.isEmpty() - || scrollStopChecker.isWorkPending(); + return disableScroller.isRunning(); } } @@ -730,39 +581,46 @@ public class GridConnector extends AbstractHasComponentsConnector implements private final CustomDetailsGenerator customDetailsGenerator = new CustomDetailsGenerator(); - private final DetailsConnectorFetcher detailsConnectorFetcher = new DetailsConnectorFetcher( - getRpcProxy(GridServerRpc.class)); - private final DetailsListener detailsListener = new DetailsListener() { @Override public void reapplyDetailsVisibility(final int rowIndex, final JsonObject row) { - Scheduler.get().scheduleDeferred(new ScheduledCommand() { - @Override - public void execute() { - if (hasDetailsOpen(row)) { - getWidget().setDetailsVisible(rowIndex, true); - detailsConnectorFetcher.schedule(); - } else { + if (hasDetailsOpen(row)) { + // Command for opening details row. + ScheduledCommand openDetails = new ScheduledCommand() { + @Override + public void execute() { + // Re-apply to force redraw. getWidget().setDetailsVisible(rowIndex, false); + getWidget().setDetailsVisible(rowIndex, true); + lazyDetailsScroller.detailsOpened(rowIndex); } + }; + + if (initialChange) { + Scheduler.get().scheduleDeferred(openDetails); + } else { + Scheduler.get().scheduleFinally(openDetails); } - }); + } else { + getWidget().setDetailsVisible(rowIndex, false); + } } private boolean hasDetailsOpen(JsonObject row) { return row.hasKey(GridState.JSONKEY_DETAILS_VISIBLE) - && row.getBoolean(GridState.JSONKEY_DETAILS_VISIBLE); - } - - @Override - public void closeDetails(int rowIndex) { - getWidget().setDetailsVisible(rowIndex, false); + && row.getString(GridState.JSONKEY_DETAILS_VISIBLE) != null; } }; - private final LazyDetailsScrollAdjuster lazyDetailsScrollAdjuster = new LazyDetailsScrollAdjuster(); + private final LazyDetailsScroller lazyDetailsScroller = new LazyDetailsScroller(); + + /* + * Initially details need to behave a bit differently to allow some + * escalator magic. + */ + private boolean initialChange; @Override @SuppressWarnings("unchecked") @@ -797,11 +655,13 @@ public class GridConnector extends AbstractHasComponentsConnector implements @Override public void scrollToEnd() { - lazyDetailsScrollAdjuster.adjustForEnd(); Scheduler.get().scheduleFinally(new ScheduledCommand() { @Override public void execute() { getWidget().scrollToEnd(); + // Scrolls further if details opens. + lazyDetailsScroller.scrollToRow(dataSource.size() - 1, + ScrollDestination.END); } }); } @@ -809,11 +669,12 @@ public class GridConnector extends AbstractHasComponentsConnector implements @Override public void scrollToRow(final int row, final ScrollDestination destination) { - lazyDetailsScrollAdjuster.adjustFor(row, destination); Scheduler.get().scheduleFinally(new ScheduledCommand() { @Override public void execute() { getWidget().scrollToRow(row, destination); + // Scrolls a bit further if details opens. + lazyDetailsScroller.scrollToRow(row, destination); } }); } @@ -822,51 +683,6 @@ public class GridConnector extends AbstractHasComponentsConnector implements public void recalculateColumnWidths() { getWidget().recalculateColumnWidths(); } - - @Override - @SuppressWarnings("boxing") - public void setDetailsConnectorChanges( - Set connectorChanges, int fetchId) { - customDetailsGenerator - .setDetailsConnectorChanges(connectorChanges); - - List removedFirst = new ArrayList( - connectorChanges); - Collections.sort(removedFirst, - DetailsConnectorChange.REMOVED_FIRST_COMPARATOR); - - // refresh moved/added details rows - for (DetailsConnectorChange change : removedFirst) { - Integer oldIndex = change.getOldIndex(); - Integer newIndex = change.getNewIndex(); - - assert oldIndex == null || oldIndex >= 0 : "Got an " - + "invalid old index: " + oldIndex - + " (connector: " + change.getConnector() + ")"; - assert newIndex == null || newIndex >= 0 : "Got an " - + "invalid new index: " + newIndex - + " (connector: " + change.getConnector() + ")"; - - if (oldIndex != null) { - /* Close the old/removed index */ - getWidget().setDetailsVisible(oldIndex, false); - - if (change.isShouldStillBeVisible()) { - getWidget().setDetailsVisible(oldIndex, true); - } - } - - if (newIndex != null) { - /* - * Since the component was lazy loaded, we need to - * refresh the details by toggling it. - */ - getWidget().setDetailsVisible(newIndex, false); - getWidget().setDetailsVisible(newIndex, true); - } - } - detailsConnectorFetcher.responseReceived(fetchId); - } }); getWidget().addSelectionHandler(internalSelectionChangeHandler); @@ -918,17 +734,12 @@ public class GridConnector extends AbstractHasComponentsConnector implements layout(); } - @Override - public void onUnregister() { - customDetailsGenerator.indexToDetailsMap.clear(); - - super.onUnregister(); - } - @Override public void onStateChanged(final StateChangeEvent stateChangeEvent) { super.onStateChanged(stateChangeEvent); + initialChange = stateChangeEvent.isInitialStateChange(); + // Column updates if (stateChangeEvent.hasPropertyChanged("columns")) { @@ -1411,6 +1222,7 @@ public class GridConnector extends AbstractHasComponentsConnector implements @Override public void onConnectorHierarchyChange( ConnectorHierarchyChangeEvent connectorHierarchyChangeEvent) { + customDetailsGenerator.updateConnectorHierarchy(getChildren()); } public String getColumnId(Grid.Column column) { @@ -1427,8 +1239,7 @@ public class GridConnector extends AbstractHasComponentsConnector implements @Override public boolean isWorkPending() { - return detailsConnectorFetcher.isWorkPending() - || lazyDetailsScrollAdjuster.isWorkPending(); + return lazyDetailsScroller.isWorkPending(); } /** diff --git a/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java b/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java index 627ee74eca..c1b9f13ef4 100644 --- a/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java +++ b/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java @@ -64,14 +64,6 @@ public class RpcDataSourceConnector extends AbstractExtensionConnector { * @see GridState#JSONKEY_DETAILS_VISIBLE */ void reapplyDetailsVisibility(int rowIndex, JsonObject row); - - /** - * Closes details for a row. - * - * @param rowIndex - * the index of the row for which to close details - */ - void closeDetails(int rowIndex); } public class RpcDataSource extends AbstractRemoteDataSource { @@ -221,11 +213,6 @@ public class RpcDataSourceConnector extends AbstractExtensionConnector { rowData.get(i)); } } - - @Override - protected void onDropFromCache(int rowIndex) { - detailsListener.closeDetails(rowIndex); - } } private final RpcDataSource dataSource = new RpcDataSource(); diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java index b3c7972b52..6f8a7e8f7b 100644 --- a/server/src/com/vaadin/data/RpcDataProviderExtension.java +++ b/server/src/com/vaadin/data/RpcDataProviderExtension.java @@ -25,7 +25,6 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; import java.util.logging.Logger; @@ -49,11 +48,9 @@ import com.vaadin.server.ClientConnector; import com.vaadin.server.KeyMapper; import com.vaadin.shared.data.DataProviderRpc; import com.vaadin.shared.data.DataRequestRpc; -import com.vaadin.shared.ui.grid.DetailsConnectorChange; import com.vaadin.shared.ui.grid.GridClientRpc; import com.vaadin.shared.ui.grid.GridState; import com.vaadin.shared.ui.grid.Range; -import com.vaadin.shared.util.SharedUtil; import com.vaadin.ui.Component; import com.vaadin.ui.Grid; import com.vaadin.ui.Grid.CellReference; @@ -119,16 +116,11 @@ public class RpcDataProviderExtension extends AbstractExtension { } for (Object itemId : itemsRemoved) { - detailComponentManager.destroyDetails(itemId); itemIdToKey.remove(itemId); } for (Object itemId : itemSet) { itemIdToKey.put(itemId, getKey(itemId)); - if (visibleDetails.contains(itemId)) { - detailComponentManager.createDetails(itemId, - indexOf(itemId)); - } } } @@ -620,34 +612,11 @@ public class RpcDataProviderExtension extends AbstractExtension { private final Map visibleDetailsComponents = Maps .newHashMap(); - /** A lookup map for which row contains which details component. */ - private BiMap rowIndexToDetails = HashBiMap - .create(); - - /** - * A copy of {@link #rowIndexToDetails} from its last stable state. Used - * for creating a diff against {@link #rowIndexToDetails}. - * - * @see #getAndResetConnectorChanges() - */ - private BiMap prevRowIndexToDetails = HashBiMap - .create(); - - /** - * A set keeping track on components that have been created, but not - * attached. They should be attached at some later point in time. - *

    - * This isn't strictly requried, but it's a handy explicit log. You - * could find out the same thing by taking out all the other components - * and checking whether Grid is their parent or not. - */ - private final Set unattachedComponents = Sets.newHashSet(); - /** * Keeps tabs on all the details that did not get a component during * {@link #createDetails(Object, int)}. */ - private final Map emptyDetails = Maps.newHashMap(); + private final Set emptyDetails = Sets.newHashSet(); private Grid grid; @@ -661,19 +630,16 @@ public class RpcDataProviderExtension extends AbstractExtension { * the item id for which to create the details component. * Assumed not null and that a component is not * currently present for this item previously - * @param rowIndex - * the row index for {@code itemId} * @throws IllegalStateException * if the current details generator provides a component * that was manually attached, or if the same instance has * already been provided */ - public void createDetails(Object itemId, int rowIndex) - throws IllegalStateException { + public void createDetails(Object itemId) throws IllegalStateException { assert itemId != null : "itemId was null"; - Integer newRowIndex = Integer.valueOf(rowIndex); - if (visibleDetailsComponents.containsKey(itemId)) { + if (visibleDetailsComponents.containsKey(itemId) + || emptyDetails.contains(itemId)) { // Don't overwrite existing components return; } @@ -684,58 +650,26 @@ public class RpcDataProviderExtension extends AbstractExtension { DetailsGenerator detailsGenerator = grid.getDetailsGenerator(); Component details = detailsGenerator.getDetails(rowReference); if (details != null) { - String generatorName = detailsGenerator.getClass().getName(); if (details.getParent() != null) { - throw new IllegalStateException(generatorName + String name = detailsGenerator.getClass().getName(); + throw new IllegalStateException(name + " generated a details component that already " - + "was attached. (itemId: " + itemId + ", row: " - + rowIndex + ", component: " + details); - } - - if (rowIndexToDetails.containsValue(details)) { - throw new IllegalStateException(generatorName - + " provided a details component that already " - + "exists in Grid. (itemId: " + itemId + ", row: " - + rowIndex + ", component: " + details); + + "was attached. (itemId: " + itemId + + ", component: " + details + ")"); } visibleDetailsComponents.put(itemId, details); - rowIndexToDetails.put(newRowIndex, details); - unattachedComponents.add(details); - assert !emptyDetails.containsKey(itemId) : "Bookeeping thinks " + details.setParent(grid); + grid.markAsDirty(); + + assert !emptyDetails.contains(itemId) : "Bookeeping thinks " + "itemId is empty even though we just created a " + "component for it (" + itemId + ")"; } else { - assert assertItemIdHasNotMovedAndNothingIsOverwritten(itemId, - newRowIndex); - emptyDetails.put(itemId, newRowIndex); - } - - /* - * Don't attach the components here. It's done by - * GridServerRpc.sendDetailsComponents in a separate roundtrip. - */ - } - - private boolean assertItemIdHasNotMovedAndNothingIsOverwritten( - Object itemId, Integer newRowIndex) { - - Integer oldRowIndex = emptyDetails.get(itemId); - if (!SharedUtil.equals(oldRowIndex, newRowIndex)) { - - assert !emptyDetails.containsKey(itemId) : "Unexpected " - + "change of empty details row index for itemId " - + itemId + " from " + oldRowIndex + " to " - + newRowIndex; - - assert !emptyDetails.containsValue(newRowIndex) : "Bookkeeping" - + " already had another itemId for this empty index " - + "(index: " + newRowIndex + ", new itemId: " + itemId - + ")"; + emptyDetails.add(itemId); } - return true; } /** @@ -756,8 +690,6 @@ public class RpcDataProviderExtension extends AbstractExtension { return; } - rowIndexToDetails.inverse().remove(removedComponent); - removedComponent.setParent(null); grid.markAsDirty(); } @@ -773,81 +705,12 @@ public class RpcDataProviderExtension extends AbstractExtension { public Collection getComponents() { Set components = new HashSet( visibleDetailsComponents.values()); - components.removeAll(unattachedComponents); return components; } - /** - * Gets information on how the connectors have changed. - *

    - * This method only returns the changes that have been made between two - * calls of this method. I.e. Calling this method once will reset the - * state for the next state. - *

    - * Used internally by the Grid object. - * - * @return information on how the connectors have changed - */ - public Set getAndResetConnectorChanges() { - Set changes = new HashSet(); - - // populate diff with added/changed - for (Entry entry : rowIndexToDetails.entrySet()) { - Component component = entry.getValue(); - assert component != null : "rowIndexToDetails contains a null component"; - - Integer newIndex = entry.getKey(); - Integer oldIndex = prevRowIndexToDetails.inverse().get( - component); - - /* - * only attach components. Detaching already happened in - * destroyDetails. - */ - if (newIndex != null && oldIndex == null) { - assert unattachedComponents.contains(component) : "unattachedComponents does not contain component for index " - + newIndex + " (" + component + ")"; - component.setParent(grid); - unattachedComponents.remove(component); - } - - if (!SharedUtil.equals(oldIndex, newIndex)) { - changes.add(new DetailsConnectorChange(component, oldIndex, - newIndex, emptyDetails.containsKey(component))); - } - } - - // populate diff with removed - for (Entry entry : prevRowIndexToDetails - .entrySet()) { - Integer oldIndex = entry.getKey(); - Component component = entry.getValue(); - Integer newIndex = rowIndexToDetails.inverse().get(component); - if (newIndex == null) { - changes.add(new DetailsConnectorChange(null, oldIndex, - null, emptyDetails.containsValue(oldIndex))); - } - } - - // reset diff map - prevRowIndexToDetails = HashBiMap.create(rowIndexToDetails); - - return changes; - } - public void refresh(Object itemId) { - Component component = visibleDetailsComponents.get(itemId); - Integer rowIndex = null; - if (component != null) { - rowIndex = rowIndexToDetails.inverse().get(component); - destroyDetails(itemId); - } else { - rowIndex = emptyDetails.remove(itemId); - } - - assert rowIndex != null : "Given itemId does not map to an " - + "existing detail row (" + itemId + ")"; - createDetails(itemId, rowIndex.intValue()); + destroyDetails(itemId); + createDetails(itemId); } void setGrid(Grid grid) { @@ -927,17 +790,13 @@ public class RpcDataProviderExtension extends AbstractExtension { listener.removeListener(); } - // Wipe clean all details. - HashSet detailItemIds = new HashSet( - detailComponentManager.visibleDetailsComponents - .keySet()); - for (Object itemId : detailItemIds) { - detailComponentManager.destroyDetails(itemId); - } - listeners.clear(); activeRowHandler.activeRange = Range.withLength(0, 0); + for (Object itemId : visibleDetails) { + detailComponentManager.destroyDetails(itemId); + } + /* Mark as dirty to push changes in beforeClientResponse */ bareItemSetTriggeredSizeChange = true; markAsDirty(); @@ -1118,7 +977,14 @@ public class RpcDataProviderExtension extends AbstractExtension { rowObject.put(GridState.JSONKEY_ROWKEY, keyMapper.getKey(itemId)); if (visibleDetails.contains(itemId)) { - rowObject.put(GridState.JSONKEY_DETAILS_VISIBLE, true); + // Double check to be sure details component exists. + detailComponentManager.createDetails(itemId); + Component detailsComponent = detailComponentManager.visibleDetailsComponents + .get(itemId); + rowObject.put( + GridState.JSONKEY_DETAILS_VISIBLE, + (detailsComponent != null ? detailsComponent + .getConnectorId() : "")); } rowReference.set(itemId); @@ -1254,15 +1120,11 @@ public class RpcDataProviderExtension extends AbstractExtension { private void internalUpdateRowData(Object itemId) { int index = container.indexOfId(itemId); - if (index >= 0) { + if (activeRowHandler.activeRange.contains(index)) { JsonValue row = getRowData(getGrid().getColumns(), itemId); JsonArray rowArray = Json.createArray(); rowArray.set(0, row); rpc.setRowData(index, rowArray); - - if (isDetailsVisible(itemId)) { - detailComponentManager.createDetails(itemId, index); - } } } @@ -1399,37 +1261,21 @@ public class RpcDataProviderExtension extends AbstractExtension { * hide */ public void setDetailsVisible(Object itemId, boolean visible) { - final boolean modified; - if (visible) { - modified = visibleDetails.add(itemId); + visibleDetails.add(itemId); /* - * We don't want to create the component here, since the component - * might be out of view, and thus we don't know where the details - * should end up on the client side. This is also a great thing to - * optimize away, so that in case a lot of things would be opened at - * once, a huge chunk of data doesn't get sent over immediately. + * This might be an issue with a huge number of open rows, but as of + * now this works in most of the cases. */ - + detailComponentManager.createDetails(itemId); } else { - modified = visibleDetails.remove(itemId); + visibleDetails.remove(itemId); - /* - * Here we can try to destroy the component no matter what. The - * component has been removed and should be detached from the - * component hierarchy. The details row will be closed on the client - * side automatically. - */ detailComponentManager.destroyDetails(itemId); } - int rowIndex = indexOf(itemId); - boolean modifiedRowIsActive = activeRowHandler.activeRange - .contains(rowIndex); - if (modified && modifiedRowIsActive) { - updateRowData(itemId); - } + updateRowData(itemId); } /** @@ -1454,18 +1300,10 @@ public class RpcDataProviderExtension extends AbstractExtension { public void refreshDetails() { for (Object itemId : ImmutableSet.copyOf(visibleDetails)) { detailComponentManager.refresh(itemId); + updateRowData(itemId); } } - private int indexOf(Object itemId) { - /* - * It would be great if we could optimize this method away, since the - * normal usage of Grid doesn't need any indices to be known. It was - * already optimized away once, maybe we can do away with these as well. - */ - return container.indexOfId(itemId); - } - /** * Gets the detail component manager for this data provider * @@ -1475,13 +1313,4 @@ public class RpcDataProviderExtension extends AbstractExtension { public DetailComponentManager getDetailComponentManager() { return detailComponentManager; } - - @Override - public void detach() { - for (Object itemId : ImmutableSet.copyOf(visibleDetails)) { - detailComponentManager.destroyDetails(itemId); - } - - super.detach(); - } } diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java index e9469c5bca..ea973bb3ba 100644 --- a/server/src/com/vaadin/ui/Grid.java +++ b/server/src/com/vaadin/ui/Grid.java @@ -3281,7 +3281,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier, * currently extends the AbstractExtension superclass, but this fact should * be regarded as an implementation detail and subject to change in a future * major or minor Vaadin revision. - * + * * @param * the type this renderer knows how to present */ @@ -3354,7 +3354,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier, * is desired. For instance, a {@code Renderer} could first turn a * date value into a formatted string and return * {@code encode(dateString, String.class)}. - * + * * @param value * the value to be encoded * @param type @@ -3369,7 +3369,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier, /** * An abstract base class for server-side Grid extensions. - * + * * @since 7.5 */ public static abstract class AbstractGridExtension extends @@ -3384,7 +3384,7 @@ public class Grid extends AbstractComponent implements SelectionNotifier, /** * Constructs a new Grid extension and extends given Grid. - * + * * @param grid * a grid instance */ @@ -3856,13 +3856,6 @@ public class Grid extends AbstractComponent implements SelectionNotifier, userOriginated); } } - - @Override - public void sendDetailsComponents(int fetchId) { - getRpcProxy(GridClientRpc.class).setDetailsConnectorChanges( - detailComponentManager.getAndResetConnectorChanges(), - fetchId); - } }); registerRpc(new EditorServerRpc() { @@ -6063,8 +6056,6 @@ public class Grid extends AbstractComponent implements SelectionNotifier, this.detailsGenerator = detailsGenerator; datasourceExtension.refreshDetails(); - getRpcProxy(GridClientRpc.class).setDetailsConnectorChanges( - detailComponentManager.getAndResetConnectorChanges(), -1); } /** diff --git a/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java b/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java index 3c6d993482..ac1b1d5a78 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java @@ -15,8 +15,6 @@ */ package com.vaadin.shared.ui.grid; -import java.util.Set; - import com.vaadin.shared.communication.ClientRpc; /** @@ -57,19 +55,4 @@ public interface GridClientRpc extends ClientRpc { * Command client Grid to recalculate column widths. */ public void recalculateColumnWidths(); - - /** - * Informs the GridConnector on how the indexing of details connectors has - * changed. - * - * @since 7.5.0 - * @param connectorChanges - * the indexing changes of details connectors - * @param fetchId - * the id of the request for fetching the changes. A negative - * number indicates a push (not requested by the client side) - */ - public void setDetailsConnectorChanges( - Set connectorChanges, int fetchId); - } diff --git a/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java index dca55c11c4..5c91f2b746 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridServerRpc.java @@ -60,23 +60,6 @@ public interface GridServerRpc extends ServerRpc { void columnsReordered(List newColumnOrder, List oldColumnOrder); - /** - * This is a trigger for Grid to send whatever has changed regarding the - * details components. - *

    - * The components can't be sent eagerly, since they are generated as a side - * effect in - * {@link com.vaadin.data.RpcDataProviderExtension#beforeClientResponse(boolean)} - * , and that is too late to change the hierarchy. So we need this - * round-trip to work around that limitation. - * - * @since 7.5.0 - * @param fetchId - * an unique identifier for the request - * @see com.vaadin.ui.Grid#setDetailsVisible(Object, boolean) - */ - void sendDetailsComponents(int fetchId); - /** * Informs the server that the column's visibility has been changed. * diff --git a/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetachTest.java b/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetachTest.java index fc79fd1b68..7406daeacd 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetachTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetachTest.java @@ -70,4 +70,28 @@ public class GridDetailsDetachTest extends MultiBrowserTest { Assert.assertEquals("Spacer content not visible", "Extra data for Bean 5", spacers.get(1).getText()); } + + @Test + public void testDetachAndImmediateReattach() { + setDebug(true); + openTestURL(); + + $(GridElement.class).first().getCell(3, 0).click(); + $(GridElement.class).first().getCell(5, 0).click(); + + assertNoErrorNotifications(); + + // Detach and Re-attach Grid + $(ButtonElement.class).get(1).click(); + + assertNoErrorNotifications(); + + List spacers = findElements(By.className("v-grid-spacer")); + Assert.assertEquals("Not enough spacers in DOM", 2, spacers.size()); + Assert.assertEquals("Spacer content not visible", + "Extra data for Bean 3", spacers.get(0).getText()); + Assert.assertEquals("Spacer content not visible", + "Extra data for Bean 5", spacers.get(1).getText()); + } + } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridDetailsServerTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridDetailsServerTest.java index 4ea64073f3..326dbcd55f 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridDetailsServerTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridDetailsServerTest.java @@ -22,7 +22,6 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.NoSuchElementException; @@ -196,14 +195,11 @@ public class GridDetailsServerTest extends GridBasicFeaturesTest { assertEquals("Two", getGridElement().getDetails(0).getText()); } - @Ignore("This use case is not currently supported by Grid. If the detail " - + "is out of view, the component is detached from the UI and a " - + "new instance is generated when scrolled back. Support will " - + "maybe be incorporated at a later time") @Test public void hierarchyChangesWorkInDetailsWhileOutOfView() { selectMenuPath(DETAILS_GENERATOR_HIERARCHICAL); selectMenuPath(OPEN_FIRST_ITEM_DETAILS); + assertEquals("One", getGridElement().getDetails(0).getText()); scrollGridVerticallyTo(10000); selectMenuPath(CHANGE_HIERARCHY); scrollGridVerticallyTo(0); -- cgit v1.2.3 From 029db52f12c0a97f6e8a1eeb7fe872b4a772eb4e Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Fri, 17 Jul 2015 13:13:07 +0300 Subject: Fix IE8 centered window initial placement (#18498) Change-Id: I8809f31c27d9ad2860c3f21b21948312272db18f --- client/src/com/vaadin/client/ui/VOverlay.java | 14 +------------- .../src/com/vaadin/client/ui/window/WindowConnector.java | 10 +++++++++- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/client/src/com/vaadin/client/ui/VOverlay.java b/client/src/com/vaadin/client/ui/VOverlay.java index e823e8ee80..3649afc74f 100644 --- a/client/src/com/vaadin/client/ui/VOverlay.java +++ b/client/src/com/vaadin/client/ui/VOverlay.java @@ -22,8 +22,6 @@ import java.util.logging.Logger; import com.google.gwt.animation.client.Animation; import com.google.gwt.aria.client.Roles; import com.google.gwt.core.client.JavaScriptObject; -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.IFrameElement; @@ -473,17 +471,7 @@ public class VOverlay extends PopupPanel implements CloseHandler { if (isAnimationEnabled()) { new ResizeAnimation().run(POPUP_PANEL_ANIMATION_DURATION); } else { - if (BrowserInfo.get().isIE8()) { - Scheduler.get().scheduleFinally(new ScheduledCommand() { - - @Override - public void execute() { - positionOrSizeUpdated(1.0); - } - }); - } else { - positionOrSizeUpdated(1.0); - } + positionOrSizeUpdated(1.0); } current = null; } diff --git a/client/src/com/vaadin/client/ui/window/WindowConnector.java b/client/src/com/vaadin/client/ui/window/WindowConnector.java index 9b710981d8..8c23f712ad 100644 --- a/client/src/com/vaadin/client/ui/window/WindowConnector.java +++ b/client/src/com/vaadin/client/ui/window/WindowConnector.java @@ -17,6 +17,8 @@ package com.vaadin.client.ui.window; import java.util.logging.Logger; +import com.google.gwt.core.client.Scheduler; +import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.Node; @@ -407,7 +409,13 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector window.centered = state.centered; // Ensure centering before setting visible (#16486) if (window.centered && getState().windowMode != WindowMode.MAXIMIZED) { - window.center(); + Scheduler.get().scheduleFinally(new ScheduledCommand() { + + @Override + public void execute() { + getWidget().center(); + } + }); } window.setVisible(true); -- cgit v1.2.3 From 9147fbad899003e578e0ffdfd1e1ff822d8b968e Mon Sep 17 00:00:00 2001 From: Markus Koivisto Date: Wed, 22 Jul 2015 16:59:01 +0300 Subject: Fix empty @since Change-Id: Ie060beaa9eca3b098d7e07116d64580c6a198ee8 --- client/src/com/vaadin/client/connectors/GridConnector.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/client/src/com/vaadin/client/connectors/GridConnector.java b/client/src/com/vaadin/client/connectors/GridConnector.java index 4c2e8ab4e1..a99b227abe 100644 --- a/client/src/com/vaadin/client/connectors/GridConnector.java +++ b/client/src/com/vaadin/client/connectors/GridConnector.java @@ -475,8 +475,7 @@ public class GridConnector extends AbstractHasComponentsConnector implements /** * Class for handling scrolling issues with open details. * - * @since - * @author Vaadin Ltd + * @since 7.5.2 */ private class LazyDetailsScroller implements DeferredWorker { @@ -506,7 +505,6 @@ public class GridConnector extends AbstractHasComponentsConnector implements /** * Inform LazyDetailsScroller that a details row has opened on a row. * - * @since * @param rowIndex * index of row with details now open */ -- cgit v1.2.3 From edbe0cef91f1776a0ceebd6d47cfd73589cddce3 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 28 Jul 2015 11:39:29 +0300 Subject: Make methods return what they promise Change-Id: I0b906047a6f6bf81b6c5fb544164b62916ef5982 --- client/src/com/vaadin/client/ComputedStyle.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/com/vaadin/client/ComputedStyle.java b/client/src/com/vaadin/client/ComputedStyle.java index 61cb3c2eb6..b11ba4b26a 100644 --- a/client/src/com/vaadin/client/ComputedStyle.java +++ b/client/src/com/vaadin/client/ComputedStyle.java @@ -155,10 +155,10 @@ public class ComputedStyle { * the property to retrieve * @return the double value of the property */ - public final int getDoubleProperty(String name) { + public final double getDoubleProperty(String name) { Profiler.enter("ComputedStyle.getDoubleProperty"); String value = getProperty(name); - int result = parseDoubleNative(value); + double result = parseDoubleNative(value); Profiler.leave("ComputedStyle.getDoubleProperty"); return result; } @@ -275,7 +275,7 @@ public class ComputedStyle { * @return the value from the string before any non-numeric characters or * NaN if the value cannot be parsed as a number */ - private static native int parseDoubleNative(final String value) + private static native double parseDoubleNative(final String value) /*-{ return parseFloat(value); }-*/; -- cgit v1.2.3 From bebb7efeaee4f02ac7d844cb0b11524d242eccba Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 30 Jul 2015 13:01:56 +0300 Subject: Detect Edge correctly (#18537) Change-Id: I6aa7e7b7498ff85489843e52bd351e54c4ba70f9 --- client/src/com/vaadin/client/BrowserInfo.java | 16 ++++++++++++++ .../client/VBrowserDetailsUserAgentParserTest.java | 25 ++++++++++++++++++++++ server/src/com/vaadin/server/WebBrowser.java | 14 ++++++++++++ shared/src/com/vaadin/shared/VBrowserDetails.java | 25 ++++++++++++++++++++++ 4 files changed, 80 insertions(+) diff --git a/client/src/com/vaadin/client/BrowserInfo.java b/client/src/com/vaadin/client/BrowserInfo.java index 8b274623c1..8dcefddcf5 100644 --- a/client/src/com/vaadin/client/BrowserInfo.java +++ b/client/src/com/vaadin/client/BrowserInfo.java @@ -30,6 +30,7 @@ public class BrowserInfo { private static final String BROWSER_OPERA = "op"; private static final String BROWSER_IE = "ie"; + private static final String BROWSER_EDGE = "edge"; private static final String BROWSER_FIREFOX = "ff"; private static final String BROWSER_SAFARI = "sa"; @@ -171,6 +172,13 @@ public class BrowserInfo { minorVersionClass = majorVersionClass + browserDetails.getBrowserMinorVersion(); browserEngineClass = ENGINE_TRIDENT; + } else if (browserDetails.isEdge()) { + browserIdentifier = BROWSER_EDGE; + majorVersionClass = browserIdentifier + + getBrowserMajorVersion(); + minorVersionClass = majorVersionClass + + browserDetails.getBrowserMinorVersion(); + browserEngineClass = ""; } else if (browserDetails.isOpera()) { browserIdentifier = BROWSER_OPERA; majorVersionClass = browserIdentifier @@ -225,6 +233,10 @@ public class BrowserInfo { return browserDetails.isIE(); } + public boolean isEdge() { + return browserDetails.isEdge(); + } + public boolean isFirefox() { return browserDetails.isFirefox(); } @@ -245,6 +257,10 @@ public class BrowserInfo { return isIE() && getBrowserMajorVersion() == 10; } + public boolean isIE11() { + return isIE() && getBrowserMajorVersion() == 11; + } + public boolean isChrome() { return browserDetails.isChrome(); } diff --git a/client/tests/src/com/vaadin/client/VBrowserDetailsUserAgentParserTest.java b/client/tests/src/com/vaadin/client/VBrowserDetailsUserAgentParserTest.java index 62b727e5f5..24bf9b6558 100644 --- a/client/tests/src/com/vaadin/client/VBrowserDetailsUserAgentParserTest.java +++ b/client/tests/src/com/vaadin/client/VBrowserDetailsUserAgentParserTest.java @@ -56,6 +56,8 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase { private static final String ANDROID_MOTOROLA_3_0 = "Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13"; private static final String ANDROID_GALAXY_NEXUS_4_0_4_CHROME = "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19"; + private static final String EDGE_WINDOWS_10 = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.10240"; + public void testSafari3() { VBrowserDetails bd = new VBrowserDetails(SAFARI3_WINDOWS); assertWebKit(bd); @@ -423,6 +425,14 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase { assertWindows(bd, true); } + public void testEdgeWindows10() { + VBrowserDetails bd = new VBrowserDetails(EDGE_WINDOWS_10); + assertEdge(bd); + assertBrowserMajorVersion(bd, 12); + assertBrowserMinorVersion(bd, 10240); + assertWindows(bd, false); + } + /* * Helper methods below */ @@ -484,6 +494,7 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase { assertFalse(browserDetails.isIE()); assertFalse(browserDetails.isOpera()); assertFalse(browserDetails.isSafari()); + assertFalse(browserDetails.isEdge()); } private void assertChrome(VBrowserDetails browserDetails) { @@ -493,6 +504,7 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase { assertFalse(browserDetails.isIE()); assertFalse(browserDetails.isOpera()); assertFalse(browserDetails.isSafari()); + assertFalse(browserDetails.isEdge()); } private void assertIE(VBrowserDetails browserDetails) { @@ -502,6 +514,7 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase { assertTrue(browserDetails.isIE()); assertFalse(browserDetails.isOpera()); assertFalse(browserDetails.isSafari()); + assertFalse(browserDetails.isEdge()); } private void assertOpera(VBrowserDetails browserDetails) { @@ -511,6 +524,7 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase { assertFalse(browserDetails.isIE()); assertTrue(browserDetails.isOpera()); assertFalse(browserDetails.isSafari()); + assertFalse(browserDetails.isEdge()); } private void assertSafari(VBrowserDetails browserDetails) { @@ -520,6 +534,17 @@ public class VBrowserDetailsUserAgentParserTest extends TestCase { assertFalse(browserDetails.isIE()); assertFalse(browserDetails.isOpera()); assertTrue(browserDetails.isSafari()); + assertFalse(browserDetails.isEdge()); + } + + private void assertEdge(VBrowserDetails browserDetails) { + // Browser + assertFalse(browserDetails.isFirefox()); + assertFalse(browserDetails.isChrome()); + assertFalse(browserDetails.isIE()); + assertFalse(browserDetails.isOpera()); + assertFalse(browserDetails.isSafari()); + assertTrue(browserDetails.isEdge()); } private void assertMacOSX(VBrowserDetails browserDetails) { diff --git a/server/src/com/vaadin/server/WebBrowser.java b/server/src/com/vaadin/server/WebBrowser.java index 66018b02f2..9bf30cb3db 100644 --- a/server/src/com/vaadin/server/WebBrowser.java +++ b/server/src/com/vaadin/server/WebBrowser.java @@ -125,6 +125,20 @@ public class WebBrowser implements Serializable { return browserDetails.isIE(); } + /** + * Tests whether the user is using Edge. + * + * @return true if the user is using Edge, false if the user is not using + * Edge or if no information on the browser is present + */ + public boolean isEdge() { + if (browserDetails == null) { + return false; + } + + return browserDetails.isEdge(); + } + /** * Tests whether the user is using Safari. * diff --git a/shared/src/com/vaadin/shared/VBrowserDetails.java b/shared/src/com/vaadin/shared/VBrowserDetails.java index 561b6c76d0..d0de8ffb9f 100644 --- a/shared/src/com/vaadin/shared/VBrowserDetails.java +++ b/shared/src/com/vaadin/shared/VBrowserDetails.java @@ -41,6 +41,7 @@ public class VBrowserDetails implements Serializable { private boolean isFirefox = false; private boolean isOpera = false; private boolean isIE = false; + private boolean isEdge = false; private boolean isPhantomJS = false; private boolean isWindowsPhone; @@ -88,6 +89,16 @@ public class VBrowserDetails implements Serializable { isSafari = !isChrome && !isIE && userAgent.indexOf("safari") != -1; isFirefox = userAgent.indexOf(" firefox/") != -1; isPhantomJS = userAgent.indexOf("phantomjs/") != -1; + if (userAgent.indexOf(" edge/") != -1) { + isEdge = true; + isChrome = false; + isOpera = false; + isIE = false; + isSafari = false; + isFirefox = false; + isWebKit = false; + isGecko = false; + } // chromeframe isChromeFrameCapable = userAgent.indexOf("chromeframe") != -1; @@ -115,6 +126,8 @@ public class VBrowserDetails implements Serializable { tmp = tmp.replaceFirst("([0-9]+\\.[0-9]+).*", "$1"); browserEngineVersion = Float.parseFloat(tmp); } + } else if (isEdge) { + browserEngineVersion = 0; } } catch (Exception e) { // Browser engine version parsing failed @@ -158,6 +171,9 @@ public class VBrowserDetails implements Serializable { i = userAgent.indexOf("opera/") + 6; } parseVersionString(safeSubstring(userAgent, i, i + 5)); + } else if (isEdge) { + int i = userAgent.indexOf(" edge/") + 6; + parseVersionString(safeSubstring(userAgent, i, i + 8)); } } catch (Exception e) { // Browser version parsing failed @@ -372,6 +388,15 @@ public class VBrowserDetails implements Serializable { return isIE; } + /** + * Tests if the browser is Edge. + * + * @return true if it is Edge, false otherwise + */ + public boolean isEdge() { + return isEdge; + } + /** * Tests if the browser is PhantomJS. * -- cgit v1.2.3 From 38abea64cc1a5f54bccc21f79a6d7f4137fe0179 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 30 Jul 2015 13:39:59 +0300 Subject: Enable IE stuff also needed for Edge (#18523) Change-Id: I8e8a80acde885a5d4e0db67101c2a4d101371845 --- client/src/com/vaadin/client/ResourceLoader.java | 8 ++++---- client/src/com/vaadin/client/ui/FocusableScrollPanel.java | 2 +- client/src/com/vaadin/client/ui/VRichTextArea.java | 2 +- client/src/com/vaadin/client/ui/VTextArea.java | 8 ++++---- client/src/com/vaadin/client/ui/VWindow.java | 8 +++----- 5 files changed, 13 insertions(+), 15 deletions(-) diff --git a/client/src/com/vaadin/client/ResourceLoader.java b/client/src/com/vaadin/client/ResourceLoader.java index 9e9ce5ac49..559768d09c 100644 --- a/client/src/com/vaadin/client/ResourceLoader.java +++ b/client/src/com/vaadin/client/ResourceLoader.java @@ -283,8 +283,7 @@ public class ResourceLoader { * @since 7.2.4 */ public static boolean supportsInOrderScriptExecution() { - return BrowserInfo.get().isIE() - && BrowserInfo.get().getBrowserMajorVersion() >= 11; + return BrowserInfo.get().isIE11() || BrowserInfo.get().isEdge(); } /** @@ -486,10 +485,11 @@ public class ResourceLoader { addOnloadHandler(linkElement, new ResourceLoadListener() { @Override public void onLoad(ResourceLoadEvent event) { - // Chrome && IE fires load for errors, must check + // Chrome, IE, Edge all fire load for errors, must check // stylesheet data if (BrowserInfo.get().isChrome() - || BrowserInfo.get().isIE()) { + || BrowserInfo.get().isIE() + || BrowserInfo.get().isEdge()) { int styleSheetLength = getStyleSheetLength(url); // Error if there's an empty stylesheet if (styleSheetLength == 0) { diff --git a/client/src/com/vaadin/client/ui/FocusableScrollPanel.java b/client/src/com/vaadin/client/ui/FocusableScrollPanel.java index 9dd9c17675..1ac5a08ccd 100644 --- a/client/src/com/vaadin/client/ui/FocusableScrollPanel.java +++ b/client/src/com/vaadin/client/ui/FocusableScrollPanel.java @@ -74,7 +74,7 @@ public class FocusableScrollPanel extends SimpleFocusablePanel implements style.setPosition(Position.FIXED); style.setTop(0, Unit.PX); style.setLeft(0, Unit.PX); - if (browserInfo.isIE()) { + if (browserInfo.isIE() || browserInfo.isEdge()) { // for #15294: artificially hide little bit more the // focusElement, otherwise IE will make the window to scroll // into it when focused diff --git a/client/src/com/vaadin/client/ui/VRichTextArea.java b/client/src/com/vaadin/client/ui/VRichTextArea.java index 3f63f38067..cb4482f7cb 100644 --- a/client/src/com/vaadin/client/ui/VRichTextArea.java +++ b/client/src/com/vaadin/client/ui/VRichTextArea.java @@ -322,7 +322,7 @@ public class VRichTextArea extends Composite implements Field, KeyPressHandler, if ("
    ".equals(result)) { result = ""; } - } else if (browser.isWebkit()) { + } else if (browser.isWebkit() || browser.isEdge()) { if ("
    ".equals(result) || "


    ".equals(result)) { result = ""; } diff --git a/client/src/com/vaadin/client/ui/VTextArea.java b/client/src/com/vaadin/client/ui/VTextArea.java index 50930f2fee..bb3d3a476b 100644 --- a/client/src/com/vaadin/client/ui/VTextArea.java +++ b/client/src/com/vaadin/client/ui/VTextArea.java @@ -224,16 +224,16 @@ public class VTextArea extends VTextField implements DragImageModifier { protected boolean browserSupportsMaxLengthAttribute() { BrowserInfo info = BrowserInfo.get(); - if (info.isFirefox() && info.isBrowserVersionNewerOrEqual(4, 0)) { + if (info.isFirefox()) { return true; } - if (info.isSafari() && info.isBrowserVersionNewerOrEqual(5, 0)) { + if (info.isSafari()) { return true; } - if (info.isIE() && info.isBrowserVersionNewerOrEqual(10, 0)) { + if (info.isIE10() || info.isIE11() || info.isEdge()) { return true; } - if (info.isAndroid() && info.isBrowserVersionNewerOrEqual(2, 3)) { + if (info.isAndroid()) { return true; } return false; diff --git a/client/src/com/vaadin/client/ui/VWindow.java b/client/src/com/vaadin/client/ui/VWindow.java index c5cab8ff6b..e5e09f9f09 100644 --- a/client/src/com/vaadin/client/ui/VWindow.java +++ b/client/src/com/vaadin/client/ui/VWindow.java @@ -762,11 +762,9 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, modalityCurtain.removeFromParent(); - if (BrowserInfo.get().isIE()) { - // IE leaks memory in certain cases unless we release the reference - // (#9197) - modalityCurtain = null; - } + // IE leaks memory in certain cases unless we release the reference + // (#9197) + modalityCurtain = null; } /* -- cgit v1.2.3 From eecacd40c83217d24ef153a2deaecabf6d01a8fc Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Fri, 31 Jul 2015 09:43:46 +0300 Subject: Reserve enough memory so SDM can be run for more than one browser Change-Id: Ie7424f43248958492de173b2dc8839ecdf8c6df4 --- eclipse/Super Development Mode (vaadin).launch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eclipse/Super Development Mode (vaadin).launch b/eclipse/Super Development Mode (vaadin).launch index 361a456e96..b03337e5ff 100644 --- a/eclipse/Super Development Mode (vaadin).launch +++ b/eclipse/Super Development Mode (vaadin).launch @@ -23,5 +23,5 @@ - + -- cgit v1.2.3 From 15de371e30c6a0213f733289095eeff14d790a17 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Wed, 29 Jul 2015 08:48:55 +0300 Subject: Use correct state classes for Vertical and HorizontalLayout Change-Id: Ifa52a2ff7225076129de9b0f964b82704221dccd --- server/src/com/vaadin/ui/HorizontalLayout.java | 7 +++++++ server/src/com/vaadin/ui/VerticalLayout.java | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/server/src/com/vaadin/ui/HorizontalLayout.java b/server/src/com/vaadin/ui/HorizontalLayout.java index 54569570b9..616fa09225 100644 --- a/server/src/com/vaadin/ui/HorizontalLayout.java +++ b/server/src/com/vaadin/ui/HorizontalLayout.java @@ -15,6 +15,8 @@ */ package com.vaadin.ui; +import com.vaadin.shared.ui.orderedlayout.HorizontalLayoutState; + /** * Horizontal layout * @@ -48,4 +50,9 @@ public class HorizontalLayout extends AbstractOrderedLayout { addComponents(children); } + @Override + protected HorizontalLayoutState getState() { + return (HorizontalLayoutState) super.getState(); + } + } diff --git a/server/src/com/vaadin/ui/VerticalLayout.java b/server/src/com/vaadin/ui/VerticalLayout.java index 12819e50bc..7002fbc7e6 100644 --- a/server/src/com/vaadin/ui/VerticalLayout.java +++ b/server/src/com/vaadin/ui/VerticalLayout.java @@ -15,6 +15,8 @@ */ package com.vaadin.ui; +import com.vaadin.shared.ui.orderedlayout.VerticalLayoutState; + /** * Vertical layout * @@ -48,4 +50,9 @@ public class VerticalLayout extends AbstractOrderedLayout { this(); addComponents(children); } + + @Override + protected VerticalLayoutState getState() { + return (VerticalLayoutState) super.getState(); + } } -- cgit v1.2.3 From 7ce8b74e7fc9ef27c8935806be74807e25888ffd Mon Sep 17 00:00:00 2001 From: Mika Murtojarvi Date: Mon, 3 Aug 2015 10:43:46 +0300 Subject: Update a test for Chrome version. Change-Id: I75c05dd316e9890452d7989d38782b13f607064b --- uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java b/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java index c6ccd1bf4c..ed0f1a9b4f 100644 --- a/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java +++ b/uitest/src/com/vaadin/tests/VerifyBrowserVersionTest.java @@ -40,7 +40,7 @@ public class VerifyBrowserVersionTest extends MultiBrowserTest { // Chrome version does not necessarily match the desired version // because of auto updates... browserIdentifier = getExpectedUserAgentString(getDesiredCapabilities()) - + "43"; + + "44"; } else { browserIdentifier = getExpectedUserAgentString(desiredCapabilities) + desiredCapabilities.getVersion(); -- cgit v1.2.3 From 951101ce39620501ed8aa1751909b7bc697713a3 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Sat, 11 Jul 2015 02:25:29 +0300 Subject: Take margin/border/padding into account when measuring ComboBox in IE (#17002) Change-Id: I8fcf33b78ff239529b794d41088fd9d8aba5c518 --- client/src/com/vaadin/client/ui/VFilterSelect.java | 23 ++++++- .../combobox/ComboboxPopupScrolling.java | 40 ++++++++++++ .../combobox/ComboboxPopupScrollingTest.java | 60 +++++++++++++++++ .../components/combobox/CustomComboBoxElement.java | 40 ++++++++++++ .../components/grid/GridDetailsLocationTest.java | 5 -- .../src/com/vaadin/tests/tb3/AbstractTB3Test.java | 75 +++++++++++++++++++++- 6 files changed, 233 insertions(+), 10 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrolling.java create mode 100644 uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrollingTest.java create mode 100644 uitest/src/com/vaadin/tests/components/combobox/CustomComboBoxElement.java diff --git a/client/src/com/vaadin/client/ui/VFilterSelect.java b/client/src/com/vaadin/client/ui/VFilterSelect.java index 8d9e30ac6e..22eef57901 100644 --- a/client/src/com/vaadin/client/ui/VFilterSelect.java +++ b/client/src/com/vaadin/client/ui/VFilterSelect.java @@ -599,7 +599,8 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, + "]"); Element menuFirstChild = menu.getElement().getFirstChildElement(); - final int naturalMenuWidth = menuFirstChild.getOffsetWidth(); + final int naturalMenuWidth = WidgetUtil + .getRequiredWidth(menuFirstChild); if (popupOuterPadding == -1) { popupOuterPadding = WidgetUtil @@ -612,12 +613,18 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, } if (BrowserInfo.get().isIE()) { + // Must take margin,border,padding manually into account for + // menu element as we measure the element child and set width to + // the element parent + int naturalMenuOuterWidth = naturalMenuWidth + + getMarginBorderPaddingWidth(menu.getElement()); + /* * IE requires us to specify the width for the container * element. Otherwise it will be 100% wide */ - int rootWidth = Math.max(desiredWidth, naturalMenuWidth) - - popupOuterPadding; + int rootWidth = Math.max(desiredWidth - popupOuterPadding, + naturalMenuOuterWidth); getContainerElement().getStyle().setWidth(rootWidth, Unit.PX); } @@ -1283,6 +1290,16 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, sinkEvents(Event.ONPASTE); } + private static int getMarginBorderPaddingWidth(Element element) { + final ComputedStyle s = new ComputedStyle(element); + int[] margin = s.getMargin(); + int[] border = s.getBorder(); + int[] padding = s.getPadding(); + return margin[1] + margin[3] + border[1] + border[3] + padding[1] + + padding[3]; + + } + /* * (non-Javadoc) * diff --git a/uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrolling.java b/uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrolling.java new file mode 100644 index 0000000000..9f1c4b9e03 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrolling.java @@ -0,0 +1,40 @@ +package com.vaadin.tests.components.combobox; + +import com.vaadin.annotations.Theme; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.ui.ComboBox; +import com.vaadin.ui.HorizontalLayout; + +@Theme("valo") +public class ComboboxPopupScrolling extends AbstractTestUIWithLog { + @Override + protected void setup(VaadinRequest request) { + ComboBox combobox = new ComboBox("100px wide combobox"); + combobox.setWidth("100px"); + combobox.addItem("AMERICAN SAMOA"); + combobox.addItem("ANTIGUA AND BARBUDA"); + + ComboBox combobox2 = new ComboBox("250px wide combobox"); + combobox2.setWidth("250px"); + combobox2.addItem("AMERICAN SAMOA"); + combobox2.addItem("ANTIGUA AND BARBUDA"); + + ComboBox combobox3 = new ComboBox("Undefined wide combobox"); + combobox3.setWidth(null); + combobox3.addItem("AMERICAN SAMOA"); + combobox3.addItem("ANTIGUA AND BARBUDA"); + + ComboBox combobox4 = new ComboBox("Another 100px wide combobox"); + combobox4.setWidth("100px"); + for (int i = 0; i < 10; i++) { + combobox4.addItem("AMERICAN SAMOA " + i); + combobox4.addItem("ANTIGUA AND BARBUDA " + i); + } + + HorizontalLayout hl = new HorizontalLayout(combobox, combobox2, + combobox3, combobox4); + addComponent(hl); + } + +} \ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrollingTest.java b/uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrollingTest.java new file mode 100644 index 0000000000..ec5bc088da --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/combobox/ComboboxPopupScrollingTest.java @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.combobox; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class ComboboxPopupScrollingTest extends MultiBrowserTest { + + @Test + public void testNoScrollbarsValo() { + testNoScrollbars("valo"); + } + + @Test + public void testNoScrollbarsChameleon() { + testNoScrollbars("chameleon"); + } + + @Test + public void testNoScrollbarsRuno() { + testNoScrollbars("runo"); + } + + @Test + public void testNoScrollbarsReindeer() { + testNoScrollbars("reindeer"); + } + + private void testNoScrollbars(String theme) { + openTestURL("theme=" + theme); + + for (CustomComboBoxElement cb : $(CustomComboBoxElement.class).all()) { + String caption = cb.getCaption(); + cb.openPopup(); + WebElement popup = cb.getSuggestionPopup(); + WebElement scrollable = popup.findElement(By + .className("v-filterselect-suggestmenu")); + assertNoHorizontalScrollbar(scrollable, caption); + assertNoVerticalScrollbar(scrollable, caption); + } + } + +} diff --git a/uitest/src/com/vaadin/tests/components/combobox/CustomComboBoxElement.java b/uitest/src/com/vaadin/tests/components/combobox/CustomComboBoxElement.java new file mode 100644 index 0000000000..697d5eb932 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/combobox/CustomComboBoxElement.java @@ -0,0 +1,40 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.combobox; + +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.By; +import com.vaadin.testbench.elements.ComboBoxElement; +import com.vaadin.testbench.elementsbase.ServerClass; + +@ServerClass("com.vaadin.ui.ComboBox") +public class CustomComboBoxElement extends ComboBoxElement { + private static org.openqa.selenium.By bySuggestionPopup = By + .vaadin("#popup"); + + public WebElement getSuggestionPopup() { + ensurePopupOpen(); + return findElement(bySuggestionPopup); + } + + private void ensurePopupOpen() { + if (!isElementPresent(bySuggestionPopup)) { + openPopup(); + } + } + +} diff --git a/uitest/src/com/vaadin/tests/components/grid/GridDetailsLocationTest.java b/uitest/src/com/vaadin/tests/components/grid/GridDetailsLocationTest.java index f20cc0f6f4..33f66d35be 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridDetailsLocationTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridDetailsLocationTest.java @@ -23,7 +23,6 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.openqa.selenium.By; -import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.Keys; import org.openqa.selenium.StaleElementReferenceException; import org.openqa.selenium.WebDriver; @@ -313,10 +312,6 @@ public class GridDetailsLocationTest extends MultiBrowserTest { checkBoxElement.click(5, 5); } - private Object executeScript(String string, Object... param) { - return ((JavascriptExecutor) getDriver()).executeScript(string, param); - } - private void scrollAndToggle(int row) { setRow(row); getScrollAndToggle().click(); diff --git a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java index 842fcbb859..0e983ab959 100644 --- a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java +++ b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java @@ -368,8 +368,8 @@ public abstract class AbstractTB3Test extends ParallelTest { * {@link org.openqa.selenium.JavascriptExecutor#executeScript(String, Object...)} * returns */ - protected Object executeScript(String script) { - return ((JavascriptExecutor) getDriver()).executeScript(script); + protected Object executeScript(String script, Object... args) { + return ((JavascriptExecutor) getDriver()).executeScript(script, args); } /** @@ -1105,4 +1105,75 @@ public abstract class AbstractTB3Test extends ParallelTest { return isElementPresent(By.className("v-debugwindow")); } + protected void assertNoHorizontalScrollbar(WebElement element, + String errorMessage) { + // IE rounds clientWidth/clientHeight down and scrollHeight/scrollWidth + // up, so using clientWidth/clientHeight will fail if the element height + // is not an integer + int clientWidth = getClientWidth(element); + int scrollWidth = getScrollWidth(element); + boolean hasScrollbar = scrollWidth > clientWidth; + + Assert.assertFalse( + "The element should not have a horizontal scrollbar (scrollWidth: " + + scrollWidth + ", clientWidth: " + clientWidth + "): " + + errorMessage, hasScrollbar); + } + + protected void assertNoVerticalScrollbar(WebElement element, + String errorMessage) { + // IE rounds clientWidth/clientHeight down and scrollHeight/scrollWidth + // up, so using clientWidth/clientHeight will fail if the element height + // is not an integer + int clientHeight = getClientHeight(element); + int scrollHeight = getScrollHeight(element); + boolean hasScrollbar = scrollHeight > clientHeight; + + Assert.assertFalse( + "The element should not have a vertical scrollbar (scrollHeight: " + + scrollHeight + ", clientHeight: " + clientHeight + + "): " + errorMessage, hasScrollbar); + } + + protected int getScrollHeight(WebElement element) { + return ((Number) executeScript("return arguments[0].scrollHeight;", + element)).intValue(); + } + + protected int getScrollWidth(WebElement element) { + return ((Number) executeScript("return arguments[0].scrollWidth;", + element)).intValue(); + } + + /** + * Returns client height rounded up instead of as double because of IE9 + * issues: https://dev.vaadin.com/ticket/18469 + */ + protected int getClientHeight(WebElement e) { + String script; + if (BrowserUtil.isIE8(getDesiredCapabilities())) { + script = "return arguments[0].clientHeight;"; // + } else { + script = "var cs = window.getComputedStyle(arguments[0]);" + + "return Math.ceil(parseFloat(cs.height)+parseFloat(cs.paddingTop)+parseFloat(cs.paddingBottom));"; + } + return ((Number) executeScript(script, e)).intValue(); + } + + /** + * Returns client width rounded up instead of as double because of IE9 + * issues: https://dev.vaadin.com/ticket/18469 + */ + protected int getClientWidth(WebElement e) { + String script; + if (BrowserUtil.isIE8(getDesiredCapabilities())) { + script = "return arguments[0].clientWidth;"; + } else { + script = "var cs = window.getComputedStyle(arguments[0]);" + + "var h = parseFloat(cs.width)+parseFloat(cs.paddingLeft)+parseFloat(cs.paddingRight);" + + "return Math.ceil(h);"; + } + + return ((Number) executeScript(script, e)).intValue(); + } } -- cgit v1.2.3 From ae9adec0467ea88fd12e0295791b77f5ef3010ae Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Wed, 15 Jul 2015 20:37:20 +0300 Subject: Ensure server side focus is applied when opening a window (#17731) This change removes all deferred commands for handling window focus to ensure the focus events are triggered in the expected order Change-Id: I46598243d1022b82cf64f0e60169f52248c3cc72 --- client/src/com/vaadin/client/ui/VUI.java | 10 +--- client/src/com/vaadin/client/ui/VWindow.java | 21 ++++---- .../window/OpenModalWindowAndFocusField.java | 62 ++++++++++++++++++++++ .../window/OpenModalWindowAndFocusFieldTest.java | 48 +++++++++++++++++ .../src/com/vaadin/tests/tb3/AbstractTB3Test.java | 19 +++++++ 5 files changed, 139 insertions(+), 21 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusField.java create mode 100644 uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusFieldTest.java diff --git a/client/src/com/vaadin/client/ui/VUI.java b/client/src/com/vaadin/client/ui/VUI.java index 0c1b83ab0f..963d83a6e6 100644 --- a/client/src/com/vaadin/client/ui/VUI.java +++ b/client/src/com/vaadin/client/ui/VUI.java @@ -18,7 +18,6 @@ package com.vaadin.client.ui; import java.util.ArrayList; -import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.Element; import com.google.gwt.event.dom.client.HasScrollHandlers; @@ -44,8 +43,8 @@ import com.vaadin.client.ConnectorMap; import com.vaadin.client.Focusable; import com.vaadin.client.LayoutManager; import com.vaadin.client.Profiler; -import com.vaadin.client.WidgetUtil; import com.vaadin.client.VConsole; +import com.vaadin.client.WidgetUtil; import com.vaadin.client.ui.ShortcutActionHandler.ShortcutActionHandlerOwner; import com.vaadin.client.ui.TouchScrollDelegate.TouchScrollHandler; import com.vaadin.client.ui.ui.UIConnector; @@ -515,13 +514,6 @@ public class VUI extends SimplePanel implements ResizeHandler, public void focusStoredElement() { if (storedFocus != null) { storedFocus.focus(); - - Scheduler.get().scheduleDeferred(new ScheduledCommand() { - @Override - public void execute() { - storedFocus.focus(); - } - }); } } diff --git a/client/src/com/vaadin/client/ui/VWindow.java b/client/src/com/vaadin/client/ui/VWindow.java index e5e09f9f09..e34e12a20b 100644 --- a/client/src/com/vaadin/client/ui/VWindow.java +++ b/client/src/com/vaadin/client/ui/VWindow.java @@ -562,17 +562,10 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, } private static void focusTopmostModalWindow() { - // If we call focus() directly without scheduling, it does not work in - // IE and FF. - Scheduler.get().scheduleDeferred(new ScheduledCommand() { - @Override - public void execute() { - VWindow topmost = getTopmostWindow(); - if ((topmost != null) && (topmost.vaadinModality)) { - topmost.focus(); - } - } - }); + VWindow topmost = getTopmostWindow(); + if ((topmost != null) && (topmost.vaadinModality)) { + topmost.focus(); + } } @Override @@ -1373,7 +1366,11 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, @Override public void focus() { - contentPanel.focus(); + // We don't want to use contentPanel.focus() as that will use a timer in + // Chrome/Safari and ultimately run focus events in the wrong order when + // opening a modal window and focusing some other component at the same + // time + contentPanel.getElement().focus(); } private int getDecorationHeight() { diff --git a/uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusField.java b/uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusField.java new file mode 100644 index 0000000000..1c82a3de02 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusField.java @@ -0,0 +1,62 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.window; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.TextArea; +import com.vaadin.ui.Window; + +public class OpenModalWindowAndFocusField extends AbstractTestUIWithLog { + + @Override + protected void setup(VaadinRequest request) { + Button button = new Button("Open modal and focus textarea"); + button.setId("openFocus"); + button.addClickListener(new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + open(true); + } + }); + addComponent(button); + + button = new Button("Only open modal"); + button.setId("open"); + button.addClickListener(new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + open(false); + } + + }); + addComponent(button); + + } + + private void open(boolean focus) { + Window wind = new Window(); + wind.setModal(true); + TextArea ta = new TextArea(); + wind.setContent(ta); + addWindow(wind); + if (focus) { + ta.focus(); + } + } +} diff --git a/uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusFieldTest.java b/uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusFieldTest.java new file mode 100644 index 0000000000..5dba1c3285 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/window/OpenModalWindowAndFocusFieldTest.java @@ -0,0 +1,48 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.window; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.testbench.elements.TextAreaElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class OpenModalWindowAndFocusFieldTest extends MultiBrowserTest { + + @Test + public void openModalAndFocusField() { + openTestURL(); + $(ButtonElement.class).id("openFocus").click(); + TextAreaElement textArea = $(TextAreaElement.class).first(); + + assertElementsEquals(textArea, getActiveElement()); + } + + @Test + public void openModal() { + openTestURL(); + $(ButtonElement.class).id("open").click(); + // WindowElement window = $(WindowElement.class).first(); + WebElement windowFocusElement = findElement(By + .xpath("//div[@class='v-window-contents']/div[@class='v-scrollable']")); + + assertElementsEquals(windowFocusElement, getActiveElement()); + } + +} diff --git a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java index 0e983ab959..2e3854cb2b 100644 --- a/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java +++ b/uitest/src/com/vaadin/tests/tb3/AbstractTB3Test.java @@ -50,6 +50,7 @@ import org.openqa.selenium.interactions.Keyboard; import org.openqa.selenium.interactions.Mouse; import org.openqa.selenium.interactions.internal.Coordinates; import org.openqa.selenium.internal.Locatable; +import org.openqa.selenium.internal.WrapsElement; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.remote.HttpCommandExecutor; import org.openqa.selenium.remote.RemoteWebDriver; @@ -1176,4 +1177,22 @@ public abstract class AbstractTB3Test extends ParallelTest { return ((Number) executeScript(script, e)).intValue(); } + + protected void assertElementsEquals(WebElement expectedElement, + WebElement actualElement) { + while (expectedElement instanceof WrapsElement) { + expectedElement = ((WrapsElement) expectedElement) + .getWrappedElement(); + } + while (actualElement instanceof WrapsElement) { + actualElement = ((WrapsElement) actualElement).getWrappedElement(); + } + + Assert.assertEquals(expectedElement, actualElement); + } + + protected WebElement getActiveElement() { + return (WebElement) executeScript("return document.activeElement;"); + + } } -- cgit v1.2.3 From f3ae913aa05fedd33c5b706f75cf6c37310a3f84 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 4 Aug 2015 00:16:04 +0300 Subject: Fix NPE when clicking and move handler is not set (#8718) Change-Id: I13dfe9344d7ca516d41145e4c35fc45c620cac56 --- .../client/ui/calendar/schedule/DateCellDayEvent.java | 9 +++++++-- .../vaadin/client/ui/calendar/schedule/SimpleDayCell.java | 7 +++++-- .../tests/components/calendar/NullEventMoveHandler.java | 14 ++++++++++++-- .../components/calendar/NullEventMoveHandlerTest.java | 15 +++++++++++++++ 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java b/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java index 1a54fe0454..55834397d3 100644 --- a/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java +++ b/client/src/com/vaadin/client/ui/calendar/schedule/DateCellDayEvent.java @@ -268,8 +268,13 @@ public class DateCellDayEvent extends FocusableHTML implements } int endX = event.getClientX(); int endY = event.getClientY(); - int xDiff = startX - endX; - int yDiff = startY - endY; + int xDiff = 0, yDiff = 0; + if (startX != -1 && startY != -1) { + // Drag started + xDiff = startX - endX; + yDiff = startY - endY; + } + startX = -1; startY = -1; mouseMoveStarted = false; diff --git a/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java b/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java index 3bf6930933..158241337b 100644 --- a/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java +++ b/client/src/com/vaadin/client/ui/calendar/schedule/SimpleDayCell.java @@ -392,8 +392,11 @@ public class SimpleDayCell extends FocusableFlowPanel implements int endX = event.getClientX(); int endY = event.getClientY(); - int xDiff = startX - endX; - int yDiff = startY - endY; + int xDiff = 0, yDiff = 0; + if (startX != -1 && startY != -1) { + xDiff = startX - endX; + yDiff = startY - endY; + } startX = -1; startY = -1; prevDayDiff = 0; diff --git a/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandler.java b/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandler.java index c2dfdb26c1..40dd43abb2 100644 --- a/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandler.java +++ b/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandler.java @@ -5,17 +5,27 @@ import java.text.SimpleDateFormat; import java.util.Locale; import com.vaadin.server.VaadinRequest; -import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.tests.components.AbstractTestUIWithLog; import com.vaadin.ui.Calendar; import com.vaadin.ui.components.calendar.CalendarComponentEvents; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventClick; +import com.vaadin.ui.components.calendar.CalendarComponentEvents.EventClickHandler; import com.vaadin.ui.components.calendar.event.BasicEvent; -public class NullEventMoveHandler extends AbstractTestUI { +public class NullEventMoveHandler extends AbstractTestUIWithLog { @Override protected void setup(VaadinRequest request) { Calendar calendar = getCalendar(); calendar.setHandler((CalendarComponentEvents.EventMoveHandler) null); + calendar.setHandler(new EventClickHandler() { + + @Override + public void eventClick(EventClick event) { + log("Clicked on " + event.getCalendarEvent().getCaption()); + + } + }); addComponent(calendar); } diff --git a/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandlerTest.java b/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandlerTest.java index c40cd9ce97..156100310c 100644 --- a/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandlerTest.java +++ b/uitest/src/com/vaadin/tests/components/calendar/NullEventMoveHandlerTest.java @@ -3,6 +3,7 @@ package com.vaadin.tests.components.calendar; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; +import org.junit.Assert; import org.junit.Test; import org.openqa.selenium.By; import org.openqa.selenium.WebElement; @@ -22,12 +23,26 @@ public class NullEventMoveHandlerTest extends DndActionsTest { assertEventCannotBeMoved(); } + @Test + public void eventIsClickableWhenNotMovableInMonthView() { + getEvent().click(); + Assert.assertEquals("1. Clicked on foo", getLogRow(0)); + } + @Test public void eventIsNotMovableInWeekView() { openWeekView(); assertEventCannotBeMoved(); } + @Test + public void eventIsClickableWhenNotMovableInWeekView() { + openWeekView(); + getEvent().findElement(By.className("v-calendar-event-caption")) + .click(); + Assert.assertEquals("1. Clicked on foo", getLogRow(0)); + } + private void assertEventCannotBeMoved() { int originalPosition = getEventXPosition(); -- cgit v1.2.3 From 59c212cae4bf5787502cd733ff3db86f222459a4 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Wed, 25 Feb 2015 09:55:55 +0200 Subject: Test for multiple manual push in same access block (#15330, #16919) Change-Id: I48ca1e392b9ec79cbd907a002d228540a355b116 --- .../vaadin/tests/push/ManualLongPollingPushUI.java | 94 ++++++++++++++++++++++ .../tests/push/ManualLongPollingPushUITest.java | 54 +++++++++++++ 2 files changed, 148 insertions(+) create mode 100644 uitest/src/com/vaadin/tests/push/ManualLongPollingPushUI.java create mode 100644 uitest/src/com/vaadin/tests/push/ManualLongPollingPushUITest.java diff --git a/uitest/src/com/vaadin/tests/push/ManualLongPollingPushUI.java b/uitest/src/com/vaadin/tests/push/ManualLongPollingPushUI.java new file mode 100644 index 0000000000..190f6daa24 --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/ManualLongPollingPushUI.java @@ -0,0 +1,94 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.push; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import com.vaadin.annotations.Push; +import com.vaadin.server.VaadinRequest; +import com.vaadin.shared.communication.PushMode; +import com.vaadin.shared.ui.ui.Transport; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; + +@Push(value = PushMode.MANUAL, transport = Transport.LONG_POLLING) +public class ManualLongPollingPushUI extends AbstractTestUIWithLog { + + ExecutorService executor = Executors.newFixedThreadPool(1); + + @Override + protected void setup(VaadinRequest request) { + Button b = new Button("Manual push after 1s", + new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + executor.submit(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + access(new Runnable() { + + @Override + public void run() { + log("Logged after 1s, followed by manual push"); + push(); + } + }); + + } + }); + } + }); + addComponent(b); + + b = new Button("Double manual push after 1s", + new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + executor.submit(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + access(new Runnable() { + + @Override + public void run() { + log("First message logged after 1s, followed by manual push"); + push(); + log("Second message logged after 1s, followed by manual push"); + push(); + } + }); + + } + }); + } + }); + addComponent(b); + + } + +} diff --git a/uitest/src/com/vaadin/tests/push/ManualLongPollingPushUITest.java b/uitest/src/com/vaadin/tests/push/ManualLongPollingPushUITest.java new file mode 100644 index 0000000000..096204ff75 --- /dev/null +++ b/uitest/src/com/vaadin/tests/push/ManualLongPollingPushUITest.java @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.push; + +import org.junit.Test; +import org.openqa.selenium.WebDriver; +import org.openqa.selenium.support.ui.ExpectedCondition; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class ManualLongPollingPushUITest extends SingleBrowserTest { + + @Test + public void doubleManualPushDoesNotFreezeApplication() { + openTestURL(); + $(ButtonElement.class).caption("Double manual push after 1s").first() + .click(); + waitUntilLogText("2. Second message logged after 1s, followed by manual push"); + $(ButtonElement.class).caption("Manual push after 1s").first().click(); + waitUntilLogText("3. Logged after 1s, followed by manual push"); + } + + private void waitUntilLogText(final String expected) { + waitUntil(new ExpectedCondition() { + private String actual; + + @Override + public Boolean apply(WebDriver arg0) { + actual = getLogRow(0); + return expected.equals(actual); + } + + @Override + public String toString() { + return String.format("log text to become '%s' (was: '%s')", + expected, actual); + } + }); + } +} -- cgit v1.2.3 From 3951ba9c2d751e3719699c546f530859d2b593ee Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Sat, 11 Jul 2015 21:12:39 +0300 Subject: Restrict old IE fix to IE <= 10 (#17002) Change-Id: Iab4ecf3ef0616471743874531264f2fe6868f133 --- client/src/com/vaadin/client/ui/VFilterSelect.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/src/com/vaadin/client/ui/VFilterSelect.java b/client/src/com/vaadin/client/ui/VFilterSelect.java index 22eef57901..d756c88f79 100644 --- a/client/src/com/vaadin/client/ui/VFilterSelect.java +++ b/client/src/com/vaadin/client/ui/VFilterSelect.java @@ -612,7 +612,8 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, menuFirstChild.getStyle().setWidth(100, Unit.PCT); } - if (BrowserInfo.get().isIE()) { + if (BrowserInfo.get().isIE() + && BrowserInfo.get().getBrowserMajorVersion() < 11) { // Must take margin,border,padding manually into account for // menu element as we measure the element child and set width to // the element parent -- cgit v1.2.3 From 50e13188aa372b0ad50c7279bcb3f18706897c23 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Mon, 3 Aug 2015 23:02:47 +0300 Subject: Attach Window in hierarchy change as required (#18502) Change-Id: Ia9ca393480b80c19e5391bce034534bde31f3a81 --- .../src/com/vaadin/client/ui/ui/UIConnector.java | 14 +++++++ .../vaadin/client/ui/window/WindowConnector.java | 4 -- .../tests/components/window/GridInWindow.java | 49 ++++++++++++++++++++++ .../tests/components/window/GridInWindowTest.java | 36 ++++++++++++++++ .../tests/tb3/newelements/WindowElement.java | 10 +++++ 5 files changed, 109 insertions(+), 4 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/window/GridInWindow.java create mode 100644 uitest/src/com/vaadin/tests/components/window/GridInWindowTest.java diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java index cfb444ada6..6d98e2108a 100644 --- a/client/src/com/vaadin/client/ui/ui/UIConnector.java +++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java @@ -71,6 +71,7 @@ import com.vaadin.client.ui.ShortcutActionHandler; import com.vaadin.client.ui.VNotification; import com.vaadin.client.ui.VOverlay; import com.vaadin.client.ui.VUI; +import com.vaadin.client.ui.VWindow; import com.vaadin.client.ui.layout.MayScrollChildren; import com.vaadin.client.ui.window.WindowConnector; import com.vaadin.server.Page.Styles; @@ -669,6 +670,19 @@ public class UIConnector extends AbstractSingleComponentContainerConnector if (c instanceof WindowConnector) { WindowConnector wc = (WindowConnector) c; wc.setWindowOrderAndPosition(); + VWindow window = wc.getWidget(); + if (!window.isAttached()) { + + // Attach so that all widgets inside the Window are attached + // when their onStateChange is run + + // Made invisible here for legacy reasons and made visible + // at the end of stateChange. This dance could probably be + // removed + window.setVisible(false); + window.show(); + } + } } diff --git a/client/src/com/vaadin/client/ui/window/WindowConnector.java b/client/src/com/vaadin/client/ui/window/WindowConnector.java index 8c23f712ad..9ea3c8bb68 100644 --- a/client/src/com/vaadin/client/ui/window/WindowConnector.java +++ b/client/src/com/vaadin/client/ui/window/WindowConnector.java @@ -356,10 +356,6 @@ public class WindowConnector extends AbstractSingleComponentContainerConnector 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.windowMode == WindowMode.NORMAL; window.setResizable(resizeable); diff --git a/uitest/src/com/vaadin/tests/components/window/GridInWindow.java b/uitest/src/com/vaadin/tests/components/window/GridInWindow.java new file mode 100644 index 0000000000..918a991cc1 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/window/GridInWindow.java @@ -0,0 +1,49 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.window; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.ui.Button; +import com.vaadin.ui.Grid; +import com.vaadin.ui.Window; + +public class GridInWindow extends AbstractTestUIWithLog { + + @Override + protected void setup(VaadinRequest request) { + final Grid grid = new Grid(); + + grid.addColumn("Hidable column").setHidable(true); + grid.addRow("Close and reopen and it vanishes"); + + Button popupButton = new Button("Open PopUp", + new Button.ClickListener() { + @Override + public void buttonClick(Button.ClickEvent event) { + Window subWindow = new Window("Sub-window"); + subWindow.setContent(grid); + subWindow.setWidth(600, Unit.PIXELS); + subWindow.setWidth(400, Unit.PIXELS); + getUI().addWindow(subWindow); + } + }); + + addComponent(popupButton); + + } + +} diff --git a/uitest/src/com/vaadin/tests/components/window/GridInWindowTest.java b/uitest/src/com/vaadin/tests/components/window/GridInWindowTest.java new file mode 100644 index 0000000000..301a7c60e4 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/window/GridInWindowTest.java @@ -0,0 +1,36 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.window; + +import org.junit.Test; + +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.tests.tb3.SingleBrowserTest; +import com.vaadin.tests.tb3.newelements.WindowElement; + +public class GridInWindowTest extends SingleBrowserTest { + + @Test + public void ensureAttachInHierachyChange() { + openTestURL("debug"); + $(ButtonElement.class).first().click(); + assertNoErrorNotifications(); + $(WindowElement.class).first().close(); + assertNoErrorNotifications(); + $(ButtonElement.class).first().click(); + assertNoErrorNotifications(); + } +} diff --git a/uitest/src/com/vaadin/tests/tb3/newelements/WindowElement.java b/uitest/src/com/vaadin/tests/tb3/newelements/WindowElement.java index 34344324d0..784d203ab0 100644 --- a/uitest/src/com/vaadin/tests/tb3/newelements/WindowElement.java +++ b/uitest/src/com/vaadin/tests/tb3/newelements/WindowElement.java @@ -14,6 +14,7 @@ public class WindowElement extends com.vaadin.testbench.elements.WindowElement { private final String restoreBoxClass = "v-window-restorebox"; private final String maximizeBoxClass = "v-window-maximizebox"; + private final String closeBoxClass = "v-window-closebox"; public void restore() { if (isMaximized()) { @@ -63,4 +64,13 @@ public class WindowElement extends com.vaadin.testbench.elements.WindowElement { public String getCaption() { return findElement(By.className("v-window-header")).getText(); } + + private WebElement getCloseButton() { + return findElement(By.className(closeBoxClass)); + } + + public void close() { + getCloseButton().click(); + + } } -- cgit v1.2.3 From f6d075df5207e02b3e96a35943c022c2c2f29bc1 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 16 Jul 2015 00:20:26 +0300 Subject: Take margin/border/padding into account when measuring TabSheet (#18471) Change-Id: Id6fed9155128ed9134b3d4949b80fc605e5ae62f --- client/src/com/vaadin/client/ComputedStyle.java | 51 ++++++++++++++++++++++ client/src/com/vaadin/client/ui/VTabsheet.java | 10 ++++- .../components/tabsheet/TabSheetInSplitPanel.java | 43 ++++++++++++++++++ .../tabsheet/TabSheetInSplitPanelTest.java | 43 ++++++++++++++++++ 4 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanel.java create mode 100644 uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanelTest.java diff --git a/client/src/com/vaadin/client/ComputedStyle.java b/client/src/com/vaadin/client/ComputedStyle.java index b11ba4b26a..1391a84bfe 100644 --- a/client/src/com/vaadin/client/ComputedStyle.java +++ b/client/src/com/vaadin/client/ComputedStyle.java @@ -280,4 +280,55 @@ public class ComputedStyle { return parseFloat(value); }-*/; + /** + * Returns the sum of the top and bottom border width + * + * @since + * @return the sum of the top and bottom border + */ + public double getBorderHeight() { + double borderHeight = getDoubleProperty("borderTopWidth"); + borderHeight += getDoubleProperty("borderBottomWidth"); + + return borderHeight; + } + + /** + * Returns the sum of the left and right border width + * + * @since + * @return the sum of the left and right border + */ + public double getBorderWidth() { + double borderWidth = getDoubleProperty("borderLeftWidth"); + borderWidth += getDoubleProperty("borderRightWidth"); + + return borderWidth; + } + + /** + * Returns the sum of the top and bottom padding + * + * @since + * @return the sum of the top and bottom padding + */ + public double getPaddingHeight() { + double paddingHeight = getDoubleProperty("paddingTop"); + paddingHeight += getDoubleProperty("paddingBottom"); + + return paddingHeight; + } + + /** + * Returns the sum of the top and bottom padding + * + * @since + * @return the sum of the left and right padding + */ + public double getPaddingWidth() { + double paddingWidth = getDoubleProperty("paddingLeft"); + paddingWidth += getDoubleProperty("paddingRight"); + + return paddingWidth; + } } diff --git a/client/src/com/vaadin/client/ui/VTabsheet.java b/client/src/com/vaadin/client/ui/VTabsheet.java index ded9977f5e..e196870348 100644 --- a/client/src/com/vaadin/client/ui/VTabsheet.java +++ b/client/src/com/vaadin/client/ui/VTabsheet.java @@ -61,11 +61,12 @@ import com.google.gwt.user.client.ui.impl.FocusImpl; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.BrowserInfo; import com.vaadin.client.ComponentConnector; +import com.vaadin.client.ComputedStyle; import com.vaadin.client.Focusable; import com.vaadin.client.TooltipInfo; -import com.vaadin.client.WidgetUtil; import com.vaadin.client.VCaption; import com.vaadin.client.VTooltip; +import com.vaadin.client.WidgetUtil; import com.vaadin.client.ui.aria.AriaHelper; import com.vaadin.shared.AbstractComponentState; import com.vaadin.shared.ComponentConstants; @@ -1227,8 +1228,13 @@ public class VTabsheet extends VTabsheetBase implements Focusable, SubPartAware public void updateContentNodeHeight() { if (!isDynamicHeight()) { int contentHeight = getOffsetHeight(); - contentHeight -= DOM.getElementPropertyInt(deco, "offsetHeight"); + contentHeight -= deco.getOffsetHeight(); contentHeight -= tb.getOffsetHeight(); + + ComputedStyle cs = new ComputedStyle(contentNode); + contentHeight -= Math.ceil(cs.getPaddingHeight()); + contentHeight -= Math.ceil(cs.getBorderHeight()); + if (contentHeight < 0) { contentHeight = 0; } diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanel.java b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanel.java new file mode 100644 index 0000000000..b2313020a3 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanel.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.tabsheet; + +import com.vaadin.annotations.Theme; +import com.vaadin.server.VaadinRequest; +import com.vaadin.ui.Label; +import com.vaadin.ui.TabSheet; +import com.vaadin.ui.UI; +import com.vaadin.ui.VerticalSplitPanel; +import com.vaadin.ui.themes.ValoTheme; + +@Theme("valo") +public class TabSheetInSplitPanel extends UI { + + @Override + protected void init(VaadinRequest request) { + VerticalSplitPanel verticalSplitter = new VerticalSplitPanel(); + setContent(verticalSplitter); + verticalSplitter.setSizeFull(); + TabSheet t = new TabSheet(); + t.setHeight("100%"); + t.addTab(new Label("Hello in tab"), "Hello tab"); + t.setStyleName(ValoTheme.TABSHEET_FRAMED); + verticalSplitter.addComponent(t); + verticalSplitter.addComponent(new Label("Hello")); + + } + +} diff --git a/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanelTest.java b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanelTest.java new file mode 100644 index 0000000000..8070133bde --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/tabsheet/TabSheetInSplitPanelTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.tabsheet; + +import java.util.List; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.elements.TabSheetElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class TabSheetInSplitPanelTest extends MultiBrowserTest { + + @Test + public void ensureNoScrollbars() { + openTestURL(); + TabSheetElement ts = $(TabSheetElement.class).first(); + List scrollables = ts.findElements(By + .xpath("//*[contains(@class,'v-scrollable')]")); + for (WebElement scrollable : scrollables) { + assertNoHorizontalScrollbar(scrollable, + "Element should not have a horizontal scrollbar"); + assertNoVerticalScrollbar(scrollable, + "Element should not have a vertical scrollbar"); + } + } + +} -- cgit v1.2.3 From 3c7eab0d5810a16a31778b22af22e8a34251db1a Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Thu, 9 Jul 2015 23:23:35 +0300 Subject: Update Select all -CheckBox from server and partial selections (#17590) Change-Id: I8f4986455029fc3b997ec5fee8916fa118a487ca --- .../vaadin/client/connectors/GridConnector.java | 21 ++++++ client/src/com/vaadin/client/widgets/Grid.java | 78 +++++++++++++--------- server/src/com/vaadin/ui/Grid.java | 17 +++++ .../com/vaadin/shared/ui/grid/GridClientRpc.java | 11 +++ .../grid/basicfeatures/GridBasicFeatures.java | 20 ++++++ .../basicfeatures/server/GridSelectionTest.java | 40 +++++++++++ 6 files changed, 155 insertions(+), 32 deletions(-) diff --git a/client/src/com/vaadin/client/connectors/GridConnector.java b/client/src/com/vaadin/client/connectors/GridConnector.java index a99b227abe..15acbc0d5a 100644 --- a/client/src/com/vaadin/client/connectors/GridConnector.java +++ b/client/src/com/vaadin/client/connectors/GridConnector.java @@ -33,6 +33,7 @@ import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.user.client.Timer; +import com.google.gwt.user.client.ui.CheckBox; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ComponentConnector; import com.vaadin.client.ConnectorHierarchyChangeEvent; @@ -681,6 +682,26 @@ public class GridConnector extends AbstractHasComponentsConnector implements public void recalculateColumnWidths() { getWidget().recalculateColumnWidths(); } + + @Override + public void setSelectAll(boolean allSelected) { + if (selectionModel instanceof SelectionModel.Multi + && selectionModel.getSelectionColumnRenderer() != null) { + final Widget widget; + try { + HeaderRow defaultHeaderRow = getWidget() + .getDefaultHeaderRow(); + if (defaultHeaderRow != null) { + widget = defaultHeaderRow.getCell( + getWidget().getColumn(0)).getWidget(); + ((CheckBox) widget).setValue(allSelected, false); + } + } catch (Exception e) { + getLogger().warning( + "Problems finding select all checkbox."); + } + } + } }); getWidget().addSelectionHandler(internalSelectionChangeHandler); diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 377943ed61..8db6e9a55a 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -2377,6 +2377,7 @@ public class Grid extends ResizeComposite implements private boolean initDone = false; private boolean selected = false; + private CheckBox selectAllCheckBox; SelectionColumn(final Renderer selectColumnRenderer) { super(selectColumnRenderer); @@ -2401,41 +2402,55 @@ public class Grid extends ResizeComposite implements * exist. */ final SelectionModel.Multi model = (Multi) getSelectionModel(); - final CheckBox checkBox = GWT.create(CheckBox.class); - checkBox.addValueChangeHandler(new ValueChangeHandler() { - @Override - public void onValueChange(ValueChangeEvent event) { - if (event.getValue()) { - fireEvent(new SelectAllEvent(model)); - selected = true; - } else { - model.deselectAll(); - selected = false; - } - } - }); - checkBox.setValue(selected); - selectionCell.setWidget(checkBox); - // Select all with space when "select all" cell is active - addHeaderKeyUpHandler(new HeaderKeyUpHandler() { - @Override - public void onKeyUp(GridKeyUpEvent event) { - if (event.getNativeKeyCode() != KeyCodes.KEY_SPACE) { - return; - } - HeaderRow targetHeaderRow = getHeader().getRow( - event.getFocusedCell().getRowIndex()); - if (!targetHeaderRow.isDefault()) { - return; + if (selectAllCheckBox == null) { + selectAllCheckBox = GWT.create(CheckBox.class); + selectAllCheckBox + .addValueChangeHandler(new ValueChangeHandler() { + + @Override + public void onValueChange( + ValueChangeEvent event) { + if (event.getValue()) { + fireEvent(new SelectAllEvent(model)); + selected = true; + } else { + model.deselectAll(); + selected = false; + } + } + }); + selectAllCheckBox.setValue(selected); + + // Select all with space when "select all" cell is active + addHeaderKeyUpHandler(new HeaderKeyUpHandler() { + @Override + public void onKeyUp(GridKeyUpEvent event) { + if (event.getNativeKeyCode() != KeyCodes.KEY_SPACE) { + return; + } + HeaderRow targetHeaderRow = getHeader().getRow( + event.getFocusedCell().getRowIndex()); + if (!targetHeaderRow.isDefault()) { + return; + } + if (event.getFocusedCell().getColumn() == SelectionColumn.this) { + // Send events to ensure state is updated + selectAllCheckBox.setValue( + !selectAllCheckBox.getValue(), true); + } } - if (event.getFocusedCell().getColumn() == SelectionColumn.this) { - // Send events to ensure row selection state is - // updated - checkBox.setValue(!checkBox.getValue(), true); + }); + } else { + for (HeaderRow row : header.getRows()) { + if (row.getCell(this).getType() == GridStaticCellType.WIDGET) { + // Detach from old header. + row.getCell(this).setText(""); } } - }); + } + + selectionCell.setWidget(selectAllCheckBox); } @Override @@ -2497,7 +2512,6 @@ public class Grid extends ResizeComposite implements super.setEditable(editable); return this; } - } /** diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java index ea973bb3ba..3e4a78db9d 100644 --- a/server/src/com/vaadin/ui/Grid.java +++ b/server/src/com/vaadin/ui/Grid.java @@ -1068,6 +1068,8 @@ public class Grid extends AbstractComponent implements SelectionNotifier, private int selectionLimit = DEFAULT_MAX_SELECTIONS; + private boolean allSelected; + @Override public boolean select(final Object... itemIds) throws IllegalArgumentException { @@ -1113,6 +1115,9 @@ public class Grid extends AbstractComponent implements SelectionNotifier, } fireSelectionEvent(oldSelection, selection); } + + updateAllSelectedState(); + return selectionWillChange; } @@ -1178,6 +1183,9 @@ public class Grid extends AbstractComponent implements SelectionNotifier, selection.removeAll(itemIds); fireSelectionEvent(oldSelection, selection); } + + updateAllSelectedState(); + return hasCommonElements; } @@ -1258,6 +1266,8 @@ public class Grid extends AbstractComponent implements SelectionNotifier, fireSelectionEvent(oldSelection, selection); } + updateAllSelectedState(); + return changed; } @@ -1271,6 +1281,13 @@ public class Grid extends AbstractComponent implements SelectionNotifier, "Vararg array of itemIds may not be null"); } } + + private void updateAllSelectedState() { + if (allSelected != selection.size() >= selectionLimit) { + allSelected = selection.size() >= selectionLimit; + grid.getRpcProxy(GridClientRpc.class).setSelectAll(allSelected); + } + } } /** diff --git a/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java b/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java index ac1b1d5a78..cf4e95d078 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java @@ -55,4 +55,15 @@ public interface GridClientRpc extends ClientRpc { * Command client Grid to recalculate column widths. */ public void recalculateColumnWidths(); + + /** + * Informs the Grid that all items have been selected or not selected on the + * server side. + * + * @since + * @param allSelected + * true to check the select all checkbox, + * false to uncheck it. + */ + public void setSelectAll(boolean allSelected); } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index ef51cdf446..6511866897 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -683,6 +683,26 @@ public class GridBasicFeatures extends AbstractComponentTest { c.setColumnReorderingAllowed(value); } }); + + createClickAction("Select all", "State", new Command() { + @Override + public void execute(Grid c, String value, Object data) { + SelectionModel selectionModel = c.getSelectionModel(); + if (selectionModel instanceof SelectionModel.Multi) { + ((SelectionModel.Multi) selectionModel).selectAll(); + } + } + }, null); + + createClickAction("Select none", "State", new Command() { + @Override + public void execute(Grid c, String value, Object data) { + SelectionModel selectionModel = c.getSelectionModel(); + if (selectionModel instanceof SelectionModel.Multi) { + ((SelectionModel.Multi) selectionModel).deselectAll(); + } + } + }, null); } protected void createHeaderActions() { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java index 9953bbcae0..1f3085d273 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java @@ -20,8 +20,10 @@ import static org.junit.Assert.assertTrue; import org.junit.Test; import org.openqa.selenium.Keys; +import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.interactions.Actions; +import org.openqa.selenium.support.ui.ExpectedCondition; import com.vaadin.testbench.By; import com.vaadin.testbench.elements.GridElement; @@ -335,6 +337,44 @@ public class GridSelectionTest extends GridBasicFeaturesTest { getRow(5).isSelected()); } + @Test + public void testServerSideSelectTogglesSelectAllCheckBox() { + openTestURL(); + + setSelectionModelMulti(); + GridCellElement header = getGridElement().getHeaderCell(0, 0); + + WebElement selectAll = header.findElement(By.tagName("input")); + + selectMenuPath("Component", "State", "Select all"); + waitUntilCheckBoxValue(selectAll, true); + assertTrue("Select all CheckBox wasn't selected as expected", + selectAll.isSelected()); + + selectMenuPath("Component", "State", "Select none"); + waitUntilCheckBoxValue(selectAll, false); + assertFalse("Select all CheckBox was selected unexpectedly", + selectAll.isSelected()); + + selectMenuPath("Component", "State", "Select all"); + waitUntilCheckBoxValue(selectAll, true); + getGridElement().getCell(5, 0).click(); + waitUntilCheckBoxValue(selectAll, false); + assertFalse("Select all CheckBox was selected unexpectedly", + selectAll.isSelected()); + } + + private void waitUntilCheckBoxValue(final WebElement checkBoxElememnt, + final boolean expectedValue) { + waitUntil(new ExpectedCondition() { + @Override + public Boolean apply(WebDriver input) { + return expectedValue ? checkBoxElememnt.isSelected() + : !checkBoxElememnt.isSelected(); + } + }, 5); + } + private void setSelectionModelMulti() { selectMenuPath("Component", "State", "Selection mode", "multi"); } -- cgit v1.2.3 From 55dc0ade6455056ce2bd910b34ddf9e242845d24 Mon Sep 17 00:00:00 2001 From: patrik Date: Wed, 5 Aug 2015 13:55:45 +0300 Subject: Add @since for change 11526 ticket #17590 Change-Id: I2154167c39384a122b06bbdaaac6c161e3fffd2f --- client/src/com/vaadin/client/ComputedStyle.java | 8 ++++---- shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/client/src/com/vaadin/client/ComputedStyle.java b/client/src/com/vaadin/client/ComputedStyle.java index 1391a84bfe..cd90e0e78b 100644 --- a/client/src/com/vaadin/client/ComputedStyle.java +++ b/client/src/com/vaadin/client/ComputedStyle.java @@ -283,7 +283,7 @@ public class ComputedStyle { /** * Returns the sum of the top and bottom border width * - * @since + * @since 7.5.3 * @return the sum of the top and bottom border */ public double getBorderHeight() { @@ -296,7 +296,7 @@ public class ComputedStyle { /** * Returns the sum of the left and right border width * - * @since + * @since 7.5.3 * @return the sum of the left and right border */ public double getBorderWidth() { @@ -309,7 +309,7 @@ public class ComputedStyle { /** * Returns the sum of the top and bottom padding * - * @since + * @since 7.5.3 * @return the sum of the top and bottom padding */ public double getPaddingHeight() { @@ -322,7 +322,7 @@ public class ComputedStyle { /** * Returns the sum of the top and bottom padding * - * @since + * @since 7.5.3 * @return the sum of the left and right padding */ public double getPaddingWidth() { diff --git a/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java b/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java index cf4e95d078..8711a757a1 100644 --- a/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java +++ b/shared/src/com/vaadin/shared/ui/grid/GridClientRpc.java @@ -60,7 +60,7 @@ public interface GridClientRpc extends ClientRpc { * Informs the Grid that all items have been selected or not selected on the * server side. * - * @since + * @since 7.5.3 * @param allSelected * true to check the select all checkbox, * false to uncheck it. -- cgit v1.2.3 From 961f10856af47b59ac8915e06f9ad9f2c0785dfa Mon Sep 17 00:00:00 2001 From: Mika Murtojarvi Date: Fri, 31 Jul 2015 17:10:31 +0300 Subject: Prevent scrolling when expanding a TreeTable item (#18247) Change-Id: I837ee83a75337eef4338e7206cdd0e366b24f183 --- client/src/com/vaadin/client/ui/VScrollTable.java | 14 +++--- .../treetable/TreeTableScrollOnExpand.java | 51 ++++++++++++++++++++++ .../treetable/TreeTableScrollOnExpandTest.java | 46 +++++++++++++++++++ 3 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpand.java create mode 100644 uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpandTest.java diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java index e036725ceb..4e030b8e49 100644 --- a/client/src/com/vaadin/client/ui/VScrollTable.java +++ b/client/src/com/vaadin/client/ui/VScrollTable.java @@ -1295,8 +1295,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets, if (uidl.hasVariable("selected")) { final Set selectedKeys = uidl .getStringArrayVariableAsSet("selected"); - removeUnselectedRowKeys(selectedKeys); - + // Do not update focus if there is a single selected row + // that is the same as the previous selection. This prevents + // unwanted scrolling (#18247). + boolean rowsUnSelected = removeUnselectedRowKeys(selectedKeys); + boolean updateFocus = rowsUnSelected || selectedRowKeys.size() == 0 + || focusedRow == null; if (scrollBody != null) { Iterator iterator = scrollBody.iterator(); while (iterator.hasNext()) { @@ -1313,7 +1317,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets, selected = true; keyboardSelectionOverRowFetchInProgress = true; } - if (selected && selectedKeys.size() == 1) { + if (selected && selectedKeys.size() == 1 && updateFocus) { /* * If a single item is selected, move focus to the * selected row. (#10522) @@ -1338,14 +1342,14 @@ public class VScrollTable extends FlowPanel implements HasWidgets, return keyboardSelectionOverRowFetchInProgress; } - private void removeUnselectedRowKeys(final Set selectedKeys) { + private boolean removeUnselectedRowKeys(final Set selectedKeys) { List unselectedKeys = new ArrayList(0); for (String key : selectedRowKeys) { if (!selectedKeys.contains(key)) { unselectedKeys.add(key); } } - selectedRowKeys.removeAll(unselectedKeys); + return selectedRowKeys.removeAll(unselectedKeys); } /** For internal use only. May be removed or replaced in the future. */ diff --git a/uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpand.java b/uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpand.java new file mode 100644 index 0000000000..07cf7f8c2e --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpand.java @@ -0,0 +1,51 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.treetable; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.TreeTable; + +public class TreeTableScrollOnExpand extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + TreeTable t = new TreeTable(); + t.setSelectable(true); + t.setImmediate(true); + t.setSizeFull(); + t.addContainerProperty("Name", String.class, "null"); + for (int i = 1; i <= 100; i++) { + String parentID = "Item " + i; + Object parent = t.addItem(new Object[] { parentID }, parentID); + String childID = "Item " + (100 + i); + Object child = t.addItem(new Object[] { childID }, childID); + t.getContainerDataSource().setParent(childID, parentID); + } + addComponent(t); + } + + @Override + public Integer getTicketNumber() { + return 18247; + } + + @Override + public String getTestDescription() { + return "After selecting an item and scrolling it out of view, TreeTable should not scroll to the " + + "selected item when expanding an item."; + } +} \ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpandTest.java b/uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpandTest.java new file mode 100644 index 0000000000..a17559cc81 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/treetable/TreeTableScrollOnExpandTest.java @@ -0,0 +1,46 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.treetable; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; + +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.elements.TreeTableElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class TreeTableScrollOnExpandTest extends MultiBrowserTest { + + @Test + public void testScrollOnExpand() throws InterruptedException, IOException { + openTestURL(); + TreeTableElement tt = $(TreeTableElement.class).first(); + tt.getRow(0).click(); + tt.scroll(300); + sleep(1000); + tt.getRow(20).toggleExpanded(); + // Need to wait a bit to avoid accepting the case where the TreeTable is + // in the desired state only for a short while. + sleep(1000); + WebElement focusedRow = getDriver().findElement( + By.className("v-table-focus")); + assertEquals("Item 21", focusedRow.getText()); + } +} \ No newline at end of file -- cgit v1.2.3 From 82647dd69e9bc6fc9961197ddb2eb9868744b568 Mon Sep 17 00:00:00 2001 From: Henri Sara Date: Sun, 9 Aug 2015 13:38:20 +0300 Subject: Use latest GAE SDK supporting Java 6 An upgrade of GAE SDK is needed to support the new HDR that replaced the old DataStore. Change-Id: I968b01bf4efcf03fae8b3c41d7f0a662f57e7727 --- server/ivy.xml | 2 +- uitest/ivy.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/ivy.xml b/server/ivy.xml index e9bc8b818d..0711b4b2ea 100644 --- a/server/ivy.xml +++ b/server/ivy.xml @@ -36,7 +36,7 @@ + rev="1.7.7" conf="build-provided,ide,test -> default" /> + rev="1.7.7" conf="build-provided,ide -> default" /> -- cgit v1.2.3 From 06f8b7dca90676efa905e3eb69b73660f1585e0b Mon Sep 17 00:00:00 2001 From: Henri Sara Date: Fri, 7 Aug 2015 15:56:32 +0300 Subject: Basic tagging commands in staging report Change-Id: I4d211975569e082aefafc9eca0bb0a374739d81d --- scripts/GenerateStagingReport.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/scripts/GenerateStagingReport.py b/scripts/GenerateStagingReport.py index cf53928379..fad66b993f 100644 --- a/scripts/GenerateStagingReport.py +++ b/scripts/GenerateStagingReport.py @@ -38,6 +38,40 @@ content += """

Trac Milestone
Add version {version} to Trac
Staging result page (See test results, pin and tag build and dependencies)
Commands to tag all repositories (warning: do not run as a single script but set variables and check before any push commands - this has not been tested yet and the change IDs are missing)
+VERSION={version}
+
+GERRIT_USER=[fill in your gerrit username]
+FRAMEWORK_REVISION=[fill in framework revision]
+SCREENSHOTS_REVISION=[fill in screenshot repository revision]
+ARCHETYPES_REVISION=[fill in maven-integration repository revision]
+PLUGIN_REVISION=[fill in maven plug-in repository revision]
+
+git clone ssh://$GERRIT_USER@dev.vaadin.com:29418/vaadin
+cd vaadin
+git tag -a -m"$VERSION" $VERSION $FRAMEWORK_REVISION
+git push --tags
+cd ..
+
+git clone ssh://$GERRIT_USER@dev.vaadin.com:29418/vaadin-screenshots
+cd vaadin-screenshots
+git tag -a -m"$VERSION" $VERSION $SCREENSHOTS_REVISION
+git push --tags
+cd ..
+
+git clone ssh://$GERRIT_USER@dev.vaadin.com:29418/maven-integration
+cd maven-integration
+git tag -a -m"$VERSION" $VERSION $ARCHETYPES_REVISION
+git push --tags
+cd ..
+
+git clone ssh://$GERRIT_USER@dev.vaadin.com:29418/maven-plugin
+cd maven-plugin
+git tag -a -m"$VERSION" $VERSION $PLUGIN_REVISION
+git push --tags
+cd ..
+
""".format(url=args.buildResultUrl, repoUrl=args.stagingRepo, version=args.version) -- cgit v1.2.3 From 554bdab01e987b09a78b23d049c0f9f9b2a2ec72 Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Fri, 3 Jul 2015 15:52:06 +0300 Subject: Keep non-editable & selection columns visible in editor Change-Id: Ib3090d43e97667707590a2bca5f4641b72d7cd7f --- WebContent/VAADIN/themes/base/grid/grid.scss | 4 ++ .../VAADIN/themes/valo/components/_grid.scss | 4 ++ client/src/com/vaadin/client/widgets/Grid.java | 51 ++++++++++++++++++++++ server/src/com/vaadin/ui/Grid.java | 3 ++ .../basicfeatures/client/GridEditorClientTest.java | 2 +- .../grid/basicfeatures/server/GridEditorTest.java | 15 ++++--- 6 files changed, 72 insertions(+), 7 deletions(-) diff --git a/WebContent/VAADIN/themes/base/grid/grid.scss b/WebContent/VAADIN/themes/base/grid/grid.scss index f587dfef4f..6b3b017070 100644 --- a/WebContent/VAADIN/themes/base/grid/grid.scss +++ b/WebContent/VAADIN/themes/base/grid/grid.scss @@ -396,6 +396,10 @@ $v-grid-details-border-bottom-stripe: 1px solid darken($v-grid-row-background-co min-width: 100%; max-width: 100%; } + + &.not-editable.#{$primaryStyleName}-cell { + float: none; + } } .error::before { diff --git a/WebContent/VAADIN/themes/valo/components/_grid.scss b/WebContent/VAADIN/themes/valo/components/_grid.scss index d00ddf30a4..11134262eb 100644 --- a/WebContent/VAADIN/themes/valo/components/_grid.scss +++ b/WebContent/VAADIN/themes/valo/components/_grid.scss @@ -119,6 +119,10 @@ $v-grid-details-border-bottom-stripe: $v-grid-cell-horizontal-border !default; vertical-align: middle; } + &.not-editable.#{$primary-stylename}-cell { + float: none; + } + .error::before { border-top: round($v-unit-size / 4) solid $v-error-indicator-color; border-right: round($v-unit-size / 4) solid transparent; diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 18407dccc9..a17c59c795 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -80,6 +80,7 @@ import com.vaadin.client.Focusable; import com.vaadin.client.WidgetUtil; import com.vaadin.client.data.DataChangeHandler; import com.vaadin.client.data.DataSource; +import com.vaadin.client.data.DataSource.RowHandle; import com.vaadin.client.renderers.ComplexRenderer; import com.vaadin.client.renderers.Renderer; import com.vaadin.client.renderers.WidgetRenderer; @@ -1265,6 +1266,7 @@ public class Grid extends ResizeComposite implements private double originalTop; /** Original scroll position of grid when editor was opened */ private double originalScrollTop; + private RowHandle pinnedRowHandle; public Editor() { saveButton = new Button(); @@ -1626,6 +1628,50 @@ public class Grid extends ResizeComposite implements } } else { cell.addClassName(NOT_EDITABLE_CLASS_NAME); + cell.addClassName(tr.getCells().getItem(i).getClassName()); + // If the focused stylename is present it should not be + // inherited by the editor cell as it is not useful in the + // editor and would look broken without additional style + // rules. This is a bit of a hack. + cell.removeClassName(grid.cellFocusStyleName); + + if (column == grid.selectionColumn) { + // Duplicate selection column CheckBox + + pinnedRowHandle = grid.getDataSource().getHandle( + grid.getDataSource().getRow(rowIndex)); + pinnedRowHandle.pin(); + + // We need to duplicate the selection CheckBox for the + // editor overlay since the original one is hidden by + // the overlay + final CheckBox checkBox = GWT.create(CheckBox.class); + checkBox.setValue(grid.isSelected(pinnedRowHandle + .getRow())); + checkBox.sinkEvents(Event.ONCLICK); + + checkBox.addClickHandler(new ClickHandler() { + @Override + public void onClick(ClickEvent event) { + T row = pinnedRowHandle.getRow(); + if (grid.isSelected(row)) { + grid.deselect(row); + } else { + grid.select(row); + } + } + }); + attachWidget(checkBox, cell); + columnToWidget.put(column, checkBox); + + // Only enable CheckBox in non-buffered mode + checkBox.setEnabled(!isBuffered()); + + } else if (!(column.getRenderer() instanceof WidgetRenderer)) { + // Copy non-widget content directly + cell.setInnerHTML(tr.getCells().getItem(i) + .getInnerHTML()); + } } } @@ -1697,6 +1743,11 @@ public class Grid extends ResizeComposite implements return; } + if (pinnedRowHandle != null) { + pinnedRowHandle.unpin(); + pinnedRowHandle = null; + } + for (Widget w : columnToWidget.values()) { setParent(w, null); } diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java index ab4236fdf0..eabd3e00c7 100644 --- a/server/src/com/vaadin/ui/Grid.java +++ b/server/src/com/vaadin/ui/Grid.java @@ -6150,6 +6150,9 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, * Opens the editor interface for the provided item. Scrolls the Grid to * bring the item to view if it is not already visible. * + * Note that any cell content rendered by a WidgetRenderer will not be + * visible in the editor row. + * * @param itemId * the id of the item to edit * @throws IllegalStateException diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java index 43fe29bc02..58d6559bfb 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java @@ -143,7 +143,7 @@ public class GridEditorClientTest extends GridBasicClientFeaturesTest { List selectorDivs = editorCells.findElements(By .cssSelector("div")); - assertTrue("selector column cell should've been empty", selectorDivs + assertFalse("selector column cell should've had contents", selectorDivs .get(0).getAttribute("innerHTML").isEmpty()); assertFalse("normal column cell shoul've had contents", selectorDivs .get(1).getAttribute("innerHTML").isEmpty()); diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java index f7592ce922..0a77d690a4 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java @@ -197,13 +197,16 @@ public abstract class GridEditorTest extends GridBasicFeaturesTest { GridEditorElement editor = getGridElement().getEditor(); assertFalse("Uneditable column should not have an editor widget", editor.isEditable(3)); - assertEquals( - "Not editable cell did not contain correct classname", - "not-editable", - editor.findElements(By.className("v-grid-editor-cells")).get(1) - .findElements(By.xpath("./div")).get(3) - .getAttribute("class")); + String classNames = editor + .findElements(By.className("v-grid-editor-cells")).get(1) + .findElements(By.xpath("./div")).get(3).getAttribute("class"); + + assertTrue("Noneditable cell should contain not-editable classname", + classNames.contains("not-editable")); + + assertTrue("Noneditable cell should contain v-grid-cell classname", + classNames.contains("v-grid-cell")); } @Test -- cgit v1.2.3 From e7e6fd78c1a1506947e8301c1235c622cf424826 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Tue, 11 Aug 2015 14:55:27 +0300 Subject: Fix Grid client-side NPE finding uneditable column editor (#18589) Change-Id: I6f3fc25785bc6036795a791d6582c3d9194b505c --- client/src/com/vaadin/client/widgets/Grid.java | 20 +++++++++++++++----- .../grid/basicfeatures/server/GridEditorTest.java | 1 + 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 8db6e9a55a..ce3db0970a 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -6745,11 +6745,21 @@ public class Grid extends ResizeComposite implements if (args.getIndicesLength() == 0) { return editor.editorOverlay; - } else if (args.getIndicesLength() == 1 - && args.getIndex(0) < columns.size()) { - escalator - .scrollToColumn(args.getIndex(0), ScrollDestination.ANY, 0); - return editor.getWidget(columns.get(args.getIndex(0))).getElement(); + } else if (args.getIndicesLength() == 1) { + int index = args.getIndex(0); + if (index >= columns.size()) { + return null; + } + + escalator.scrollToColumn(index, ScrollDestination.ANY, 0); + Widget widget = editor.getWidget(columns.get(index)); + + if (widget != null) { + return widget.getElement(); + } + + // No widget for the column. + return null; } return null; diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java index b77cc41946..e772ed44e9 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridEditorTest.java @@ -365,6 +365,7 @@ public class GridEditorTest extends GridBasicFeaturesTest { .findElements(By.xpath("./div")).get(3) .getAttribute("class")); + assertNoErrorNotifications(); } private WebElement getSaveButton() { -- cgit v1.2.3 From 53c114ec5e0c2223dfb6e9456c60a05e1c2ad381 Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Tue, 11 Aug 2015 22:55:43 +0300 Subject: Add style names to selection checkboxes (#17755) Change-Id: I982433f643962ed68b0856b520d331038c7fe838 --- .../widget/grid/selection/MultiSelectionRenderer.java | 4 ++++ client/src/com/vaadin/client/widgets/Grid.java | 4 ++++ .../grid/basicfeatures/server/GridSelectionTest.java | 18 ++++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/client/src/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java b/client/src/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java index 1e47d3ad6b..c64908f24c 100644 --- a/client/src/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java +++ b/client/src/com/vaadin/client/widget/grid/selection/MultiSelectionRenderer.java @@ -56,6 +56,8 @@ import com.vaadin.client.widgets.Grid; public class MultiSelectionRenderer extends ClickableRenderer { + private static final String SELECTION_CHECKBOX_CLASSNAME = "-selection-checkbox"; + /** The size of the autoscroll area, both top and bottom. */ private static final int SCROLL_AREA_GRADIENT_PX = 100; @@ -591,6 +593,8 @@ public class MultiSelectionRenderer extends @Override public CheckBox createWidget() { final CheckBox checkBox = GWT.create(CheckBox.class); + checkBox.setStylePrimaryName(grid.getStylePrimaryName() + + SELECTION_CHECKBOX_CLASSNAME); CheckBoxEventHandler handler = new CheckBoxEventHandler(checkBox); // Sink events diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index ce3db0970a..369e530b9d 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -209,6 +209,8 @@ public class Grid extends ResizeComposite implements HasSelectionHandlers, SubPartAware, DeferredWorker, HasWidgets, HasEnabled { + private static final String SELECT_ALL_CHECKBOX_CLASSNAME = "-select-all-checkbox"; + /** * Enum describing different sections of Grid. */ @@ -2405,6 +2407,8 @@ public class Grid extends ResizeComposite implements if (selectAllCheckBox == null) { selectAllCheckBox = GWT.create(CheckBox.class); + selectAllCheckBox.setStylePrimaryName(getStylePrimaryName() + + SELECT_ALL_CHECKBOX_CLASSNAME); selectAllCheckBox .addValueChangeHandler(new ValueChangeHandler() { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java index 1f3085d273..8bf8639d76 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridSelectionTest.java @@ -337,6 +337,24 @@ public class GridSelectionTest extends GridBasicFeaturesTest { getRow(5).isSelected()); } + @Test + public void testSelectionCheckBoxesHaveStyleNames() { + openTestURL(); + + setSelectionModelMulti(); + + assertTrue( + "Selection column CheckBox should have the proper style name set", + getGridElement().getCell(0, 0).findElement(By.tagName("span")) + .getAttribute("class") + .contains("v-grid-selection-checkbox")); + + GridCellElement header = getGridElement().getHeaderCell(0, 0); + assertTrue("Select all CheckBox should have the proper style name set", + header.findElement(By.tagName("span")).getAttribute("class") + .contains("v-grid-select-all-checkbox")); + } + @Test public void testServerSideSelectTogglesSelectAllCheckBox() { openTestURL(); -- cgit v1.2.3 From 2b19ef308931a0f0d2d1a87b8ac11a38412eb0ef Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Sat, 11 Jul 2015 21:54:02 +0300 Subject: Do not force zero height for empty caption height in FormLayout (#15409) Change-Id: I0575556785aa2c5cedb8ec40e2db1ec6644967cc --- client/src/com/vaadin/client/ui/VFormLayout.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/client/src/com/vaadin/client/ui/VFormLayout.java b/client/src/com/vaadin/client/ui/VFormLayout.java index 84a9b4f3dd..bcbb3ebf7b 100644 --- a/client/src/com/vaadin/client/ui/VFormLayout.java +++ b/client/src/com/vaadin/client/ui/VFormLayout.java @@ -22,7 +22,6 @@ import java.util.List; import com.google.gwt.aria.client.Roles; import com.google.gwt.dom.client.Element; -import com.google.gwt.dom.client.Style.Overflow; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.DOM; @@ -327,22 +326,6 @@ public class VFormLayout extends SimplePanel { requiredFieldIndicator = null; } } - - // Workaround for IE weirdness, sometimes returns bad height in some - // circumstances when Caption is empty. See #1444 - // IE7 bugs more often. I wonder what happens when IE8 arrives... - // FIXME: This could be unnecessary for IE8+ - if (BrowserInfo.get().isIE()) { - if (isEmpty) { - setHeight("0px"); - getElement().getStyle().setOverflow(Overflow.HIDDEN); - } else { - setHeight(""); - getElement().getStyle().clearOverflow(); - } - - } - } /** -- cgit v1.2.3 From e02262491c5d3d1b5c8c8e08a118af65e9b5f6ac Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 6 Aug 2015 11:13:21 +0300 Subject: Guard against disconnect() being called twice (#15263) Change-Id: I256529ebcf4a223faa6fd43c4090ba4544c2b040 --- .../com/vaadin/server/communication/AtmospherePushConnection.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java index 357278f411..a45d9aa059 100644 --- a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java +++ b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java @@ -274,6 +274,13 @@ public class AtmospherePushConnection implements PushConnection { public void disconnect() { assert isConnected(); + if (resource == null) { + // Already disconnected. Should not happen but if it does, we don't + // want to cause NPEs + getLogger() + .fine("AtmospherePushConnection.disconnect() called twice, this should not happen"); + return; + } if (resource.isResumed()) { // This can happen for long polling because of // http://dev.vaadin.com/ticket/16919 -- cgit v1.2.3 From a3c9c8ee978ec4117266a30e6483da5aca475e46 Mon Sep 17 00:00:00 2001 From: Taras Hupalo Date: Wed, 5 Aug 2015 13:09:30 +0300 Subject: Add class for last frozen column requested by designers (#18590) See https://github.com/vaadin/components/pull/57#issuecomment-127622121 for details Change-Id: Iba32b6f36f5c98c86a3902133c7486af2dad9669 --- .../src/com/vaadin/client/widgets/Escalator.java | 32 ++++++++++++++++++---- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/client/src/com/vaadin/client/widgets/Escalator.java b/client/src/com/vaadin/client/widgets/Escalator.java index a6247aee12..99f13378d4 100644 --- a/client/src/com/vaadin/client/widgets/Escalator.java +++ b/client/src/com/vaadin/client/widgets/Escalator.java @@ -1475,6 +1475,9 @@ public class Escalator extends Widget implements RequiresResize, cellElem.addClassName("frozen"); position.set(cellElem, scroller.lastScrollLeft, 0); } + if (columnConfiguration.frozenColumns > 0 && col == columnConfiguration.frozenColumns - 1) { + cellElem.addClassName("last-frozen"); + } } referenceRow = paintInsertRow(referenceRow, tr, row); @@ -1732,6 +1735,14 @@ public class Escalator extends Widget implements RequiresResize, } public void setColumnFrozen(int column, boolean frozen) { + toggleFrozenColumnClass(column, frozen, "frozen"); + + if (frozen) { + updateFreezePosition(column, scroller.lastScrollLeft); + } + } + + private void toggleFrozenColumnClass(int column, boolean frozen, String className) { final NodeList childRows = root.getRows(); for (int row = 0; row < childRows.getLength(); row++) { @@ -1742,16 +1753,16 @@ public class Escalator extends Widget implements RequiresResize, TableCellElement cell = tr.getCells().getItem(column); if (frozen) { - cell.addClassName("frozen"); + cell.addClassName(className); } else { - cell.removeClassName("frozen"); + cell.removeClassName(className); position.reset(cell); } } + } - if (frozen) { - updateFreezePosition(column, scroller.lastScrollLeft); - } + public void setColumnLastFrozen(int column, boolean lastFrozen) { + toggleFrozenColumnClass(column, lastFrozen, "last-frozen"); } public void updateFreezePosition(int column, double scrollLeft) { @@ -4309,6 +4320,17 @@ public class Escalator extends Widget implements RequiresResize, firstUnaffectedCol = oldCount; } + if (oldCount > 0) { + header.setColumnLastFrozen(oldCount - 1, false); + body.setColumnLastFrozen(oldCount - 1, false); + footer.setColumnLastFrozen(oldCount - 1, false); + } + if (count > 0) { + header.setColumnLastFrozen(count - 1, true); + body.setColumnLastFrozen(count - 1, true); + footer.setColumnLastFrozen(count - 1, true); + } + for (int col = firstAffectedCol; col < firstUnaffectedCol; col++) { header.setColumnFrozen(col, frozen); body.setColumnFrozen(col, frozen); -- cgit v1.2.3 From 3e6c07b654656632b5b785966783f139c046d9b3 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Wed, 12 Aug 2015 15:13:08 +0300 Subject: Add reporting script for post-publish validation Change-Id: I3c145566cc3c5a103e68955c3fff19cfdfa3a4d2 --- scripts/GeneratePublishReport.py | 53 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 scripts/GeneratePublishReport.py diff --git a/scripts/GeneratePublishReport.py b/scripts/GeneratePublishReport.py new file mode 100644 index 0000000000..0293bdbb44 --- /dev/null +++ b/scripts/GeneratePublishReport.py @@ -0,0 +1,53 @@ +#coding=UTF-8 + +import argparse, cgi + +parser = argparse.ArgumentParser(description="Post-publish report generator") +parser.add_argument("version", type=str, help="Vaadin version that was just built") +parser.add_argument("buildResultUrl", type=str, help="URL for the build result page") + +args = parser.parse_args() + +(major, minor, maintenance) = args.version.split(".", 2) +prerelease = "." in maintenance +if prerelease: + maintenance = maintenance.split('.')[0] + +content = """ + + + +""" + +if not prerelease: + content += "".format(maj=major, min=minor, ver=args.version) +else: + content += "".format(maj=major, min=minor, main=maintenance, ver=args.version) + +content += """ + + + + + +""" + +if not prerelease: + content += '' + +content += """ + +""".format(version=args.version) + +if not prerelease: + content += '' + +content += """ + + +
Check {ver} is published to vaadin.com/download
Check {ver} is published as prerelease to vaadin.com/download
Verify Latest Vaadin 7:
Verify Vaadin 7 Version List:
Verify Latest Vaadin 7.5:
Verify Latest Vaadin 7.6:
Verify Latest Vaadin 6:
Verify Latest Vaadin 7 Prerelease:
Set latest version to default
Verify uploaded to test.vaadin.com
Verify tags pushed to GitHub
Verify API version list updated
Batch update tickets in Trac
Publish result page (See test results, pin and tag build and dependencies)
+ +""".format(url=args.buildResultUrl, version=args.version) + +f = open("result/report.html", 'w') +f.write(content) -- cgit v1.2.3 From bb87c5c3339b5b7ce926829047582889ac1eb87c Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Mon, 10 Aug 2015 11:52:07 +0300 Subject: Add missing URLs to staging report This adds a new command line parameter for TestBench API build Change-Id: I78b916bf59da1267e31ed522ee9c4bdf47800d45 --- scripts/GenerateStagingReport.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/GenerateStagingReport.py b/scripts/GenerateStagingReport.py index fad66b993f..23977aa933 100644 --- a/scripts/GenerateStagingReport.py +++ b/scripts/GenerateStagingReport.py @@ -9,6 +9,7 @@ parser.add_argument("version", type=str, help="Vaadin version that was just buil parser.add_argument("deployUrl", type=str, help="Base url of the deployment server") parser.add_argument("buildResultUrl", type=str, help="URL for the build result page") parser.add_argument("stagingRepo", type=str, help="URL for the staging repository") +parser.add_argument("tbapiUrl", type=str, help="URL for the TestBench API build") args = parser.parse_args() @@ -35,7 +36,8 @@ content += cgi.escape(""" """.format(repoUrl=args.stagingRepo)) content += """ -Trac Milestone +Close Trac Milestone +Verify pending release tickets still have milestone {version} Add version {version} to Trac Staging result page (See test results, pin and tag build and dependencies) Commands to tag all repositories (warning: do not run as a single script but set variables and check before any push commands - this has not been tested yet and the change IDs are missing) @@ -72,9 +74,10 @@ git tag -a -m"$VERSION" $VERSION $PLUGIN_REVISION git push --tags cd .. +Build and publish TestBench API for version {version} if proceeding -""".format(url=args.buildResultUrl, repoUrl=args.stagingRepo, version=args.version) +""".format(url=args.buildResultUrl, repoUrl=args.stagingRepo, version=args.version, tbapi=args.tbapiUrl) f = open("result/report.html", 'w') f.write(content) -- cgit v1.2.3 From 2be70f04484c793fff15b21e661c5c56df443775 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 15 Jan 2015 21:59:00 +0200 Subject: Decode filename before finding resource (#15407) Change-Id: Iede2deff19058ee65bfe06ee8abb918218a57924 --- .../resource with special $chars@.txt | 1 + .../VAADIN/themes/tests-tickets/ordinary.txt | 1 + .../themes/tests-tickets/percentagein%20name.txt | 1 + server/src/com/vaadin/server/VaadinServlet.java | 20 +++++---- .../resources/SpecialCharsInThemeResources.java | 52 ++++++++++++++++++++++ 5 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 WebContent/VAADIN/themes/tests-tickets/folder with space/resource with special $chars@.txt create mode 100644 WebContent/VAADIN/themes/tests-tickets/ordinary.txt create mode 100644 WebContent/VAADIN/themes/tests-tickets/percentagein%20name.txt create mode 100644 uitest/src/com/vaadin/tests/resources/SpecialCharsInThemeResources.java diff --git a/WebContent/VAADIN/themes/tests-tickets/folder with space/resource with special $chars@.txt b/WebContent/VAADIN/themes/tests-tickets/folder with space/resource with special $chars@.txt new file mode 100644 index 0000000000..dff31dd51f --- /dev/null +++ b/WebContent/VAADIN/themes/tests-tickets/folder with space/resource with special $chars@.txt @@ -0,0 +1 @@ +Just ordinary contents here \ No newline at end of file diff --git a/WebContent/VAADIN/themes/tests-tickets/ordinary.txt b/WebContent/VAADIN/themes/tests-tickets/ordinary.txt new file mode 100644 index 0000000000..dff31dd51f --- /dev/null +++ b/WebContent/VAADIN/themes/tests-tickets/ordinary.txt @@ -0,0 +1 @@ +Just ordinary contents here \ No newline at end of file diff --git a/WebContent/VAADIN/themes/tests-tickets/percentagein%20name.txt b/WebContent/VAADIN/themes/tests-tickets/percentagein%20name.txt new file mode 100644 index 0000000000..dff31dd51f --- /dev/null +++ b/WebContent/VAADIN/themes/tests-tickets/percentagein%20name.txt @@ -0,0 +1 @@ +Just ordinary contents here \ No newline at end of file diff --git a/server/src/com/vaadin/server/VaadinServlet.java b/server/src/com/vaadin/server/VaadinServlet.java index 7aada2402d..61df02feaa 100644 --- a/server/src/com/vaadin/server/VaadinServlet.java +++ b/server/src/com/vaadin/server/VaadinServlet.java @@ -28,6 +28,7 @@ import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; +import java.net.URLDecoder; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -694,17 +695,20 @@ public class VaadinServlet extends HttpServlet implements Constants { return false; } + String decodedRequestURI = URLDecoder.decode(request.getRequestURI(), + "UTF-8"); if ((request.getContextPath() != null) - && (request.getRequestURI().startsWith("/VAADIN/"))) { - serveStaticResourcesInVAADIN(request.getRequestURI(), request, - response); + && (decodedRequestURI.startsWith("/VAADIN/"))) { + serveStaticResourcesInVAADIN(decodedRequestURI, request, response); return true; - } else if (request.getRequestURI().startsWith( - request.getContextPath() + "/VAADIN/")) { + } + + String decodedContextPath = URLDecoder.decode(request.getContextPath(), + "UTF-8"); + if (decodedRequestURI.startsWith(decodedContextPath + "/VAADIN/")) { serveStaticResourcesInVAADIN( - request.getRequestURI().substring( - request.getContextPath().length()), request, - response); + decodedRequestURI.substring(decodedContextPath.length()), + request, response); return true; } diff --git a/uitest/src/com/vaadin/tests/resources/SpecialCharsInThemeResources.java b/uitest/src/com/vaadin/tests/resources/SpecialCharsInThemeResources.java new file mode 100644 index 0000000000..e584ec73cc --- /dev/null +++ b/uitest/src/com/vaadin/tests/resources/SpecialCharsInThemeResources.java @@ -0,0 +1,52 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.resources; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class SpecialCharsInThemeResources extends SingleBrowserTest { + + @Test + public void loadThemeResource() { + loadResource("/VAADIN/themes/tests-tickets/ordinary.txt"); + checkSource(); + } + + @Test + public void loadThemeResourceWithPercentage() { + loadResource("/VAADIN/themes/tests-tickets/percentagein%2520name.txt"); + checkSource(); + } + + @Test + public void loadThemeResourceWithSpecialChars() { + loadResource("/VAADIN/themes/tests-tickets/folder%20with%20space/resource%20with%20special%20$chars@.txt"); + checkSource(); + } + + private void loadResource(String path) { + getDriver().get(getBaseURL() + path); + } + + private void checkSource() { + String source = getDriver().getPageSource(); + Assert.assertTrue("Incorrect contents (was: " + source + ")", + source.contains("Just ordinary contents here")); + } +} -- cgit v1.2.3 From 7d1b0d2ca1ae28e25ad5e46ddcdc3f51c10fd9b8 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Thu, 13 Aug 2015 10:22:42 +0300 Subject: Add server check for deployment script Change-Id: Ic8622cb0e83657417bb01135ed752a87b364c7a1 --- scripts/DeployHelpers.py | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/scripts/DeployHelpers.py b/scripts/DeployHelpers.py index 2c879088ff..12c7baaaec 100644 --- a/scripts/DeployHelpers.py +++ b/scripts/DeployHelpers.py @@ -12,14 +12,51 @@ except Exception as e: from requests.auth import HTTPDigestAuth from os.path import join, expanduser, basename from BuildHelpers import parser, getArgs +from time import sleep parser.add_argument("--deployUrl", help="Wildfly management URL") parser.add_argument("--deployUser", help="Deployment user", default=None) parser.add_argument("--deployPass", help="Deployment password", default=None) +serverUp = None + +def testServer(): + global serverUp + + if serverUp is not None: + return serverUp + + print("Checking server status") + i = 0 + request = {"operation" : "read-attribute", "name" : "server-state"} + serverUp = False + while not serverUp and i < 2: + try: + print("Trying on url %s" % (getUrl())) + result = doPostJson(url=getUrl(), auth=getAuth(), data=json.dumps(request)) + response = result.json() + if "outcome" not in response or response["outcome"] != "success": + # Failure + raise Exception(response) + elif "result" not in response or response["result"] != "running": + # Another failure + raise Exception(response) + # All OK + serverUp = True + print("Got server connection.") + except Exception as e: + print("Exception while checking server state: ", e) + print("Server connection failed, retrying in 5 seconds.") + i = i + 1 + sleep(5) + return serverUp + # Helper for handling the full deployment # name should end with .war def deployWar(warFile, name=None): + if not testServer(): + raise Exception("Server not up. Skipping deployment.") + return if name is None: name = basename(warFile).replace('.war', "-%s.war" % (getArgs().version.split('-')[0])) -- cgit v1.2.3 From 38e7c12bac61fb60fc4916e36b979cb3667db8e1 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Thu, 13 Aug 2015 08:27:58 +0300 Subject: Make Valo work with sass-lang compiler again (#18438) Change-Id: I0b49dc9a2d5a620244829739ccef644e3b7572ca --- WebContent/VAADIN/themes/valo/components/_grid.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/WebContent/VAADIN/themes/valo/components/_grid.scss b/WebContent/VAADIN/themes/valo/components/_grid.scss index d00ddf30a4..dffd5fbb65 100644 --- a/WebContent/VAADIN/themes/valo/components/_grid.scss +++ b/WebContent/VAADIN/themes/valo/components/_grid.scss @@ -21,6 +21,11 @@ $v-grid-details-marker-width: first-number($v-grid-border) * 2 !default; $v-grid-details-marker-color: $v-selection-color !default; $v-grid-details-border-top: valo-border($color: $v-grid-border-color-source, $strength: 0.3) !default; $v-grid-details-border-top-stripe: valo-border($color: $v-grid-row-stripe-background-color, $strength: 0.3) !default; + +$v-grid-border-size: 1px !default; +$v-grid-border: $v-grid-border-size solid #ddd !default; +$v-grid-cell-vertical-border: $v-grid-border !default; +$v-grid-cell-horizontal-border: $v-grid-cell-vertical-border !default; $v-grid-details-border-bottom: $v-grid-cell-horizontal-border !default; $v-grid-details-border-bottom-stripe: $v-grid-cell-horizontal-border !default; -- cgit v1.2.3 From caea8f39e7e39123992982924d0a2c703dc5979e Mon Sep 17 00:00:00 2001 From: Henri Sara Date: Thu, 13 Aug 2015 13:51:00 +0300 Subject: Disable websphereportal8 test The automated test environment is missing the server, so the test was always ignored. Change-Id: Ida3266758eea461c65f2d937109455b209903dfb --- uitest/integration_tests.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/uitest/integration_tests.xml b/uitest/integration_tests.xml index d56ba2683f..bdbf1f2e5b 100644 --- a/uitest/integration_tests.xml +++ b/uitest/integration_tests.xml @@ -404,7 +404,8 @@ - + + -- cgit v1.2.3 From 86e0fddbdc1dc849d596f526bb17efdfa8d67019 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Fri, 14 Aug 2015 13:21:53 +0300 Subject: Prevent Escalator scrollbars oscillation in HeightByRows mode (#18596) Change-Id: Id7e72fbd31277b7c93055c8aa9309d73c86795d6 --- client/src/com/vaadin/client/widgets/Escalator.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/client/src/com/vaadin/client/widgets/Escalator.java b/client/src/com/vaadin/client/widgets/Escalator.java index 99f13378d4..5b3d4e1b70 100644 --- a/client/src/com/vaadin/client/widgets/Escalator.java +++ b/client/src/com/vaadin/client/widgets/Escalator.java @@ -5641,14 +5641,29 @@ public class Escalator extends Widget implements RequiresResize, horizontalScrollbar.setScrollbarThickness(scrollbarThickness); horizontalScrollbar .addVisibilityHandler(new ScrollbarBundle.VisibilityHandler() { + + private boolean queued = false; + @Override public void visibilityChanged( ScrollbarBundle.VisibilityChangeEvent event) { + if (queued) { + return; + } + queued = true; + /* * We either lost or gained a scrollbar. In any case, we * need to change the height, if it's defined by rows. */ - applyHeightByRows(); + Scheduler.get().scheduleFinally(new ScheduledCommand() { + + @Override + public void execute() { + applyHeightByRows(); + queued = false; + } + }); } }); -- cgit v1.2.3 From 029cb1a81bf66488df1f8d5a376dd7b1a0c03bd2 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 4 Aug 2015 12:33:30 +0300 Subject: Handle renderer exceptions gracefully (#18554) Change-Id: I46557f6c6f8543ab61b863145863824785d14784 --- .../com/vaadin/data/RpcDataProviderExtension.java | 9 ++++- .../src/com/vaadin/ui/renderers/ImageRenderer.java | 2 +- .../components/grid/GridWithBrokenRenderer.java | 43 ++++++++++++++++++++++ .../grid/GridWithBrokenRendererTest.java | 41 +++++++++++++++++++++ 4 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRenderer.java create mode 100644 uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRendererTest.java diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java index 6f8a7e8f7b..98394c45df 100644 --- a/server/src/com/vaadin/data/RpcDataProviderExtension.java +++ b/server/src/com/vaadin/data/RpcDataProviderExtension.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.logging.Level; import java.util.logging.Logger; import com.google.gwt.thirdparty.guava.common.collect.BiMap; @@ -1238,7 +1239,13 @@ public class RpcDataProviderExtension extends AbstractExtension { safeConverter.getPresentationType(), locale); } - JsonValue encodedValue = renderer.encode(presentationValue); + JsonValue encodedValue; + try { + encodedValue = renderer.encode(presentationValue); + } catch (Exception e) { + getLogger().log(Level.SEVERE, "Unable to encode data", e); + encodedValue = renderer.encode(null); + } return encodedValue; } diff --git a/server/src/com/vaadin/ui/renderers/ImageRenderer.java b/server/src/com/vaadin/ui/renderers/ImageRenderer.java index 2fb872583e..ad7d5cae2b 100644 --- a/server/src/com/vaadin/ui/renderers/ImageRenderer.java +++ b/server/src/com/vaadin/ui/renderers/ImageRenderer.java @@ -58,7 +58,7 @@ public class ImageRenderer extends ClickableRenderer { if (!(resource == null || resource instanceof ExternalResource || resource instanceof ThemeResource)) { throw new IllegalArgumentException( "ImageRenderer only supports ExternalResource and ThemeResource (" - + resource.getClass().getSimpleName() + "given )"); + + resource.getClass().getSimpleName() + " given)"); } return encode(ResourceReference.create(resource, this, null), diff --git a/uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRenderer.java b/uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRenderer.java new file mode 100644 index 0000000000..4d44eeb248 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRenderer.java @@ -0,0 +1,43 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.grid; + +import com.vaadin.server.ClassResource; +import com.vaadin.server.Resource; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUIWithLog; +import com.vaadin.tests.integration.FlagSeResource; +import com.vaadin.ui.Grid; +import com.vaadin.ui.renderers.ImageRenderer; + +public class GridWithBrokenRenderer extends AbstractTestUIWithLog { + + @Override + protected void setup(VaadinRequest request) { + final Grid grid = new Grid(); + grid.addColumn("short", String.class); + grid.addColumn("icon", Resource.class); + grid.addColumn("country", String.class); + + grid.getColumn("icon").setRenderer(new ImageRenderer()); + addComponent(grid); + + grid.addRow("FI", new ClassResource("fi.gif"), "Finland"); + grid.addRow("SE", new FlagSeResource(), "Sweden"); + + } + +} diff --git a/uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRendererTest.java b/uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRendererTest.java new file mode 100644 index 0000000000..011c8c92ce --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/GridWithBrokenRendererTest.java @@ -0,0 +1,41 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.grid; + +import org.junit.Assert; +import org.junit.Test; + +import com.vaadin.testbench.elements.GridElement; +import com.vaadin.tests.tb3.SingleBrowserTest; + +public class GridWithBrokenRendererTest extends SingleBrowserTest { + + @Test + public void ensureRendered() { + openTestURL(); + GridElement grid = $(GridElement.class).first(); + assertRow(grid, 0, "FI", "", "Finland"); + assertRow(grid, 1, "SE", "", "Sweden"); + } + + private void assertRow(GridElement grid, int row, String... texts) { + for (int column = 0; column < texts.length; column++) { + Assert.assertEquals("Cell " + row + "," + column, texts[column], + grid.getCell(row, column).getText()); + } + + } +} -- cgit v1.2.3 From e7fda93b300b11d9507f25917306e1f3d57cb27c Mon Sep 17 00:00:00 2001 From: Sauli Tähkäpää Date: Sat, 15 Aug 2015 23:14:14 +0300 Subject: Prevent NPE on missing security key. (#18573) Change-Id: I6d9eeb257a4a4889ce679a31a45133c3d0c90368 --- .../server/communication/FileUploadHandler.java | 2 +- .../communication/FileUploadHandlerTest.java | 120 ++++++++++++++++++--- 2 files changed, 104 insertions(+), 18 deletions(-) diff --git a/server/src/com/vaadin/server/communication/FileUploadHandler.java b/server/src/com/vaadin/server/communication/FileUploadHandler.java index 576cbd8411..532c7fe95b 100644 --- a/server/src/com/vaadin/server/communication/FileUploadHandler.java +++ b/server/src/com/vaadin/server/communication/FileUploadHandler.java @@ -269,7 +269,7 @@ public class FileUploadHandler implements RequestHandler { streamVariable = uI.getConnectorTracker().getStreamVariable( connectorId, variableName); String secKey = uI.getConnectorTracker().getSeckey(streamVariable); - if (!secKey.equals(parts[3])) { + if (secKey == null || !secKey.equals(parts[3])) { // TODO Should rethink error handling return true; } diff --git a/server/tests/src/com/vaadin/server/communication/FileUploadHandlerTest.java b/server/tests/src/com/vaadin/server/communication/FileUploadHandlerTest.java index 2cb4c3bf4d..286163541e 100644 --- a/server/tests/src/com/vaadin/server/communication/FileUploadHandlerTest.java +++ b/server/tests/src/com/vaadin/server/communication/FileUploadHandlerTest.java @@ -15,50 +15,136 @@ */ package com.vaadin.server.communication; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; + import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import org.junit.Before; import org.junit.Test; -import org.mockito.Mockito; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import com.vaadin.server.ClientConnector; +import com.vaadin.server.ServletPortletHelper; +import com.vaadin.server.StreamVariable; import com.vaadin.server.VaadinRequest; +import com.vaadin.server.VaadinResponse; +import com.vaadin.server.VaadinSession; +import com.vaadin.ui.ConnectorTracker; +import com.vaadin.ui.UI; -/** - * Tests whether we get infinite loop if InputStream is already read (#10096) - */ public class FileUploadHandlerTest { private FileUploadHandler handler; - private VaadinRequest request; + @Mock private VaadinResponse response; + @Mock private StreamVariable streamVariable; + @Mock private ClientConnector clientConnector; + @Mock private VaadinRequest request; + @Mock private UI ui; + @Mock private ConnectorTracker connectorTracker; + @Mock private VaadinSession session; + @Mock private OutputStream responseOutput; + + private int uiId = 123; + private final String connectorId = "connectorId"; + private final String variableName = "name"; + private final String expectedSecurityKey = "key"; @Before public void setup() throws Exception { + MockitoAnnotations.initMocks(this); + handler = new FileUploadHandler(); - InputStream inputStream = new InputStream() { - private int counter = 0; + + mockRequest(); + mockConnectorTracker(); + mockUi(); + + when(clientConnector.isConnectorEnabled()).thenReturn(true); + when(streamVariable.getOutputStream()).thenReturn(mock(OutputStream.class)); + when(response.getOutputStream()).thenReturn(responseOutput); + } + + private void mockConnectorTracker() { + when(connectorTracker.getSeckey(streamVariable)).thenReturn(expectedSecurityKey); + when(connectorTracker.getStreamVariable(connectorId, variableName)).thenReturn(streamVariable); + when(connectorTracker.getConnector(connectorId)).thenReturn(clientConnector); + } + + private void mockRequest() throws IOException { + when(request.getPathInfo()).thenReturn("/" + ServletPortletHelper.UPLOAD_URL_PREFIX + uiId + "/"+ connectorId + "/" + variableName + "/" + expectedSecurityKey); + when(request.getInputStream()).thenReturn(createInputStream("foobar")); + when(request.getHeader("Content-Length")).thenReturn("6"); + when(request.getContentType()).thenReturn("foobar"); + } + + private InputStream createInputStream(final String content) { + return new InputStream() { + int counter = 0; + byte[] msg = content.getBytes(); @Override public int read() throws IOException { - counter++; - if (counter > 6) { - throw new RuntimeException( - "-1 is ignored by FileUploadHandler"); + if(counter > msg.length + 1) { + throw new AssertionError("-1 was ignored by FileUploadHandler."); + } + + if(counter >= msg.length) { + counter++; + return -1; } - return -1; - } + return msg[counter++]; + } }; - request = Mockito.mock(VaadinRequest.class); - Mockito.when(request.getInputStream()).thenReturn(inputStream); - Mockito.when(request.getHeader("Content-Length")).thenReturn("211"); } + private void mockUi() { + when(ui.getConnectorTracker()).thenReturn(connectorTracker); + when(session.getUIById(uiId)).thenReturn(ui); + } + + /** + * Tests whether we get infinite loop if InputStream is already read (#10096) + */ @Test(expected = IOException.class) - public void testStreamEnded() throws IOException { + public void exceptionIsThrownOnUnexpectedEnd() throws IOException { + when(request.getInputStream()).thenReturn(createInputStream("")); + when(request.getHeader("Content-Length")).thenReturn("1"); + handler.doHandleSimpleMultipartFileUpload(null, request, null, null, null, null, null); + } + + @Test + public void responseIsSentOnCorrectSecurityKey() throws IOException { + when(connectorTracker.getSeckey(streamVariable)).thenReturn(expectedSecurityKey); + + handler.handleRequest(session, request, response); + verify(responseOutput).close(); } + @Test + public void responseIsNotSentOnIncorrectSecurityKey() throws IOException { + when(connectorTracker.getSeckey(streamVariable)).thenReturn("another key expected"); + + handler.handleRequest(session, request, response); + + verifyZeroInteractions(responseOutput); + } + + @Test + public void responseIsNotSentOnMissingSecurityKey() throws IOException { + when(connectorTracker.getSeckey(streamVariable)).thenReturn(null); + + handler.handleRequest(session, request, response); + + verifyZeroInteractions(responseOutput); + } } -- cgit v1.2.3 From 15ad8bccfc9073cdf1e587f7f7dd6e1f3f27c43f Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Wed, 22 Jul 2015 14:50:26 +0300 Subject: Fix RpcDataProviderExtension to not rely on item indices (#18503) Change-Id: I68a77bee4ef8e7a859f3a3c143e6f5922decf025 --- .../client/connectors/RpcDataSourceConnector.java | 27 ++ .../client/data/AbstractRemoteDataSource.java | 18 +- .../com/vaadin/data/RpcDataProviderExtension.java | 352 +++++---------------- .../com/vaadin/shared/data/DataProviderRpc.java | 12 + .../src/com/vaadin/shared/data/DataRequestRpc.java | 14 +- .../tests/components/grid/GridDetailsDetach.java | 1 - 6 files changed, 152 insertions(+), 272 deletions(-) diff --git a/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java b/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java index c1b9f13ef4..5680b09cef 100644 --- a/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java +++ b/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java @@ -17,6 +17,7 @@ package com.vaadin.client.connectors; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import com.vaadin.client.ServerConnector; @@ -96,6 +97,11 @@ public class RpcDataSourceConnector extends AbstractExtensionConnector { public void resetDataAndSize(int size) { RpcDataSource.this.resetDataAndSize(size); } + + @Override + public void updateRowData(JsonObject row) { + RpcDataSource.this.updateRowData(row); + } }); } @@ -213,6 +219,27 @@ public class RpcDataSourceConnector extends AbstractExtensionConnector { rowData.get(i)); } } + + /** + * Updates row data based on row key. + * + * @since + * @param row + * new row object + */ + protected void updateRowData(JsonObject row) { + int index = indexOfKey(getRowKey(row)); + if (index >= 0) { + setRowData(index, Collections.singletonList(row)); + } + } + + @Override + protected void onDropFromCache(int rowIndex) { + super.onDropFromCache(rowIndex); + + rpcProxy.dropRow(getRowKey(getRow(rowIndex))); + } } private final RpcDataSource dataSource = new RpcDataSource(); diff --git a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java index 459127c9b4..c8910f8699 100644 --- a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java +++ b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java @@ -330,16 +330,18 @@ public abstract class AbstractRemoteDataSource implements DataSource { private void dropFromCache(Range range) { for (int i = range.getStart(); i < range.getEnd(); i++) { + // Called before dropping from cache, so we can actually do + // something with the data before the drop. + onDropFromCache(i); + T removed = indexToRowMap.remove(Integer.valueOf(i)); keyToIndexMap.remove(getRowKey(removed)); - - onDropFromCache(i); } } /** - * A hook that can be overridden to do something whenever a row is dropped - * from the cache. + * A hook that can be overridden to do something whenever a row is about to + * be dropped from the cache. * * @since 7.5.0 * @param rowIndex @@ -732,4 +734,12 @@ public abstract class AbstractRemoteDataSource implements DataSource { dataChangeHandler.resetDataAndSize(newSize); } } + + protected int indexOfKey(Object rowKey) { + if (!keyToIndexMap.containsKey(rowKey)) { + return -1; + } else { + return keyToIndexMap.get(rowKey); + } + } } diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java index 98394c45df..848873098d 100644 --- a/server/src/com/vaadin/data/RpcDataProviderExtension.java +++ b/server/src/com/vaadin/data/RpcDataProviderExtension.java @@ -21,6 +21,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; @@ -100,31 +101,6 @@ public class RpcDataProviderExtension extends AbstractExtension { // private implementation } - /** - * Sets the currently active rows. This will purge any unpinned rows - * from cache. - * - * @param itemIds - * collection of itemIds to map to row keys - */ - void setActiveRows(Collection itemIds) { - Set itemSet = new HashSet(itemIds); - Set itemsRemoved = new HashSet(); - for (Object itemId : itemIdToKey.keySet()) { - if (!itemSet.contains(itemId) && !isPinned(itemId)) { - itemsRemoved.add(itemId); - } - } - - for (Object itemId : itemsRemoved) { - itemIdToKey.remove(itemId); - } - - for (Object itemId : itemSet) { - itemIdToKey.put(itemId, getKey(itemId)); - } - } - private String nextKey() { return String.valueOf(rollingIndex++); } @@ -273,246 +249,91 @@ public class RpcDataProviderExtension extends AbstractExtension { public boolean isPinned(Object itemId) { return pinnedItemIds.contains(itemId); } - } - /** - * A helper class that handles the client-side Escalator logic relating to - * making sure that whatever is currently visible to the user, is properly - * initialized and otherwise handled on the server side (as far as - * required). - *

- * This bookeeping includes, but is not limited to: - *

    - *
  • listening to the currently visible {@link com.vaadin.data.Property - * Properties'} value changes on the server side and sending those back to - * the client; and - *
  • attaching and detaching {@link com.vaadin.ui.Component Components} - * from the Vaadin Component hierarchy. - *
- */ - private class ActiveRowHandler implements Serializable { /** - * A map from index to the value change listener used for all of column - * properties - */ - private final Map valueChangeListeners = new HashMap(); - - /** - * The currently active range. Practically, it's the range of row - * indices being cached currently. - */ - private Range activeRange = Range.withLength(0, 0); - - /** - * A hook for making sure that appropriate data is "active". All other - * rows should be "inactive". - *

- * "Active" can mean different things in different contexts. For - * example, only the Properties in the active range need - * ValueChangeListeners. Also, whenever a row with a Component becomes - * active, it needs to be attached (and conversely, when inactive, it - * needs to be detached). + * Removes all inactive item id to key mapping from the key mapper. * - * @param firstActiveRow - * the first active row - * @param activeRowCount - * the number of active rows + * @since */ - public void setActiveRows(Range newActiveRange) { - - // TODO [[Components]] attach and detach components - - /*- - * Example - * - * New Range: [3, 4, 5, 6, 7] - * Old Range: [1, 2, 3, 4, 5] - * Result: [1, 2][3, 4, 5] [] - */ - final Range[] depractionPartition = activeRange - .partitionWith(newActiveRange); - removeValueChangeListeners(depractionPartition[0]); - removeValueChangeListeners(depractionPartition[2]); - - /*- - * Example - * - * Old Range: [1, 2, 3, 4, 5] - * New Range: [3, 4, 5, 6, 7] - * Result: [] [3, 4, 5][6, 7] - */ - final Range[] activationPartition = newActiveRange - .partitionWith(activeRange); - addValueChangeListeners(activationPartition[0]); - addValueChangeListeners(activationPartition[2]); - - activeRange = newActiveRange; - - assert valueChangeListeners.size() == newActiveRange.length() : "Value change listeners not set up correctly!"; - } - - private void addValueChangeListeners(Range range) { - for (Integer i = range.getStart(); i < range.getEnd(); i++) { - - final Object itemId = container.getIdByIndex(i); - final Item item = container.getItem(itemId); - - assert valueChangeListeners.get(i) == null : "Overwriting existing listener"; - - GridValueChangeListener listener = new GridValueChangeListener( - itemId, item); - valueChangeListeners.put(i, listener); + public void dropInactiveItems() { + Collection active = activeItemHandler.getActiveItemIds(); + Iterator itemIter = itemIdToKey.keySet().iterator(); + while (itemIter.hasNext()) { + Object itemId = itemIter.next(); + if (!active.contains(itemId) && !isPinned(itemId)) { + itemIter.remove(); + } } } + } - private void removeValueChangeListeners(Range range) { - for (Integer i = range.getStart(); i < range.getEnd(); i++) { - final GridValueChangeListener listener = valueChangeListeners - .remove(i); + /** + * Class for keeping track of current items and ValueChangeListeners. + * + * @since + */ + private class ActiveItemHandler implements Serializable { - assert listener != null : "Trying to remove nonexisting listener"; - - listener.removeListener(); - } - } + private final Map activeItemMap = new HashMap(); + private final Set droppedItems = new HashSet(); /** - * Manages removed columns in active rows. - *

- * This method does not send data again to the client. + * Registers ValueChangeListeners for given items ids. * - * @param removedColumns - * the columns that have been removed from the grid + * @param itemIds + * collection of new active item ids */ - public void columnsRemoved(Collection removedColumns) { - if (removedColumns.isEmpty()) { - return; + public void addActiveItems(Collection itemIds) { + for (Object itemId : itemIds) { + if (!activeItemMap.containsKey(itemId)) { + activeItemMap.put(itemId, new GridValueChangeListener( + itemId, container.getItem(itemId))); + } } - for (GridValueChangeListener listener : valueChangeListeners - .values()) { - listener.removeColumns(removedColumns); - } + // Remove still active rows that were "dropped" + droppedItems.removeAll(itemIds); + dropListeners(droppedItems); + droppedItems.clear(); } /** - * Manages added columns in active rows. - *

- * This method sends the data for the changed rows to client side. + * Marks given item id as dropped. Dropped items are cleared when adding + * new active items. * - * @param addedColumns - * the columns that have been added to the grid + * @param itemId + * dropped item id */ - public void columnsAdded(Collection addedColumns) { - if (addedColumns.isEmpty()) { - return; + public void dropActiveItem(Object itemId) { + if (activeItemMap.containsKey(itemId)) { + droppedItems.add(itemId); } + } - for (GridValueChangeListener listener : valueChangeListeners - .values()) { - listener.addColumns(addedColumns); + private void dropListeners(Collection itemIds) { + for (Object itemId : droppedItems) { + assert activeItemMap.containsKey(itemId) : "Item ID should exist in the activeItemMap"; + + activeItemMap.remove(itemId).removeListener(); } } /** - * Handles the insertion of rows. - *

- * This method's responsibilities are to: - *

    - *
  • shift the internal bookkeeping by count if the - * insertion happens above currently active range - *
  • ignore rows inserted below the currently active range - *
  • shift (and deactivate) rows pushed out of view - *
  • activate rows that are inserted in the current viewport - *
+ * Gets a collection copy of currently active item ids. * - * @param firstIndex - * the index of the first inserted rows - * @param count - * the number of rows inserted at firstIndex + * @return collection of item ids */ - public void insertRows(int firstIndex, int count) { - if (firstIndex < activeRange.getStart()) { - moveListeners(activeRange, count); - activeRange = activeRange.offsetBy(count); - } else if (firstIndex < activeRange.getEnd()) { - int end = activeRange.getEnd(); - // Move rows from first added index by count - Range movedRange = Range.between(firstIndex, end); - moveListeners(movedRange, count); - // Remove excess listeners from extra rows - removeValueChangeListeners(Range.withLength(end, count)); - // Add listeners for new rows - final Range freshRange = Range.withLength(firstIndex, count); - addValueChangeListeners(freshRange); - } else { - // out of view, noop - } + public Collection getActiveItemIds() { + return new HashSet(activeItemMap.keySet()); } /** - * Handles the removal of rows. - *

- * This method's responsibilities are to: - *

    - *
  • shift the internal bookkeeping by count if the - * removal happens above currently active range - *
  • ignore rows removed below the currently active range - *
+ * Gets a collection copy of currently active ValueChangeListeners. * - * @param firstIndex - * the index of the first removed rows - * @param count - * the number of rows removed at firstIndex + * @return collection of value change listeners */ - public void removeRows(int firstIndex, int count) { - Range removed = Range.withLength(firstIndex, count); - if (removed.intersects(activeRange)) { - final Range[] deprecated = activeRange.partitionWith(removed); - // Remove the listeners that are no longer existing - removeValueChangeListeners(deprecated[1]); - - // Move remaining listeners to fill the listener map correctly - moveListeners(deprecated[2], -deprecated[1].length()); - activeRange = Range.withLength(activeRange.getStart(), - activeRange.length() - deprecated[1].length()); - - } else { - if (removed.getEnd() < activeRange.getStart()) { - /* firstIndex < lastIndex < start */ - moveListeners(activeRange, -count); - activeRange = activeRange.offsetBy(-count); - } - /* else: end <= firstIndex, no need to do anything */ - } - } - - /** - * Moves value change listeners in map with given index range by count - */ - private void moveListeners(Range movedRange, int diff) { - if (diff < 0) { - for (Integer i = movedRange.getStart(); i < movedRange.getEnd(); ++i) { - moveListener(i, i + diff); - } - } else if (diff > 0) { - for (Integer i = movedRange.getEnd() - 1; i >= movedRange - .getStart(); --i) { - moveListener(i, i + diff); - } - } else { - // diff == 0 should not happen. If it does, should be no-op - return; - } - } - - private void moveListener(Integer oldIndex, Integer newIndex) { - assert valueChangeListeners.get(newIndex) == null : "Overwriting existing listener"; - - GridValueChangeListener listener = valueChangeListeners - .remove(oldIndex); - assert listener != null : "Moving nonexisting listener."; - valueChangeListeners.put(newIndex, listener); + public Collection getValueChangeListeners() { + return new HashSet(activeItemMap.values()); } } @@ -724,8 +545,6 @@ public class RpcDataProviderExtension extends AbstractExtension { private final Indexed container; - private final ActiveRowHandler activeRowHandler = new ActiveRowHandler(); - private DataProviderRpc rpc; private final ItemSetChangeListener itemListener = new ItemSetChangeListener() { @@ -786,14 +605,6 @@ public class RpcDataProviderExtension extends AbstractExtension { * taking all the corner cases into account. */ - Map listeners = activeRowHandler.valueChangeListeners; - for (GridValueChangeListener listener : listeners.values()) { - listener.removeListener(); - } - - listeners.clear(); - activeRowHandler.activeRange = Range.withLength(0, 0); - for (Object itemId : visibleDetails) { detailComponentManager.destroyDetails(itemId); } @@ -834,6 +645,7 @@ public class RpcDataProviderExtension extends AbstractExtension { private Set visibleDetails = new HashSet(); private final DetailComponentManager detailComponentManager = new DetailComponentManager(); + private final ActiveItemHandler activeItemHandler = new ActiveItemHandler(); /** * Creates a new data provider using the given container. @@ -849,7 +661,6 @@ public class RpcDataProviderExtension extends AbstractExtension { @Override public void requestRows(int firstRow, int numberOfRows, int firstCachedRowIndex, int cacheSize) { - pushRowData(firstRow, numberOfRows, firstCachedRowIndex, cacheSize); } @@ -867,6 +678,11 @@ public class RpcDataProviderExtension extends AbstractExtension { keyMapper.unpin(itemId); } } + + @Override + public void dropRow(String rowKey) { + activeItemHandler.dropActiveItem(keyMapper.getItemId(rowKey)); + } }); if (container instanceof ItemSetChangeNotifier) { @@ -905,10 +721,9 @@ public class RpcDataProviderExtension extends AbstractExtension { // Send current rows again if needed. if (refreshCache) { - int firstRow = activeRowHandler.activeRange.getStart(); - int numberOfRows = activeRowHandler.activeRange.length(); - - pushRowData(firstRow, numberOfRows, firstRow, numberOfRows); + for (Object itemId : activeItemHandler.getActiveItemIds()) { + internalUpdateRowData(itemId); + } } } @@ -936,7 +751,6 @@ public class RpcDataProviderExtension extends AbstractExtension { List itemIds = container.getItemIds(fullRange.getStart(), fullRange.length()); - keyMapper.setActiveRows(itemIds); JsonArray rows = Json.createArray(); @@ -948,14 +762,16 @@ public class RpcDataProviderExtension extends AbstractExtension { for (int i = 0; i < newRange.length() && i + diff < itemIds.size(); ++i) { Object itemId = itemIds.get(i + diff); + rows.set(i, getRowData(getGrid().getColumns(), itemId)); } rpc.setRowData(firstRowToPush, rows); - activeRowHandler.setActiveRows(fullRange); + activeItemHandler.addActiveItems(itemIds); + keyMapper.dropInactiveItems(); } - private JsonValue getRowData(Collection columns, Object itemId) { + private JsonObject getRowData(Collection columns, Object itemId) { Item item = container.getItem(itemId); JsonObject rowData = Json.createObject(); @@ -1072,8 +888,6 @@ public class RpcDataProviderExtension extends AbstractExtension { rpc.insertRowData(index, count); } }); - - activeRowHandler.insertRows(index, count); } /** @@ -1098,8 +912,6 @@ public class RpcDataProviderExtension extends AbstractExtension { rpc.removeRowData(index, count); } }); - - activeRowHandler.removeRows(index, count); } /** @@ -1120,12 +932,9 @@ public class RpcDataProviderExtension extends AbstractExtension { } private void internalUpdateRowData(Object itemId) { - int index = container.indexOfId(itemId); - if (activeRowHandler.activeRange.contains(index)) { - JsonValue row = getRowData(getGrid().getColumns(), itemId); - JsonArray rowArray = Json.createArray(); - rowArray.set(0, row); - rpc.setRowData(index, rowArray); + if (activeItemHandler.getActiveItemIds().contains(itemId)) { + JsonObject row = getRowData(getGrid().getColumns(), itemId); + rpc.updateRowData(row); } } @@ -1143,9 +952,8 @@ public class RpcDataProviderExtension extends AbstractExtension { public void setParent(ClientConnector parent) { if (parent == null) { // We're being detached, release various listeners - - activeRowHandler - .removeValueChangeListeners(activeRowHandler.activeRange); + activeItemHandler.dropListeners(activeItemHandler + .getActiveItemIds()); if (container instanceof ItemSetChangeNotifier) { ((ItemSetChangeNotifier) container) @@ -1171,7 +979,13 @@ public class RpcDataProviderExtension extends AbstractExtension { * a list of removed columns */ public void columnsRemoved(List removedColumns) { - activeRowHandler.columnsRemoved(removedColumns); + for (GridValueChangeListener l : activeItemHandler + .getValueChangeListeners()) { + l.removeColumns(removedColumns); + } + + // No need to resend unchanged data. Client will remember the old + // columns until next set of rows is sent. } /** @@ -1181,7 +995,13 @@ public class RpcDataProviderExtension extends AbstractExtension { * a list of added columns */ public void columnsAdded(List addedColumns) { - activeRowHandler.columnsAdded(addedColumns); + for (GridValueChangeListener l : activeItemHandler + .getValueChangeListeners()) { + l.addColumns(addedColumns); + } + + // Resend all rows to contain new data. + refreshCache(); } public DataProviderKeyMapper getKeyMapper() { diff --git a/shared/src/com/vaadin/shared/data/DataProviderRpc.java b/shared/src/com/vaadin/shared/data/DataProviderRpc.java index 4bfdb8b6c5..bddbdd113d 100644 --- a/shared/src/com/vaadin/shared/data/DataProviderRpc.java +++ b/shared/src/com/vaadin/shared/data/DataProviderRpc.java @@ -20,6 +20,7 @@ import com.vaadin.shared.annotations.NoLayout; import com.vaadin.shared.communication.ClientRpc; import elemental.json.JsonArray; +import elemental.json.JsonObject; /** * RPC interface used for pushing container data to the client. @@ -91,4 +92,15 @@ public interface DataProviderRpc extends ClientRpc { * the size of the new data set */ public void resetDataAndSize(int size); + + /** + * Informs the client that a row has updated. The client-side DataSource + * will map the given data to correct index if it should be in the cache. + * + * @since + * @param row + * the updated row data + */ + @NoLayout + public void updateRowData(JsonObject row); } diff --git a/shared/src/com/vaadin/shared/data/DataRequestRpc.java b/shared/src/com/vaadin/shared/data/DataRequestRpc.java index 0d9b919a4e..84216f0fab 100644 --- a/shared/src/com/vaadin/shared/data/DataRequestRpc.java +++ b/shared/src/com/vaadin/shared/data/DataRequestRpc.java @@ -16,8 +16,8 @@ package com.vaadin.shared.data; -import com.vaadin.shared.annotations.NoLoadingIndicator; import com.vaadin.shared.annotations.Delayed; +import com.vaadin.shared.annotations.NoLoadingIndicator; import com.vaadin.shared.communication.ServerRpc; /** @@ -55,5 +55,17 @@ public interface DataRequestRpc extends ServerRpc { * pinned status of referenced item */ @Delayed + @NoLoadingIndicator public void setPinned(String key, boolean isPinned); + + /** + * Informs the server that an item is dropped from the client cache. + * + * @since + * @param rowKey + * key mapping to item + */ + @Delayed + @NoLoadingIndicator + public void dropRow(String rowKey); } diff --git a/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetach.java b/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetach.java index 1032378a2d..3d7f6da587 100644 --- a/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetach.java +++ b/uitest/src/com/vaadin/tests/components/grid/GridDetailsDetach.java @@ -56,7 +56,6 @@ public class GridDetailsDetach extends AbstractTestUI { layout.addComponent(new Button("Reattach Grid", new Button.ClickListener() { - @Override public void buttonClick(ClickEvent event) { gridContainer.removeAllComponents(); -- cgit v1.2.3 From bbf0e1749499194aff4bf827bba6aef8b0752c3c Mon Sep 17 00:00:00 2001 From: Henri Sara Date: Fri, 7 Aug 2015 13:00:00 +0300 Subject: Add optional OSGi imports for portals (#18561) Change-Id: Id13dc29347c93ad142c991f95f89cf04eb06db94 --- server/build.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/build.xml b/server/build.xml index 4bb2bde730..95c0b0add4 100644 --- a/server/build.xml +++ b/server/build.xml @@ -34,7 +34,7 @@ + value="javax.servlet;version="2.4.0",javax.servlet.http;version="2.4.0",javax.validation;version="1.0.0.GA";resolution:=optional,org.jsoup;version="1.6.3",org.jsoup.parser;version="1.6.3",org.jsoup.nodes;version="1.6.3",org.jsoup.helper;version="1.6.3",org.jsoup.safety;version="1.6.3",org.jsoup.select;version="1.6.3",javax.portlet;version="[2.0,3)";resolution:=optional,javax.portlet.filter;version="[2.0,3)";resolution:=optional,com.liferay.portal.kernel.util;resolution:=optional" /> -- cgit v1.2.3 From 7ed0d2a10e250b6ccadca1a6a1d3b9e52b9973b7 Mon Sep 17 00:00:00 2001 From: patrik Date: Mon, 3 Aug 2015 11:41:03 +0300 Subject: Prevent race-condition induced sporadic error in Escalator (#17258) Change-Id: I624c44056d43a6a3205be46a748070f269a3c3e3 --- .../src/com/vaadin/client/widgets/Escalator.java | 36 +++-- .../tests/components/grid/GridFastAsyncUpdate.java | 148 +++++++++++++++++++++ 2 files changed, 174 insertions(+), 10 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/grid/GridFastAsyncUpdate.java diff --git a/client/src/com/vaadin/client/widgets/Escalator.java b/client/src/com/vaadin/client/widgets/Escalator.java index 5b3d4e1b70..7b0bb3bfe4 100644 --- a/client/src/com/vaadin/client/widgets/Escalator.java +++ b/client/src/com/vaadin/client/widgets/Escalator.java @@ -2767,17 +2767,33 @@ public class Escalator extends Widget implements RequiresResize, // move the surrounding rows to their correct places. double rowTop = (unupdatedLogicalStart + (end - start)) * getDefaultRowHeight(); - final ListIterator i = visualRowOrder - .listIterator(visualTargetIndex + (end - start)); - int logicalRowIndexCursor = unupdatedLogicalStart; - while (i.hasNext()) { - rowTop += spacerContainer - .getSpacerHeight(logicalRowIndexCursor++); - - final TableRowElement tr = i.next(); - setRowPosition(tr, 0, rowTop); - rowTop += getDefaultRowHeight(); + // TODO: Get rid of this try/catch block by fixing the + // underlying issue. The reason for this erroneous behavior + // might be that Escalator actually works 'by mistake', and + // the order of operations is, in fact, wrong. + try { + final ListIterator i = visualRowOrder + .listIterator(visualTargetIndex + (end - start)); + + int logicalRowIndexCursor = unupdatedLogicalStart; + while (i.hasNext()) { + rowTop += spacerContainer + .getSpacerHeight(logicalRowIndexCursor++); + + final TableRowElement tr = i.next(); + setRowPosition(tr, 0, rowTop); + rowTop += getDefaultRowHeight(); + } + } catch (Exception e) { + Logger logger = getLogger(); + logger.warning("Ignored out-of-bounds row element access"); + logger.warning("Escalator state: start=" + start + + ", end=" + end + ", visualTargetIndex=" + + visualTargetIndex + + ", visualRowOrder.size()=" + + visualRowOrder.size()); + logger.warning(e.toString()); } } diff --git a/uitest/src/com/vaadin/tests/components/grid/GridFastAsyncUpdate.java b/uitest/src/com/vaadin/tests/components/grid/GridFastAsyncUpdate.java new file mode 100644 index 0000000000..31fe0275a5 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/GridFastAsyncUpdate.java @@ -0,0 +1,148 @@ +package com.vaadin.tests.components.grid; + +import java.util.Calendar; +import java.util.Random; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.logging.Level; + +import com.vaadin.annotations.Push; +import com.vaadin.annotations.Theme; +import com.vaadin.data.Item; +import com.vaadin.data.util.IndexedContainer; +import com.vaadin.event.SelectionEvent; +import com.vaadin.event.SelectionEvent.SelectionListener; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Grid; +import com.vaadin.ui.Grid.SelectionMode; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.VerticalLayout; + +@Push +@Theme("valo") +@SuppressWarnings("serial") +public class GridFastAsyncUpdate extends AbstractTestUI { + + private final Runnable addRowsTask = new Runnable() { + @Override + public void run() { + System.out.println("Logging..."); + try { + Random random = new Random(); + while (!Thread.currentThread().isInterrupted()) { + Thread.sleep(random.nextInt(100)); + + GridFastAsyncUpdate.this.access(new Runnable() { + @SuppressWarnings("unchecked") + @Override + public void run() { + + ++counter; + Item item = container.addItem(counter); + item.getItemProperty("sequenceNumber").setValue( + String.valueOf(counter)); + item.getItemProperty("millis").setValue( + String.valueOf(Calendar.getInstance() + .getTimeInMillis() - loggingStart)); + item.getItemProperty("level").setValue( + Level.INFO.toString()); + item.getItemProperty("message").setValue("Message"); + if (grid != null && !scrollLock) { + grid.scrollToEnd(); + } + } + }); + } + } catch (InterruptedException e) { + System.out.println("logging thread interrupted"); + } + } + }; + + private int counter; + + private Grid grid; + private IndexedContainer container; + private long loggingStart; + private volatile boolean scrollLock = false; + + @Override + protected void setup(VaadinRequest vaadinRequest) { + final VerticalLayout layout = new VerticalLayout(); + layout.setSizeFull(); + layout.setMargin(true); + addComponent(layout); + + HorizontalLayout buttons = new HorizontalLayout(); + layout.addComponent(buttons); + + final ExecutorService logExecutor = Executors.newSingleThreadExecutor(); + + final Button logButton = new Button("Start logging"); + logButton.addClickListener(new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + if ("Start logging".equals(logButton.getCaption())) { + loggingStart = Calendar.getInstance().getTimeInMillis(); + logExecutor.submit(addRowsTask); + logButton.setCaption("Stop logging"); + } else { + System.out.println("Stop logging..."); + try { + logExecutor.shutdownNow(); + } catch (Exception e) { + e.printStackTrace(); + } + logButton.setCaption("Start logging"); + } + } + }); + buttons.addComponent(logButton); + + final Button scrollButton = new Button("Stop scrolling"); + scrollButton.addClickListener(new Button.ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + if (!scrollLock) { + System.out.println("Stop scrolling"); + scrollButton.setCaption("Start scrolling"); + scrollLock = true; + } else { + System.out.println("Start scrolling"); + scrollButton.setCaption("Stop scrolling"); + scrollLock = false; + } + } + }); + buttons.addComponent(scrollButton); + + container = new IndexedContainer(); + container.addContainerProperty("sequenceNumber", String.class, null); + container.addContainerProperty("millis", String.class, null); + container.addContainerProperty("level", String.class, null); + container.addContainerProperty("message", String.class, null); + + grid = new Grid(container); + grid.setWidth("100%"); + grid.setImmediate(true); + grid.setSelectionMode(SelectionMode.SINGLE); + grid.addSelectionListener(new SelectionListener() { + @Override + public void select(final SelectionEvent event) { + if (grid.getSelectedRow() != null) { + disableScroll(); + } + } + }); + + layout.addComponent(grid); + layout.setExpandRatio(grid, 1.0f); + } + + protected void disableScroll() { + scrollLock = true; + } +} \ No newline at end of file -- cgit v1.2.3 From ba7071612bb546a74e49fcd82d37ceab9bbe420a Mon Sep 17 00:00:00 2001 From: patrik Date: Wed, 12 Aug 2015 16:02:50 +0300 Subject: Make Grid Editor return focus to last focused cell (#16834) Change-Id: Ifbea95c2b5b39ca3c4532baa7e3f9298423bc030 --- client/src/com/vaadin/client/widgets/Grid.java | 72 ++++++++++++++++++++-- .../basicfeatures/client/GridEditorClientTest.java | 12 +++- 2 files changed, 79 insertions(+), 5 deletions(-) diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index eb54f9c720..3271f51656 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -50,6 +50,9 @@ import com.google.gwt.dom.client.TableSectionElement; import com.google.gwt.dom.client.Touch; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.FocusEvent; +import com.google.gwt.event.dom.client.FocusHandler; +import com.google.gwt.event.dom.client.HasFocusHandlers; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.dom.client.KeyDownEvent; import com.google.gwt.event.dom.client.KeyDownHandler; @@ -1157,11 +1160,12 @@ public class Grid extends ResizeComposite implements private DivElement message = DivElement.as(DOM.createDiv()); private Map, Widget> columnToWidget = new HashMap, Widget>(); + private List focusHandlers = new ArrayList(); private boolean enabled = false; private State state = State.INACTIVE; private int rowIndex = -1; - private int columnIndex = -1; + private int focusedColumnIndex = -1; private String styleName = null; /* @@ -1363,7 +1367,8 @@ public class Grid extends ResizeComposite implements } } - this.columnIndex = columnIndex; + this.rowIndex = rowIndex; + this.focusedColumnIndex = columnIndex; state = State.ACTIVATING; if (grid.getEscalator().getVisibleRowRange().contains(rowIndex)) { @@ -1410,7 +1415,7 @@ public class Grid extends ResizeComposite implements hideOverlay(); state = State.INACTIVE; rowIndex = -1; - columnIndex = -1; + focusedColumnIndex = -1; grid.getEscalator().setScrollLocked(Direction.VERTICAL, false); updateSelectionCheckboxesAsNeeded(true); grid.fireEvent(new EditorCloseEvent(grid.eventCell)); @@ -1620,7 +1625,28 @@ public class Grid extends ResizeComposite implements attachWidget(editor, cell); } - if (i == columnIndex) { + final int currentColumnIndex = i; + if (editor instanceof HasFocusHandlers) { + // Use a proper focus handler if available + focusHandlers.add(((HasFocusHandlers) editor) + .addFocusHandler(new FocusHandler() { + @Override + public void onFocus(FocusEvent event) { + focusedColumnIndex = currentColumnIndex; + } + })); + } else { + // Try sniffing for DOM focus events + focusHandlers.add(editor.addDomHandler( + new FocusHandler() { + @Override + public void onFocus(FocusEvent event) { + focusedColumnIndex = currentColumnIndex; + } + }, FocusEvent.getType())); + } + + if (i == focusedColumnIndex) { if (editor instanceof Focusable) { ((Focusable) editor).focus(); } else if (editor instanceof com.google.gwt.user.client.ui.Focusable) { @@ -1750,6 +1776,11 @@ public class Grid extends ResizeComposite implements pinnedRowHandle = null; } + for (HandlerRegistration r : focusHandlers) { + r.removeHandler(); + } + focusHandlers.clear(); + for (Widget w : columnToWidget.values()) { setParent(w, null); } @@ -1766,6 +1797,10 @@ public class Grid extends ResizeComposite implements scrollHandler.removeHandler(); clearEditorColumnErrors(); + + if (focusedColumnIndex != -1) { + grid.focusCell(rowIndex, focusedColumnIndex); + } } protected void setStylePrimaryName(String primaryName) { @@ -5553,6 +5588,35 @@ public class Grid extends ResizeComposite implements } } + /** + * Try to focus a cell by row and column index. Purely internal method. + * + * @param rowIndex + * row index from Editor + * @param columnIndex + * column index from Editor + */ + void focusCell(int rowIndex, int columnIndex) { + RowReference row = new RowReference(this); + Range visibleRows = escalator.getVisibleRowRange(); + + TableRowElement rowElement; + if (visibleRows.contains(rowIndex)) { + rowElement = escalator.getBody().getRowElement(rowIndex); + } else { + rowElement = null; + getLogger().warning("Row index was not among visible row range"); + } + row.set(rowIndex, dataSource.getRow(rowIndex), rowElement); + + CellReference cell = new CellReference(row); + cell.set(columnIndex, columnIndex, getVisibleColumn(columnIndex)); + + cellFocusHandler.setCellFocus(cell); + + WidgetUtil.focus(getElement()); + } + /** * Refreshes all header rows */ diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java index 58d6559bfb..0dd137db48 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/client/GridEditorClientTest.java @@ -81,9 +81,19 @@ public class GridEditorClientTest extends GridBasicClientFeaturesTest { getGridElement().getCell(4, 0).doubleClick(); assertNotNull(getEditor()); - getCancelButton().click(); + // Move focus to the third input field + getEditor().findElements(By.className("gwt-TextBox")).get(2).click(); + + // Press save button + getSaveButton().click(); + + // Make sure the editor went away assertNull(getEditor()); + // Check that focus has moved to cell 4,2 - the last one that was + // focused in Editor + assertTrue(getGridElement().getCell(4, 2).isFocused()); + // Disable editor selectMenuPath("Component", "Editor", "Enabled"); -- cgit v1.2.3 From 5c56d140bebc5aaf23790c6abb081f5f2b2a5cf6 Mon Sep 17 00:00:00 2001 From: Teppo Kurki Date: Tue, 18 Aug 2015 21:46:39 +0300 Subject: Cut off Grid cell content when max column width is set (#18617) Change-Id: I912377ffe366e6ac46280b374fa04caa59c3bcf2 --- client/src/com/vaadin/client/widgets/Grid.java | 4 ++- .../grid/basicfeatures/GridBasicFeatures.java | 12 +++++++ .../server/GridColumnMaxWidthTest.java | 37 ++++++++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnMaxWidthTest.java diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 3271f51656..3cc02e763c 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -2992,8 +2992,9 @@ public class Grid extends ResizeComposite implements for (Column column : nonFixedColumns) { final int expandRatio = (defaultExpandRatios ? 1 : column .getExpandRatio()); - final double newWidth = column.getWidthActual(); final double maxWidth = getMaxWidth(column); + final double newWidth = Math.min(maxWidth, + column.getWidthActual()); boolean shouldExpand = newWidth < maxWidth && expandRatio > 0 && column != selectionColumn; if (shouldExpand) { @@ -3012,6 +3013,7 @@ public class Grid extends ResizeComposite implements double pixelsToDistribute = escalator.getInnerWidth() - reservedPixels; if (pixelsToDistribute <= 0 || totalRatios <= 0) { + setColumnSizes(columnSizes); return; } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java index 23226fb6cf..479ece71ca 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/GridBasicFeatures.java @@ -1174,6 +1174,18 @@ public class GridBasicFeatures extends AbstractComponentTest { } }); + + createClickAction("All columns expanding, Col 0 has max width of 30px", + "Columns", new Command() { + + @Override + public void execute(Grid c, Boolean value, Object data) { + for (Column col : grid.getColumns()) { + col.setWidthUndefined(); + } + grid.getColumns().get(0).setMaximumWidth(30); + } + }, null); } private static String getColumnProperty(int c) { diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnMaxWidthTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnMaxWidthTest.java new file mode 100644 index 0000000000..dffa22fdc6 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnMaxWidthTest.java @@ -0,0 +1,37 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.grid.basicfeatures.server; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest; + +public class GridColumnMaxWidthTest extends GridBasicFeaturesTest { + + @Test + public void testRemovingAllColumns() { + setDebug(true); + openTestURL(); + + selectMenuPath("Component", "Columns", + "All columns expanding, Col 0 has max width of 30px"); + + assertEquals("Column 0 did not obey max width of 30px.", "30px", + getGridElement().getCell(0, 0).getCssValue("width")); + } +} \ No newline at end of file -- cgit v1.2.3 From d40df1dc68f166bc23609d631420a34d1a0f2adf Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Sat, 4 Jul 2015 16:25:43 +0300 Subject: Column collapse events for Table (#6914) Change-Id: Ifeb081086a4231f75f07f4d26c56ec22e72ce5d1 --- server/src/com/vaadin/ui/Table.java | 89 +++++++++++++++- .../com/vaadin/shared/ui/table/TableConstants.java | 1 + .../table/ColumnCollapsingAndColumnExpansion.java | 64 ++++++------ .../ColumnCollapsingAndColumnExpansionTest.java | 112 +++++++++++++++++++++ .../tests/components/table/CustomTableElement.java | 57 +++++++++++ .../table/ColumnCollapsingAndColumnExpansion.html | 97 ------------------ 6 files changed, 291 insertions(+), 129 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansionTest.java create mode 100644 uitest/src/com/vaadin/tests/components/table/CustomTableElement.java delete mode 100644 uitest/tb2/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.html diff --git a/server/src/com/vaadin/ui/Table.java b/server/src/com/vaadin/ui/Table.java index 42c4beab6c..2cd4084ad9 100644 --- a/server/src/com/vaadin/ui/Table.java +++ b/server/src/com/vaadin/ui/Table.java @@ -69,6 +69,7 @@ import com.vaadin.shared.util.SharedUtil; import com.vaadin.ui.declarative.DesignAttributeHandler; import com.vaadin.ui.declarative.DesignContext; import com.vaadin.ui.declarative.DesignException; +import com.vaadin.util.ReflectTools; /** *

@@ -1310,6 +1311,8 @@ public class Table extends AbstractSelect implements Action.Container, * the desired collapsedness. * @throws IllegalStateException * if column collapsing is not allowed + * @throws IllegalArgumentException + * if the property id does not exist */ public void setColumnCollapsed(Object propertyId, boolean collapsed) throws IllegalStateException { @@ -1319,11 +1322,19 @@ public class Table extends AbstractSelect implements Action.Container, if (collapsed && noncollapsibleColumns.contains(propertyId)) { throw new IllegalStateException("The column is noncollapsible!"); } + if (!getContainerPropertyIds().contains(propertyId)) { + throw new IllegalArgumentException("Property '" + propertyId + + "' was not found in the container"); + } if (collapsed) { - collapsedColumns.add(propertyId); + if (collapsedColumns.add(propertyId)) { + fireColumnCollapseEvent(propertyId); + } } else { - collapsedColumns.remove(propertyId); + if (collapsedColumns.remove(propertyId)) { + fireColumnCollapseEvent(propertyId); + } } // Assures the visual refresh @@ -3182,6 +3193,10 @@ public class Table extends AbstractSelect implements Action.Container, } } + private void fireColumnCollapseEvent(Object propertyId) { + fireEvent(new ColumnCollapseEvent(this, propertyId)); + } + private void fireColumnResizeEvent(Object propertyId, int previousWidth, int currentWidth) { /* @@ -5741,6 +5756,53 @@ public class Table extends AbstractSelect implements Action.Container, public void columnReorder(ColumnReorderEvent event); } + /** + * This event is fired when the collapse state of a column changes + */ + public static class ColumnCollapseEvent extends Component.Event { + + public static final Method METHOD = ReflectTools.findMethod( + ColumnCollapseListener.class, "columnCollapseStateChange", + ColumnCollapseEvent.class); + private Object propertyId; + + /** + * Constructor + * + * @param source + * The source of the event + * @param propertyId + * The id of the coumn + */ + public ColumnCollapseEvent(Component source, Object propertyId) { + super(source); + this.propertyId = propertyId; + } + + /** + * Gets the id of the column whose collapse state changed + * + * @return the property id of the column + */ + public Object getPropertyId() { + return propertyId; + } + } + + /** + * Interface for listening to column collapse events. + */ + public interface ColumnCollapseListener extends Serializable { + + /** + * This method is triggered when the collapse state for a column has + * changed + * + * @param event + */ + public void columnCollapseStateChange(ColumnCollapseEvent event); + } + /** * Adds a column reorder listener to the Table. A column reorder listener is * called when a user reorders columns. @@ -5782,6 +5844,29 @@ public class Table extends AbstractSelect implements Action.Container, removeColumnReorderListener(listener); } + /** + * Adds a column collapse listener to the Table. A column collapse listener + * is called when the collapsed state of a column changes. + * + * @param listener + * The listener to attach + */ + public void addColumnCollapseListener(ColumnCollapseListener listener) { + addListener(TableConstants.COLUMN_COLLAPSE_EVENT_ID, + ColumnCollapseEvent.class, listener, ColumnCollapseEvent.METHOD); + } + + /** + * Removes a column reorder listener from the Table. + * + * @param listener + * The listener to remove + */ + public void removeColumnCollapseListener(ColumnCollapseListener listener) { + removeListener(TableConstants.COLUMN_COLLAPSE_EVENT_ID, + ColumnCollapseEvent.class, listener); + } + /** * Set the item description generator which generates tooltips for cells and * rows in the Table diff --git a/shared/src/com/vaadin/shared/ui/table/TableConstants.java b/shared/src/com/vaadin/shared/ui/table/TableConstants.java index fd1c61c772..e782492e9d 100644 --- a/shared/src/com/vaadin/shared/ui/table/TableConstants.java +++ b/shared/src/com/vaadin/shared/ui/table/TableConstants.java @@ -23,6 +23,7 @@ public class TableConstants implements Serializable { public static final String FOOTER_CLICK_EVENT_ID = "handleFooterClick"; public static final String COLUMN_RESIZE_EVENT_ID = "columnResize"; public static final String COLUMN_REORDER_EVENT_ID = "columnReorder"; + public static final String COLUMN_COLLAPSE_EVENT_ID = "columnCollapse"; @Deprecated public static final String ATTRIBUTE_PAGEBUFFER_FIRST = "pb-ft"; diff --git a/uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.java b/uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.java index 08b65e2ef5..8d1a9fc7df 100644 --- a/uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.java +++ b/uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.java @@ -2,21 +2,22 @@ package com.vaadin.tests.components.table; import com.vaadin.event.Action; import com.vaadin.event.Action.Handler; -import com.vaadin.tests.components.TestBase; -import com.vaadin.ui.Alignment; +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUIWithLog; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Table; -import com.vaadin.ui.TextField; +import com.vaadin.ui.Table.ColumnCollapseEvent; +import com.vaadin.ui.Table.ColumnCollapseListener; -public class ColumnCollapsingAndColumnExpansion extends TestBase { +public class ColumnCollapsingAndColumnExpansion extends AbstractTestUIWithLog { private Table table; @Override - public void setup() { + protected void setup(VaadinRequest request) { table = new Table(); @@ -50,41 +51,44 @@ public class ColumnCollapsingAndColumnExpansion extends TestBase { "cell " + 2 + "-" + y, "cell " + 3 + "-" + y, }, new Object()); } - - addComponent(table); - - HorizontalLayout hl = new HorizontalLayout(); - final TextField tf = new TextField("Column name (ColX)"); - Button hide = new Button("Collapse", new ClickListener() { + table.addColumnCollapseListener(new ColumnCollapseListener() { @Override - public void buttonClick(ClickEvent event) { - table.setColumnCollapsed(tf.getValue(), true); - } - - }); + public void columnCollapseStateChange(ColumnCollapseEvent event) { + log("Collapse state for " + event.getPropertyId() + + " changed to " + + table.isColumnCollapsed(event.getPropertyId())); - Button show = new Button("Show", new ClickListener() { - - @Override - public void buttonClick(ClickEvent event) { - table.setColumnCollapsed(tf.getValue(), false); } - }); + addComponent(table); - hl.addComponent(tf); - hl.addComponent(hide); - hl.addComponent(show); - hl.setComponentAlignment(tf, Alignment.BOTTOM_LEFT); - hl.setComponentAlignment(hide, Alignment.BOTTOM_LEFT); - hl.setComponentAlignment(show, Alignment.BOTTOM_LEFT); - addComponent(hl); + for (int i = 1; i <= 3; i++) { + HorizontalLayout hl = new HorizontalLayout(); + final String id = "Col" + i; + Button hide = new Button("Collapse " + id, new ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + table.setColumnCollapsed(id, true); + } + }); + + Button show = new Button("Show " + id, new ClickListener() { + @Override + public void buttonClick(ClickEvent event) { + table.setColumnCollapsed(id, false); + } + }); + + hl.addComponent(hide); + hl.addComponent(show); + addComponent(hl); + } } @Override - protected String getDescription() { + protected String getTestDescription() { return "After hiding column 2 the remaining columns (1 and 3) should use all available space in the table"; } diff --git a/uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansionTest.java b/uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansionTest.java new file mode 100644 index 0000000000..739851de2f --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansionTest.java @@ -0,0 +1,112 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.table; + +import java.io.IOException; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.JavascriptExecutor; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.TestBenchElement; +import com.vaadin.testbench.elements.ButtonElement; +import com.vaadin.testbench.parallel.BrowserUtil; +import com.vaadin.tests.components.table.CustomTableElement.ContextMenuElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class ColumnCollapsingAndColumnExpansionTest extends MultiBrowserTest { + + @Test + public void expandCorrectlyAfterCollapse() throws IOException { + openTestURL(); + + CustomTableElement table = $(CustomTableElement.class).first(); + + // Hide col2 through UI + table.openCollapseMenu().getItem(1).click(); + compareScreen(table, "col1-col3"); + + // Hide col1 using button + ButtonElement hide1 = $(ButtonElement.class).caption("Collapse Col1") + .first(); + hide1.click(); + compareScreen(table, "col3"); + + // Show column 2 using context menu (first action) + if (BrowserUtil.isIE8(getDesiredCapabilities())) { + // IE8 can context click but the popup is off screen so it can't be + // interacted with... + ButtonElement show2 = $(ButtonElement.class).caption("Show Col2") + .first(); + show2.click(); + } else { + contextClick(table.getCell(0, 0)); + ContextMenuElement contextMenu = table.getContextMenu(); + WebElement i = contextMenu.getItem(0); + i.click(); + } + compareScreen(table, "col2-col3"); + + // Show column 1 again + ButtonElement show1 = $(ButtonElement.class).caption("Show Col1") + .first(); + show1.click(); + + compareScreen(table, "col1-col2-col3"); + } + + private void contextClick(TestBenchElement e) { + if (e.isPhantomJS()) { + JavascriptExecutor js = e.getCommandExecutor(); + String scr = "var element=arguments[0];" + + "var ev = document.createEvent('HTMLEvents');" + + "ev.initEvent('contextmenu', true, false);" + + "element.dispatchEvent(ev);"; + js.executeScript(scr, e); + } else { + e.contextClick(); + } + + } + + @Test + public void collapseEvents() { + openTestURL(); + CustomTableElement table = $(CustomTableElement.class).first(); + + // Through menu + table.openCollapseMenu().getItem(0).click(); + Assert.assertEquals("1. Collapse state for Col1 changed to true", + getLogRow(0)); + + // Through button + $(ButtonElement.class).caption("Collapse Col2").first().click(); + Assert.assertEquals("2. Collapse state for Col2 changed to true", + getLogRow(0)); + + // Show through menu + table.openCollapseMenu().getItem(1).click(); + Assert.assertEquals("3. Collapse state for Col1 changed to false", + getLogRow(0)); + + // Show through button + $(ButtonElement.class).caption("Show Col2").first().click(); + Assert.assertEquals("4. Collapse state for Col2 changed to false", + getLogRow(0)); + + } +} diff --git a/uitest/src/com/vaadin/tests/components/table/CustomTableElement.java b/uitest/src/com/vaadin/tests/components/table/CustomTableElement.java new file mode 100644 index 0000000000..f1df98fb38 --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/table/CustomTableElement.java @@ -0,0 +1,57 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.table; + +import org.openqa.selenium.By; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.elements.TableElement; +import com.vaadin.testbench.elementsbase.AbstractElement; +import com.vaadin.testbench.elementsbase.ServerClass; + +@ServerClass("com.vaadin.ui.Table") +public class CustomTableElement extends TableElement { + + public CollapseMenu openCollapseMenu() { + getCollapseMenuToggle().click(); + WebElement cm = getDriver().findElement( + By.xpath("//*[@id='PID_VAADIN_CM']")); + return wrapElement(cm, getCommandExecutor()).wrap(CollapseMenu.class); + } + + public static class CollapseMenu extends ContextMenuElement { + } + + public WebElement getCollapseMenuToggle() { + return findElement(By.className("v-table-column-selector")); + } + + public static class ContextMenuElement extends AbstractElement { + + public WebElement getItem(int index) { + return findElement(By.xpath(".//table//tr[" + (index + 1) + + "]//td/*")); + } + + } + + public ContextMenuElement getContextMenu() { + WebElement cm = getDriver().findElement(By.className("v-contextmenu")); + return wrapElement(cm, getCommandExecutor()).wrap( + ContextMenuElement.class); + } + +} diff --git a/uitest/tb2/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.html b/uitest/tb2/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.html deleted file mode 100644 index 4dc63721a1..0000000000 --- a/uitest/tb2/com/vaadin/tests/components/table/ColumnCollapsingAndColumnExpansion.html +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - -ColumnCollapsingAndColumnExpansion - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ColumnCollapsingAndColumnExpansion
open/run/com.vaadin.tests.components.table.ColumnCollapsingAndColumnExpansion?restartApplication
screenCapturecol1-col2-col3-visible
clickvaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[0]/domChild[1]
mouseClick//tr[2]/td/span/div23,2
screenCapturecol2-hidden
enterCharactervaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VTextField[0]Col1
clickvaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[1]/VButton[0]/domChild[0]/domChild[0]
screenCapturecol1-col2-hidden
contextmenuvaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VScrollTable[0]/domChild[1]/domChild[0]/domChild[1]/domChild[0]/domChild[2]/domChild[0]/domChild[0]
mouseClickvaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VContextMenu[0]#option011,6
enterCharactervaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VTextField[0]Col2
screenCapturecol1-hidden
enterCharactervaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[0]/VTextField[0]Col1
clickvaadin=runcomvaadintestscomponentstableColumnCollapsingAndColumnExpansion::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VHorizontalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]
screenCapturecol1-col2-col3-visible-again
- - -- cgit v1.2.3 From 5db6f100da4c66ce394dffdfe16689be188314f1 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Fri, 21 Aug 2015 14:17:17 +0300 Subject: Fix AbstractRemoteDataSource cache clearing (#18630) This patch also reduces the amount of RPC calls when dropping rows from cache. Change-Id: Ib69a807883bc885dcd877a008cec16e44fa2bfdd --- .../client/connectors/RpcDataSourceConnector.java | 12 ++++-- .../client/data/AbstractRemoteDataSource.java | 45 ++++++++++++++++++---- .../com/vaadin/data/RpcDataProviderExtension.java | 9 +++-- .../src/com/vaadin/shared/data/DataRequestRpc.java | 10 +++-- 4 files changed, 57 insertions(+), 19 deletions(-) diff --git a/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java b/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java index 5680b09cef..79838f3252 100644 --- a/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java +++ b/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java @@ -107,10 +107,16 @@ public class RpcDataSourceConnector extends AbstractExtensionConnector { private DataRequestRpc rpcProxy = getRpcProxy(DataRequestRpc.class); private DetailsListener detailsListener; + private JsonArray droppedRowKeys = Json.createArray(); @Override protected void requestRows(int firstRowIndex, int numberOfRows, RequestRowsCallback callback) { + if (droppedRowKeys.length() > 0) { + rpcProxy.dropRows(droppedRowKeys); + droppedRowKeys = Json.createArray(); + } + /* * If you're looking at this code because you want to learn how to * use AbstactRemoteDataSource, please look somewhere else instead. @@ -235,10 +241,8 @@ public class RpcDataSourceConnector extends AbstractExtensionConnector { } @Override - protected void onDropFromCache(int rowIndex) { - super.onDropFromCache(rowIndex); - - rpcProxy.dropRow(getRowKey(getRow(rowIndex))); + protected void onDropFromCache(int rowIndex, JsonObject row) { + droppedRowKeys.set(droppedRowKeys.length(), getRowKey(row)); } } diff --git a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java index c8910f8699..256bc5ff6a 100644 --- a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java +++ b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java @@ -287,8 +287,7 @@ public abstract class AbstractRemoteDataSource implements DataSource { * Simple case: no overlap between cached data and needed data. * Clear the cache and request new data */ - indexToRowMap.clear(); - keyToIndexMap.clear(); + dropFromCache(cached); cached = Range.between(0, 0); handleMissingRows(getMaxCacheRange()); @@ -330,27 +329,48 @@ public abstract class AbstractRemoteDataSource implements DataSource { private void dropFromCache(Range range) { for (int i = range.getStart(); i < range.getEnd(); i++) { - // Called before dropping from cache, so we can actually do - // something with the data before the drop. - onDropFromCache(i); - + // Called after dropping from cache. Dropped row is passed as a + // parameter, but is no longer present in the DataSource T removed = indexToRowMap.remove(Integer.valueOf(i)); + onDropFromCache(i, removed); keyToIndexMap.remove(getRowKey(removed)); } } /** - * A hook that can be overridden to do something whenever a row is about to - * be dropped from the cache. + * A hook that can be overridden to do something whenever a row has been + * dropped from the cache. DataSource no longer has anything in the given + * index. + *

+ * NOTE: This method has been replaced. Override + * {@link #onDropFromCache(int, Object)} instead of this method. * * @since 7.5.0 * @param rowIndex * the index of the dropped row + * @deprecated replaced by {@link #onDropFromCache(int, Object)} */ + @Deprecated protected void onDropFromCache(int rowIndex) { // noop } + /** + * A hook that can be overridden to do something whenever a row has been + * dropped from the cache. DataSource no longer has anything in the given + * index. + * + * @since + * @param rowIndex + * the index of the dropped row + * @param removed + * the removed row object + */ + protected void onDropFromCache(int rowIndex, T removed) { + // Call old version as a fallback (someone might have used it) + onDropFromCache(rowIndex); + } + private void handleMissingRows(Range range) { if (range.isEmpty()) { return; @@ -481,6 +501,15 @@ public abstract class AbstractRemoteDataSource implements DataSource { * updated before the widget settings. Support for this will be * implemented later on. */ + + // Run a dummy drop from cache for unused rows. + for (int i = 0; i < partition[0].length(); ++i) { + onDropFromCache(i + partition[0].getStart(), rowData.get(i)); + } + + for (int i = 0; i < partition[2].length(); ++i) { + onDropFromCache(i + partition[2].getStart(), rowData.get(i)); + } } // Eventually check whether all needed rows are now available diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java index 403cc4c016..2ec100eba6 100644 --- a/server/src/com/vaadin/data/RpcDataProviderExtension.java +++ b/server/src/com/vaadin/data/RpcDataProviderExtension.java @@ -123,7 +123,7 @@ public class RpcDataProviderExtension extends AbstractExtension { * the item ids for which to get keys * @return keys for the {@code itemIds} */ - public List getKeys(Collection itemIds) { + public List getKeys(Collection itemIds) { if (itemIds == null) { throw new IllegalArgumentException("itemIds can't be null"); } @@ -698,8 +698,11 @@ public class RpcDataProviderExtension extends AbstractExtension { } @Override - public void dropRow(String rowKey) { - activeItemHandler.dropActiveItem(keyMapper.getItemId(rowKey)); + public void dropRows(JsonArray rowKeys) { + for (int i = 0; i < rowKeys.length(); ++i) { + activeItemHandler.dropActiveItem(keyMapper + .getItemId(rowKeys.getString(i))); + } } }); diff --git a/shared/src/com/vaadin/shared/data/DataRequestRpc.java b/shared/src/com/vaadin/shared/data/DataRequestRpc.java index 84216f0fab..041e92d05c 100644 --- a/shared/src/com/vaadin/shared/data/DataRequestRpc.java +++ b/shared/src/com/vaadin/shared/data/DataRequestRpc.java @@ -20,6 +20,8 @@ import com.vaadin.shared.annotations.Delayed; import com.vaadin.shared.annotations.NoLoadingIndicator; import com.vaadin.shared.communication.ServerRpc; +import elemental.json.JsonArray; + /** * RPC interface used for requesting container data to the client. * @@ -59,13 +61,13 @@ public interface DataRequestRpc extends ServerRpc { public void setPinned(String key, boolean isPinned); /** - * Informs the server that an item is dropped from the client cache. + * Informs the server that items have been dropped from the client cache. * * @since - * @param rowKey - * key mapping to item + * @param rowKeys + * array of dropped keys mapping to items */ @Delayed @NoLoadingIndicator - public void dropRow(String rowKey); + public void dropRows(JsonArray rowKeys); } -- cgit v1.2.3 From 03c262b21bf91f6635e6725e4fd8f79d67359b93 Mon Sep 17 00:00:00 2001 From: Mika Murtojarvi Date: Wed, 19 Aug 2015 17:11:49 +0300 Subject: Add missing @since tags. Previously, they were only updated in the 7.5 branch. Change-Id: Ic889c2f6a6d150a013adb5895c191c5107e8c6df --- .../com/vaadin/data/util/converter/StringToBooleanConverter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/server/src/com/vaadin/data/util/converter/StringToBooleanConverter.java b/server/src/com/vaadin/data/util/converter/StringToBooleanConverter.java index dafcf8dac2..f965cfcc6a 100644 --- a/server/src/com/vaadin/data/util/converter/StringToBooleanConverter.java +++ b/server/src/com/vaadin/data/util/converter/StringToBooleanConverter.java @@ -44,7 +44,7 @@ public class StringToBooleanConverter implements Converter { /** * Creates converter with custom string representation. * - * @since + * @since 7.5.4 * @param falseString string representation for false * @param trueString string representation for true */ @@ -124,7 +124,7 @@ public class StringToBooleanConverter implements Converter { * Gets the locale-depended string representation for false. * Default is locale-independent value provided by {@link #getFalseString()} * - * @since + * @since 7.5.4 * @param locale to be used * @return the string representation for false */ @@ -136,7 +136,7 @@ public class StringToBooleanConverter implements Converter { * Gets the locale-depended string representation for true. * Default is locale-independent value provided by {@link #getTrueString()} * - * @since + * @since 7.5.4 * @param locale to be used * @return the string representation for true */ -- cgit v1.2.3 From e007f059b28f686109705ad1972cfdb6adc7ec43 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 14 Jul 2015 19:33:49 +0300 Subject: Use correct classname for ValoTheme.SCROLL_INDICATOR (#14802) Use constants in Valo tests to ensure they are correct Change-Id: Ie8234a45a6f81551cdc4de2e81141aba704f4b6b --- server/src/com/vaadin/ui/themes/ValoTheme.java | 2 +- .../com/vaadin/tests/themes/valo/Accordions.java | 5 +- .../tests/themes/valo/AlignTopIconInButton.java | 3 +- .../vaadin/tests/themes/valo/ButtonsAndLinks.java | 47 ++++++------- .../com/vaadin/tests/themes/valo/CalendarTest.java | 10 +-- .../com/vaadin/tests/themes/valo/CheckBoxes.java | 25 +++---- .../com/vaadin/tests/themes/valo/ColorPickers.java | 5 +- .../com/vaadin/tests/themes/valo/ComboBoxes.java | 19 +++--- .../com/vaadin/tests/themes/valo/CommonParts.java | 79 +++++++++++----------- .../com/vaadin/tests/themes/valo/DateFields.java | 19 +++--- .../src/com/vaadin/tests/themes/valo/Dragging.java | 15 ++-- uitest/src/com/vaadin/tests/themes/valo/Forms.java | 31 +++++---- .../src/com/vaadin/tests/themes/valo/Labels.java | 27 ++++---- .../src/com/vaadin/tests/themes/valo/MenuBars.java | 31 +++++---- .../vaadin/tests/themes/valo/NativeSelects.java | 5 +- .../tests/themes/valo/NotificationStyleTest.java | 4 +- .../src/com/vaadin/tests/themes/valo/Panels.java | 29 ++++---- .../com/vaadin/tests/themes/valo/PopupViews.java | 5 +- .../src/com/vaadin/tests/themes/valo/Sliders.java | 15 ++-- .../com/vaadin/tests/themes/valo/SplitPanels.java | 9 +-- .../src/com/vaadin/tests/themes/valo/Tables.java | 51 +++++++------- .../com/vaadin/tests/themes/valo/Tabsheets.java | 9 +-- .../com/vaadin/tests/themes/valo/TextFields.java | 73 ++++++++++---------- uitest/src/com/vaadin/tests/themes/valo/Trees.java | 5 +- .../vaadin/tests/themes/valo/ValoMenuLayout.java | 5 +- .../com/vaadin/tests/themes/valo/ValoThemeUI.java | 26 +++---- 26 files changed, 289 insertions(+), 265 deletions(-) diff --git a/server/src/com/vaadin/ui/themes/ValoTheme.java b/server/src/com/vaadin/ui/themes/ValoTheme.java index 1285bf7f67..3a9986c632 100644 --- a/server/src/com/vaadin/ui/themes/ValoTheme.java +++ b/server/src/com/vaadin/ui/themes/ValoTheme.java @@ -709,7 +709,7 @@ public class ValoTheme { * area is scrolled. Suitable with the {@link #PANEL_BORDERLESS} style. Can * be combined with any other Panel style. */ - public static final String PANEL_SCROLL_INDICATOR = "scroll-indicator"; + public static final String PANEL_SCROLL_INDICATOR = "scroll-divider"; /** * Inset panel style. Can be combined with any other Panel style. diff --git a/uitest/src/com/vaadin/tests/themes/valo/Accordions.java b/uitest/src/com/vaadin/tests/themes/valo/Accordions.java index c32be01d8d..3c7ad2ad33 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/Accordions.java +++ b/uitest/src/com/vaadin/tests/themes/valo/Accordions.java @@ -21,13 +21,14 @@ import com.vaadin.ui.Accordion; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; public class Accordions extends VerticalLayout implements View { public Accordions() { setMargin(true); Label h1 = new Label("Accordions"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); HorizontalLayout row = new HorizontalLayout(); @@ -38,7 +39,7 @@ public class Accordions extends VerticalLayout implements View { row.addComponent(getAccordion("Normal")); Accordion ac = getAccordion("Borderless"); - ac.addStyleName("borderless"); + ac.addStyleName(ValoTheme.ACCORDION_BORDERLESS); row.addComponent(ac); } diff --git a/uitest/src/com/vaadin/tests/themes/valo/AlignTopIconInButton.java b/uitest/src/com/vaadin/tests/themes/valo/AlignTopIconInButton.java index dc257fb3ec..eb4be8e0d8 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/AlignTopIconInButton.java +++ b/uitest/src/com/vaadin/tests/themes/valo/AlignTopIconInButton.java @@ -20,6 +20,7 @@ import com.vaadin.server.ThemeResource; import com.vaadin.server.VaadinRequest; import com.vaadin.tests.components.AbstractTestUI; import com.vaadin.ui.Button; +import com.vaadin.ui.themes.ValoTheme; /** * Test UI for image icon in button with 'icon-align-top' style. @@ -34,7 +35,7 @@ public class AlignTopIconInButton extends AbstractTestUI { Button button = new Button(); button.setIcon(new ThemeResource("../runo/icons/16/document.png")); addComponent(button); - button.addStyleName("icon-align-top"); + button.addStyleName(ValoTheme.BUTTON_ICON_ALIGN_TOP); button.setCaption("caption"); } diff --git a/uitest/src/com/vaadin/tests/themes/valo/ButtonsAndLinks.java b/uitest/src/com/vaadin/tests/themes/valo/ButtonsAndLinks.java index 9ed48896eb..ee88595ba7 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/ButtonsAndLinks.java +++ b/uitest/src/com/vaadin/tests/themes/valo/ButtonsAndLinks.java @@ -25,6 +25,7 @@ import com.vaadin.ui.Label; import com.vaadin.ui.Link; import com.vaadin.ui.NativeButton; import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; /** * @@ -39,11 +40,11 @@ public class ButtonsAndLinks extends VerticalLayout implements View { setMargin(true); Label h1 = new Label("Buttons"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); HorizontalLayout row = new HorizontalLayout(); - row.addStyleName("wrapping"); + row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); row.setSpacing(true); addComponent(row); @@ -55,30 +56,30 @@ public class ButtonsAndLinks extends VerticalLayout implements View { row.addComponent(button); button = new Button("Primary"); - button.addStyleName("primary"); + button.addStyleName(ValoTheme.BUTTON_PRIMARY); row.addComponent(button); button = new Button("Friendly"); - button.addStyleName("friendly"); + button.addStyleName(ValoTheme.BUTTON_FRIENDLY); row.addComponent(button); button = new Button("Danger"); - button.addStyleName("danger"); + button.addStyleName(ValoTheme.BUTTON_DANGER); row.addComponent(button); TestIcon testIcon = new TestIcon(10); button = new Button("Small"); - button.addStyleName("small"); + button.addStyleName(ValoTheme.BUTTON_SMALL); button.setIcon(testIcon.get()); row.addComponent(button); button = new Button("Large"); - button.addStyleName("large"); + button.addStyleName(ValoTheme.BUTTON_LARGE); button.setIcon(testIcon.get()); row.addComponent(button); button = new Button("Top"); - button.addStyleName("icon-align-top"); + button.addStyleName(ValoTheme.BUTTON_ICON_ALIGN_TOP); button.setIcon(testIcon.get()); row.addComponent(button); @@ -87,7 +88,7 @@ public class ButtonsAndLinks extends VerticalLayout implements View { row.addComponent(button); button = new Button("Image icon"); - button.addStyleName("icon-align-right"); + button.addStyleName(ValoTheme.BUTTON_ICON_ALIGN_RIGHT); button.setIcon(testIcon.get(true)); row.addComponent(button); @@ -97,36 +98,36 @@ public class ButtonsAndLinks extends VerticalLayout implements View { button = new Button(); button.setIcon(testIcon.get()); - button.addStyleName("icon-only"); + button.addStyleName(ValoTheme.BUTTON_ICON_ONLY); row.addComponent(button); button = new Button("Borderless"); button.setIcon(testIcon.get()); - button.addStyleName("borderless"); + button.addStyleName(ValoTheme.BUTTON_BORDERLESS); row.addComponent(button); button = new Button("Borderless, colored"); button.setIcon(testIcon.get()); - button.addStyleName("borderless-colored"); + button.addStyleName(ValoTheme.BUTTON_BORDERLESS_COLORED); row.addComponent(button); button = new Button("Quiet"); button.setIcon(testIcon.get()); - button.addStyleName("quiet"); + button.addStyleName(ValoTheme.BUTTON_QUIET); row.addComponent(button); button = new Button("Link style"); button.setIcon(testIcon.get()); - button.addStyleName("link"); + button.addStyleName(ValoTheme.BUTTON_LINK); row.addComponent(button); button = new Button("Icon on right"); button.setIcon(testIcon.get()); - button.addStyleName("icon-align-right"); + button.addStyleName(ValoTheme.BUTTON_ICON_ALIGN_RIGHT); row.addComponent(button); CssLayout group = new CssLayout(); - group.addStyleName("v-component-group"); + group.addStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP); row.addComponent(group); button = new Button("One"); @@ -137,22 +138,22 @@ public class ButtonsAndLinks extends VerticalLayout implements View { group.addComponent(button); button = new Button("Tiny"); - button.addStyleName("tiny"); + button.addStyleName(ValoTheme.BUTTON_TINY); row.addComponent(button); button = new Button("Huge"); - button.addStyleName("huge"); + button.addStyleName(ValoTheme.BUTTON_HUGE); row.addComponent(button); NativeButton nbutton = new NativeButton("Native"); row.addComponent(nbutton); h1 = new Label("Links"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); row = new HorizontalLayout(); - row.addStyleName("wrapping"); + row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); row.setSpacing(true); addComponent(row); @@ -167,16 +168,16 @@ public class ButtonsAndLinks extends VerticalLayout implements View { row.addComponent(link); link = new Link("Small", new ExternalResource("https://vaadin.com")); - link.addStyleName("small"); + link.addStyleName(ValoTheme.LINK_SMALL); row.addComponent(link); link = new Link("Large", new ExternalResource("https://vaadin.com")); - link.addStyleName("large"); + link.addStyleName(ValoTheme.LINK_LARGE); row.addComponent(link); link = new Link(null, new ExternalResource("https://vaadin.com")); link.setIcon(testIcon.get()); - link.addStyleName("large"); + link.addStyleName(ValoTheme.LINK_LARGE); row.addComponent(link); link = new Link("Disabled", new ExternalResource("https://vaadin.com")); diff --git a/uitest/src/com/vaadin/tests/themes/valo/CalendarTest.java b/uitest/src/com/vaadin/tests/themes/valo/CalendarTest.java index 280ddf98b7..e18665f2fa 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/CalendarTest.java +++ b/uitest/src/com/vaadin/tests/themes/valo/CalendarTest.java @@ -286,7 +286,7 @@ public class CalendarTest extends GridLayout implements View { hl.addComponent(captionLabel); CssLayout group = new CssLayout(); - group.addStyleName("v-component-group"); + group.addStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP); group.addComponent(dayButton); group.addComponent(weekButton); group.addComponent(monthButton); @@ -922,7 +922,7 @@ public class CalendarTest extends GridLayout implements View { scheduleEventPopup.setModal(true); scheduleEventPopup.center(); - scheduleEventFieldLayout.addStyleName("light"); + scheduleEventFieldLayout.addStyleName(ValoTheme.FORMLAYOUT_LIGHT); scheduleEventFieldLayout.setMargin(false); layout.addComponent(scheduleEventFieldLayout); @@ -939,7 +939,7 @@ public class CalendarTest extends GridLayout implements View { } } }); - applyEventButton.addStyleName("primary"); + applyEventButton.addStyleName(ValoTheme.BUTTON_PRIMARY); Button cancel = new Button("Cancel", new ClickListener() { private static final long serialVersionUID = 1L; @@ -958,7 +958,7 @@ public class CalendarTest extends GridLayout implements View { deleteCalendarEvent(); } }); - deleteEventButton.addStyleName("borderless"); + deleteEventButton.addStyleName(ValoTheme.BUTTON_BORDERLESS); scheduleEventPopup.addCloseListener(new Window.CloseListener() { private static final long serialVersionUID = 1L; @@ -970,7 +970,7 @@ public class CalendarTest extends GridLayout implements View { }); HorizontalLayout buttons = new HorizontalLayout(); - buttons.addStyleName("v-window-bottom-toolbar"); + buttons.addStyleName(ValoTheme.WINDOW_BOTTOM_TOOLBAR); buttons.setWidth("100%"); buttons.setSpacing(true); buttons.addComponent(deleteEventButton); diff --git a/uitest/src/com/vaadin/tests/themes/valo/CheckBoxes.java b/uitest/src/com/vaadin/tests/themes/valo/CheckBoxes.java index 9a889b3bda..f77cf9a315 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/CheckBoxes.java +++ b/uitest/src/com/vaadin/tests/themes/valo/CheckBoxes.java @@ -23,17 +23,18 @@ import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.OptionGroup; import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; public class CheckBoxes extends VerticalLayout implements View { public CheckBoxes() { setMargin(true); Label h1 = new Label("Check Boxes"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); HorizontalLayout row = new HorizontalLayout(); - row.addStyleName("wrapping"); + row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); row.setSpacing(true); addComponent(row); @@ -72,11 +73,11 @@ public class CheckBoxes extends VerticalLayout implements View { row.addComponent(check); check = new CheckBox("Small", true); - check.addStyleName("small"); + check.addStyleName(ValoTheme.CHECKBOX_SMALL); row.addComponent(check); check = new CheckBox("Large", true); - check.addStyleName("large"); + check.addStyleName(ValoTheme.CHECKBOX_LARGE); row.addComponent(check); check = new CheckBox("Disabled", true); @@ -90,11 +91,11 @@ public class CheckBoxes extends VerticalLayout implements View { row.addComponent(check); h1 = new Label("Option Groups"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); row = new HorizontalLayout(); - row.addStyleName("wrapping"); + row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); row.setSpacing(true); addComponent(row); @@ -124,7 +125,7 @@ public class CheckBoxes extends VerticalLayout implements View { row.addComponent(options); options = new OptionGroup("Choose one, small"); - options.addStyleName("small"); + options.addStyleName(ValoTheme.OPTIONGROUP_SMALL); options.setMultiSelect(false); options.addItem("Option One"); options.addItem("Option Two"); @@ -136,7 +137,7 @@ public class CheckBoxes extends VerticalLayout implements View { row.addComponent(options); options = new OptionGroup("Choose many, small"); - options.addStyleName("small"); + options.addStyleName(ValoTheme.OPTIONGROUP_SMALL); options.setMultiSelect(true); options.addItem("Option One"); options.addItem("Option Two"); @@ -148,7 +149,7 @@ public class CheckBoxes extends VerticalLayout implements View { row.addComponent(options); options = new OptionGroup("Choose one, large"); - options.addStyleName("large"); + options.addStyleName(ValoTheme.OPTIONGROUP_LARGE); options.setMultiSelect(false); options.addItem("Option One"); options.addItem("Option Two"); @@ -160,7 +161,7 @@ public class CheckBoxes extends VerticalLayout implements View { row.addComponent(options); options = new OptionGroup("Choose many, large"); - options.addStyleName("large"); + options.addStyleName(ValoTheme.OPTIONGROUP_LARGE); options.setMultiSelect(true); options.addItem("Option One"); options.addItem("Option Two"); @@ -172,7 +173,7 @@ public class CheckBoxes extends VerticalLayout implements View { row.addComponent(options); options = new OptionGroup("Horizontal items"); - options.addStyleName("horizontal"); + options.addStyleName(ValoTheme.OPTIONGROUP_HORIZONTAL); options.addItem("Option One"); two = options.addItem("Option Two, with a longer caption"); options.addItem("Option Three"); @@ -185,7 +186,7 @@ public class CheckBoxes extends VerticalLayout implements View { options = new OptionGroup("Horizontal items, explicit width"); options.setMultiSelect(true); options.setWidth("500px"); - options.addStyleName("horizontal"); + options.addStyleName(ValoTheme.OPTIONGROUP_HORIZONTAL); options.addItem("Option One"); two = options.addItem("Option Two, with a longer caption"); options.addItem("Option Three"); diff --git a/uitest/src/com/vaadin/tests/themes/valo/ColorPickers.java b/uitest/src/com/vaadin/tests/themes/valo/ColorPickers.java index a7fd60ea51..8e32b07ebd 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/ColorPickers.java +++ b/uitest/src/com/vaadin/tests/themes/valo/ColorPickers.java @@ -23,17 +23,18 @@ import com.vaadin.ui.ColorPicker; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; public class ColorPickers extends VerticalLayout implements View { public ColorPickers() { setMargin(true); Label h1 = new Label("Color Pickers"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); HorizontalLayout row = new HorizontalLayout(); - row.addStyleName("wrapping"); + row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); row.setSpacing(true); addComponent(row); diff --git a/uitest/src/com/vaadin/tests/themes/valo/ComboBoxes.java b/uitest/src/com/vaadin/tests/themes/valo/ComboBoxes.java index 98a9cad83c..4a88d87cd2 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/ComboBoxes.java +++ b/uitest/src/com/vaadin/tests/themes/valo/ComboBoxes.java @@ -25,17 +25,18 @@ import com.vaadin.ui.CssLayout; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; public class ComboBoxes extends VerticalLayout implements View { public ComboBoxes() { setMargin(true); Label h1 = new Label("Combo Boxes"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); HorizontalLayout row = new HorizontalLayout(); - row.addStyleName("wrapping"); + row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); row.setSpacing(true); addComponent(row); @@ -52,7 +53,7 @@ public class ComboBoxes extends VerticalLayout implements View { CssLayout group = new CssLayout(); group.setCaption("Grouped with a Button"); - group.addStyleName("v-component-group"); + group.addStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP); row.addComponent(group); combo = new ComboBox(); @@ -104,7 +105,7 @@ public class ComboBoxes extends VerticalLayout implements View { combo.setNullSelectionAllowed(false); combo.select("Option One"); combo.setComponentError(new UserError("Fix it, now!")); - combo.addStyleName("borderless"); + combo.addStyleName(ValoTheme.COMBOBOX_BORDERLESS); row.addComponent(combo); combo = new ComboBox("Disabled"); @@ -144,7 +145,7 @@ public class ComboBoxes extends VerticalLayout implements View { combo.setContainerDataSource(ValoThemeUI.generateContainer(200, false)); combo.setItemCaptionPropertyId(ValoThemeUI.CAPTION_PROPERTY); combo.setItemIconPropertyId(ValoThemeUI.ICON_PROPERTY); - combo.addStyleName("small"); + combo.addStyleName(ValoTheme.COMBOBOX_SMALL); row.addComponent(combo); combo = new ComboBox("Large"); @@ -152,7 +153,7 @@ public class ComboBoxes extends VerticalLayout implements View { combo.setContainerDataSource(ValoThemeUI.generateContainer(200, false)); combo.setItemCaptionPropertyId(ValoThemeUI.CAPTION_PROPERTY); combo.setItemIconPropertyId(ValoThemeUI.ICON_PROPERTY); - combo.addStyleName("large"); + combo.addStyleName(ValoTheme.COMBOBOX_LARGE); row.addComponent(combo); combo = new ComboBox("Borderless"); @@ -160,7 +161,7 @@ public class ComboBoxes extends VerticalLayout implements View { combo.addItem("Option One"); combo.addItem("Option Two"); combo.addItem("Option Three"); - combo.addStyleName("borderless"); + combo.addStyleName(ValoTheme.COMBOBOX_BORDERLESS); row.addComponent(combo); combo = new ComboBox("Tiny"); @@ -168,7 +169,7 @@ public class ComboBoxes extends VerticalLayout implements View { combo.setContainerDataSource(ValoThemeUI.generateContainer(200, false)); combo.setItemCaptionPropertyId(ValoThemeUI.CAPTION_PROPERTY); combo.setItemIconPropertyId(ValoThemeUI.ICON_PROPERTY); - combo.addStyleName("tiny"); + combo.addStyleName(ValoTheme.COMBOBOX_TINY); row.addComponent(combo); combo = new ComboBox("Huge"); @@ -176,7 +177,7 @@ public class ComboBoxes extends VerticalLayout implements View { combo.setContainerDataSource(ValoThemeUI.generateContainer(200, false)); combo.setItemCaptionPropertyId(ValoThemeUI.CAPTION_PROPERTY); combo.setItemIconPropertyId(ValoThemeUI.ICON_PROPERTY); - combo.addStyleName("huge"); + combo.addStyleName(ValoTheme.COMBOBOX_HUGE); row.addComponent(combo); } diff --git a/uitest/src/com/vaadin/tests/themes/valo/CommonParts.java b/uitest/src/com/vaadin/tests/themes/valo/CommonParts.java index 52cc43ac28..ea7c42ba2e 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/CommonParts.java +++ b/uitest/src/com/vaadin/tests/themes/valo/CommonParts.java @@ -51,13 +51,14 @@ import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.Window; import com.vaadin.ui.Window.CloseEvent; import com.vaadin.ui.Window.CloseListener; +import com.vaadin.ui.themes.ValoTheme; public class CommonParts extends VerticalLayout implements View { public CommonParts() { setMargin(true); Label h1 = new Label("Common UI Elements"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); GridLayout row = new GridLayout(2, 3); @@ -83,7 +84,7 @@ public class CommonParts extends VerticalLayout implements View { CssLayout group = new CssLayout(); group.setCaption("Show the loading indicator for…"); - group.addStyleName("v-component-group"); + group.addStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP); content.addComponent(group); Button loading = new Button("0.8"); loading.addClickListener(new ClickListener() { @@ -127,13 +128,13 @@ public class CommonParts extends VerticalLayout implements View { Label spinnerDesc = new Label( "The theme also provides a mixin that you can use to include a spinner anywhere in your application. Below is a Label with a custom style name, for which the spinner mixin is added."); - spinnerDesc.addStyleName("small"); + spinnerDesc.addStyleName(ValoTheme.LABEL_SMALL); spinnerDesc.setCaption("Spinner"); content.addComponent(spinnerDesc); if (!ValoThemeUI.isTestMode()) { Label spinner = new Label(); - spinner.addStyleName("spinner"); + spinner.addStyleName(ValoTheme.LABEL_SPINNER); content.addComponent(spinner); } @@ -172,7 +173,7 @@ public class CommonParts extends VerticalLayout implements View { addComponent(title); description.setInputPrompt("Description for the notification"); - description.addStyleName("small"); + description.addStyleName(ValoTheme.TEXTAREA_SMALL); description.addValueChangeListener(new ValueChangeListener() { @Override public void valueChange(ValueChangeEvent event) { @@ -217,7 +218,7 @@ public class CommonParts extends VerticalLayout implements View { type.addItem("Error", typeCommand).setCheckable(true); type.addItem("System", typeCommand).setCheckable(true); addComponent(type); - type.addStyleName("small"); + type.addStyleName(ValoTheme.MENUBAR_SMALL); Command styleCommand = new Command() { @Override @@ -249,16 +250,16 @@ public class CommonParts extends VerticalLayout implements View { style.addItem("Small", styleCommand).setCheckable(true); style.addItem("Closable", styleCommand).setCheckable(true); addComponent(style); - style.addStyleName("small"); + style.addStyleName(ValoTheme.MENUBAR_SMALL); CssLayout group = new CssLayout(); group.setCaption("Fade delay"); - group.addStyleName("v-component-group"); + group.addStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP); addComponent(group); delay.setInputPrompt("Infinite"); - delay.addStyleName("align-right"); - delay.addStyleName("small"); + delay.addStyleName(ValoTheme.TEXTFIELD_ALIGN_RIGHT); + delay.addStyleName(ValoTheme.TEXTFIELD_SMALL); delay.setWidth("7em"); delay.addValueChangeListener(new ValueChangeListener() { @Override @@ -284,8 +285,8 @@ public class CommonParts extends VerticalLayout implements View { }); clear.setIcon(FontAwesome.TIMES_CIRCLE); clear.addStyleName("last"); - clear.addStyleName("small"); - clear.addStyleName("icon-only"); + clear.addStyleName(ValoTheme.BUTTON_SMALL); + clear.addStyleName(ValoTheme.BUTTON_ICON_ONLY); group.addComponent(clear); group.addComponent(new Label("  msec", ContentMode.HTML)); @@ -301,7 +302,7 @@ public class CommonParts extends VerticalLayout implements View { notification.show(Page.getCurrent()); } }); - pos.addStyleName("small"); + pos.addStyleName(ValoTheme.BUTTON_SMALL); grid.addComponent(pos); pos = new Button("", new ClickListener() { @@ -311,7 +312,7 @@ public class CommonParts extends VerticalLayout implements View { notification.show(Page.getCurrent()); } }); - pos.addStyleName("small"); + pos.addStyleName(ValoTheme.BUTTON_SMALL); grid.addComponent(pos); pos = new Button("", new ClickListener() { @@ -321,7 +322,7 @@ public class CommonParts extends VerticalLayout implements View { notification.show(Page.getCurrent()); } }); - pos.addStyleName("small"); + pos.addStyleName(ValoTheme.BUTTON_SMALL); grid.addComponent(pos); pos = new Button("", new ClickListener() { @@ -331,7 +332,7 @@ public class CommonParts extends VerticalLayout implements View { notification.show(Page.getCurrent()); } }); - pos.addStyleName("small"); + pos.addStyleName(ValoTheme.BUTTON_SMALL); grid.addComponent(pos); pos = new Button("", new ClickListener() { @@ -341,7 +342,7 @@ public class CommonParts extends VerticalLayout implements View { notification.show(Page.getCurrent()); } }); - pos.addStyleName("small"); + pos.addStyleName(ValoTheme.BUTTON_SMALL); grid.addComponent(pos); pos = new Button("", new ClickListener() { @@ -351,7 +352,7 @@ public class CommonParts extends VerticalLayout implements View { notification.show(Page.getCurrent()); } }); - pos.addStyleName("small"); + pos.addStyleName(ValoTheme.BUTTON_SMALL); grid.addComponent(pos); pos = new Button("", new ClickListener() { @@ -361,7 +362,7 @@ public class CommonParts extends VerticalLayout implements View { notification.show(Page.getCurrent()); } }); - pos.addStyleName("small"); + pos.addStyleName(ValoTheme.BUTTON_SMALL); grid.addComponent(pos); pos = new Button("", new ClickListener() { @@ -371,7 +372,7 @@ public class CommonParts extends VerticalLayout implements View { notification.show(Page.getCurrent()); } }); - pos.addStyleName("small"); + pos.addStyleName(ValoTheme.BUTTON_SMALL); grid.addComponent(pos); pos = new Button("", new ClickListener() { @@ -381,7 +382,7 @@ public class CommonParts extends VerticalLayout implements View { notification.show(Page.getCurrent()); } }); - pos.addStyleName("small"); + pos.addStyleName(ValoTheme.BUTTON_SMALL); grid.addComponent(pos); } @@ -397,35 +398,35 @@ public class CommonParts extends VerticalLayout implements View { { setSpacing(true); setMargin(true); - addStyleName("wrapping"); + addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); addComponent(new Label( "Try out different tooltips/descriptions by hovering over the labels.")); Label label = new Label("Simple"); - label.addStyleName("bold"); + label.addStyleName(ValoTheme.LABEL_BOLD); label.setDescription("Simple tooltip message"); addComponent(label); label = new Label("Long"); - label.addStyleName("bold"); + label.addStyleName(ValoTheme.LABEL_BOLD); label.setDescription("Long tooltip message. Inmensae subtilitatis, obscuris et malesuada fames. Salutantibus vitae elit libero, a pharetra augue."); addComponent(label); label = new Label("HTML tooltip"); - label.addStyleName("bold"); + label.addStyleName(ValoTheme.LABEL_BOLD); label.setDescription("

Ut enim ad minim veniam, quis nostrud exercitation

Morbi fringilla convallis sapien, id pulvinar odio volutpat. Vivamus sagittis lacus vel augue laoreet rutrum faucibus. Donec sed odio operae, eu vulputate felis rhoncus. At nos hinc posthac, sitientis piros Afros. Tu quoque, Brute, fili mi, nihil timor populi, nihil!

Gallia est omnis divisa in partes tres, quarum. Praeterea iter est quasdam res quas ex communi. Cum ceteris in veneratione tui montes, nascetur mus. Quam temere in vitiis, legem sancimus haerentia. Idque Caesaris facere voluntate liceret: sese habere.

"); addComponent(label); label = new Label("With an error message"); - label.addStyleName("bold"); + label.addStyleName(ValoTheme.LABEL_BOLD); label.setDescription("Simple tooltip message"); label.setComponentError(new UserError( "Something terrible has happened")); addComponent(label); label = new Label("With a long error message"); - label.addStyleName("bold"); + label.addStyleName(ValoTheme.LABEL_BOLD); label.setDescription("Simple tooltip message"); label.setComponentError(new UserError( "

Contra legem facit qui id facit quod lex prohibet Tityre, tu patulae recubans sub tegmine fagi dolor. Tityre, tu patulae recubans sub tegmine fagi dolor. Prima luce, cum quibus mons aliud consensu ab eo. Quid securi etiam tamquam eu fugiat nulla pariatur. Fabio vel iudice vincam, sunt in culpa qui officia. Nihil hic munitissimus habendi senatus locus, nihil horum?

Plura mihi bona sunt, inclinet, amari petere vellent. Integer legentibus erat a ante historiarum dapibus. Quam diu etiam furor iste tuus nos eludet? Nec dubitamus multa iter quae et nos invenerat. Quisque ut dolor gravida, placerat libero vel, euismod. Quae vero auctorem tractata ab fiducia dicuntur.

", @@ -434,7 +435,7 @@ public class CommonParts extends VerticalLayout implements View { addComponent(label); label = new Label("Error message only"); - label.addStyleName("bold"); + label.addStyleName(ValoTheme.LABEL_BOLD); label.setComponentError(new UserError( "Something terrible has happened")); addComponent(label); @@ -479,7 +480,7 @@ public class CommonParts extends VerticalLayout implements View { Alignment.TOP_RIGHT); toolbar = toolbarLayout; } - toolbar.addStyleName("v-window-top-toolbar"); + toolbar.addStyleName(ValoTheme.WINDOW_TOP_TOOLBAR); root.addComponent(toolbar); } @@ -498,7 +499,7 @@ public class CommonParts extends VerticalLayout implements View { "Another"); tabs.addTab(new Label(" ", ContentMode.HTML), "One more"); - tabs.addStyleName("padded-tabbar"); + tabs.addStyleName(ValoTheme.TABSHEET_PADDED_TABBAR); tabs.addSelectedTabChangeListener(new SelectedTabChangeListener() { @Override public void selectedTabChange( @@ -514,9 +515,9 @@ public class CommonParts extends VerticalLayout implements View { } else if (!autoHeight) { Panel p = new Panel(); p.setSizeFull(); - p.addStyleName("borderless"); + p.addStyleName(ValoTheme.PANEL_BORDERLESS); if (!toolbarVisible || !toolbarLayout) { - p.addStyleName("scroll-divider"); + p.addStyleName(ValoTheme.PANEL_SCROLL_INDICATOR); } VerticalLayout l = new VerticalLayout(); l.addComponent(new Label( @@ -538,13 +539,13 @@ public class CommonParts extends VerticalLayout implements View { HorizontalLayout footer = new HorizontalLayout(); footer.setWidth("100%"); footer.setSpacing(true); - footer.addStyleName("v-window-bottom-toolbar"); + footer.addStyleName(ValoTheme.WINDOW_BOTTOM_TOOLBAR); Label footerText = new Label("Footer text"); footerText.setSizeUndefined(); Button ok = new Button("OK"); - ok.addStyleName("primary"); + ok.addStyleName(ValoTheme.BUTTON_PRIMARY); Button cancel = new Button("Cancel"); @@ -614,7 +615,7 @@ public class CommonParts extends VerticalLayout implements View { if (selectedItem.getText() .equals("Borderless Toolbars")) { - toolbarStyle = selectedItem.isChecked() ? "borderless" + toolbarStyle = selectedItem.isChecked() ? ValoTheme.MENUBAR_BORDERLESS : null; } @@ -630,7 +631,7 @@ public class CommonParts extends VerticalLayout implements View { MenuItem option = options.addItem("Footer", optionsCommand); option.setCheckable(true); option.setChecked(true); - options.addStyleName("small"); + options.addStyleName(ValoTheme.MENUBAR_SMALL); addComponent(options); options = new MenuBar(); @@ -643,7 +644,7 @@ public class CommonParts extends VerticalLayout implements View { .setCheckable(true); options.addItem("Borderless Toolbars", optionsCommand) .setCheckable(true); - options.addStyleName("small"); + options.addStyleName(ValoTheme.MENUBAR_SMALL); addComponent(options); Command optionsCommand2 = new Command() { @@ -671,7 +672,7 @@ public class CommonParts extends VerticalLayout implements View { options.addItem("Resizable", optionsCommand2) .setCheckable(true); options.addItem("Modal", optionsCommand2).setCheckable(true); - options.addStyleName("small"); + options.addStyleName(ValoTheme.MENUBAR_SMALL); addComponent(options); final Button show = new Button("Open Window", @@ -684,7 +685,7 @@ public class CommonParts extends VerticalLayout implements View { event.getButton().setEnabled(false); } }); - show.addStyleName("primary"); + show.addStyleName(ValoTheme.BUTTON_PRIMARY); addComponent(show); final CheckBox hidden = new CheckBox("Hidden"); diff --git a/uitest/src/com/vaadin/tests/themes/valo/DateFields.java b/uitest/src/com/vaadin/tests/themes/valo/DateFields.java index 4b29f83621..9c95b7400c 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/DateFields.java +++ b/uitest/src/com/vaadin/tests/themes/valo/DateFields.java @@ -35,17 +35,18 @@ import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.InlineDateField; import com.vaadin.ui.Label; import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; public class DateFields extends VerticalLayout implements View { public DateFields() { setMargin(true); Label h1 = new Label("Date Fields"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); HorizontalLayout row = new HorizontalLayout(); - row.addStyleName("wrapping"); + row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); row.setSpacing(true); addComponent(row); @@ -61,12 +62,12 @@ public class DateFields extends VerticalLayout implements View { date = new DateField("Error, borderless"); setDate(date); date.setComponentError(new UserError("Fix it, now!")); - date.addStyleName("borderless"); + date.addStyleName(ValoTheme.DATEFIELD_BORDERLESS); row.addComponent(date); CssLayout group = new CssLayout(); group.setCaption("Grouped with a Button"); - group.addStyleName("v-component-group"); + group.addStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP); row.addComponent(group); final DateField date2 = new DateField(); @@ -143,19 +144,19 @@ public class DateFields extends VerticalLayout implements View { date = new DateField("Small"); setDate(date); date.setResolution(Resolution.DAY); - date.addStyleName("small"); + date.addStyleName(ValoTheme.DATEFIELD_SMALL); row.addComponent(date); date = new DateField("Large"); setDate(date); date.setResolution(Resolution.DAY); - date.addStyleName("large"); + date.addStyleName(ValoTheme.DATEFIELD_LARGE); row.addComponent(date); date = new DateField("Borderless"); setDate(date); date.setResolution(Resolution.DAY); - date.addStyleName("borderless"); + date.addStyleName(ValoTheme.DATEFIELD_BORDERLESS); row.addComponent(date); date = new DateField("Week numbers"); @@ -179,13 +180,13 @@ public class DateFields extends VerticalLayout implements View { date = new DateField("Tiny"); setDate(date); date.setResolution(Resolution.DAY); - date.addStyleName("tiny"); + date.addStyleName(ValoTheme.DATEFIELD_TINY); row.addComponent(date); date = new DateField("Huge"); setDate(date); date.setResolution(Resolution.DAY); - date.addStyleName("huge"); + date.addStyleName(ValoTheme.DATEFIELD_HUGE); row.addComponent(date); date = new InlineDateField("Date picker"); diff --git a/uitest/src/com/vaadin/tests/themes/valo/Dragging.java b/uitest/src/com/vaadin/tests/themes/valo/Dragging.java index 27bdea7d8a..8de518be23 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/Dragging.java +++ b/uitest/src/com/vaadin/tests/themes/valo/Dragging.java @@ -46,6 +46,7 @@ import com.vaadin.ui.MenuBar; import com.vaadin.ui.MenuBar.MenuItem; import com.vaadin.ui.Notification; import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; /** * @@ -61,7 +62,7 @@ public class Dragging extends VerticalLayout implements View { setSpacing(true); Label h1 = new Label("Dragging Components"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); MenuBar options = new MenuBar(); @@ -74,9 +75,9 @@ public class Dragging extends VerticalLayout implements View { @Override public void menuSelected(MenuItem selectedItem) { if (selectedItem.isChecked()) { - sample.removeStyleName("no-vertical-drag-hints"); + sample.removeStyleName(ValoTheme.DRAG_AND_DROP_WRAPPER_NO_VERTICAL_DRAG_HINTS); } else { - sample.addStyleName("no-vertical-drag-hints"); + sample.addStyleName(ValoTheme.DRAG_AND_DROP_WRAPPER_NO_VERTICAL_DRAG_HINTS); } } }); @@ -87,9 +88,9 @@ public class Dragging extends VerticalLayout implements View { @Override public void menuSelected(MenuItem selectedItem) { if (selectedItem.isChecked()) { - sample.removeStyleName("no-horizontal-drag-hints"); + sample.removeStyleName(ValoTheme.DRAG_AND_DROP_WRAPPER_NO_HORIZONTAL_DRAG_HINTS); } else { - sample.addStyleName("no-horizontal-drag-hints"); + sample.addStyleName(ValoTheme.DRAG_AND_DROP_WRAPPER_NO_HORIZONTAL_DRAG_HINTS); } } }); @@ -100,9 +101,9 @@ public class Dragging extends VerticalLayout implements View { @Override public void menuSelected(MenuItem selectedItem) { if (selectedItem.isChecked()) { - sample.removeStyleName("no-box-drag-hints"); + sample.removeStyleName(ValoTheme.DRAG_AND_DROP_WRAPPER_NO_BOX_DRAG_HINTS); } else { - sample.addStyleName("no-box-drag-hints"); + sample.addStyleName(ValoTheme.DRAG_AND_DROP_WRAPPER_NO_BOX_DRAG_HINTS); } } }); diff --git a/uitest/src/com/vaadin/tests/themes/valo/Forms.java b/uitest/src/com/vaadin/tests/themes/valo/Forms.java index 90a6c51496..91fe473d60 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/Forms.java +++ b/uitest/src/com/vaadin/tests/themes/valo/Forms.java @@ -36,6 +36,7 @@ import com.vaadin.ui.RichTextArea; import com.vaadin.ui.TextArea; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; /** * @@ -48,18 +49,18 @@ public class Forms extends VerticalLayout implements View { setMargin(true); Label title = new Label("Forms"); - title.addStyleName("h1"); + title.addStyleName(ValoTheme.LABEL_H1); addComponent(title); final FormLayout form = new FormLayout(); form.setMargin(false); form.setWidth("800px"); - form.addStyleName("light"); + form.addStyleName(ValoTheme.FORMLAYOUT_LIGHT); addComponent(form); Label section = new Label("Personal Info"); - section.addStyleName("h2"); - section.addStyleName("colored"); + section.addStyleName(ValoTheme.LABEL_H2); + section.addStyleName(ValoTheme.LABEL_COLORED); form.addComponent(section); StringGenerator sg = new StringGenerator(); @@ -81,12 +82,12 @@ public class Forms extends VerticalLayout implements View { sex.addItem("Female"); sex.addItem("Male"); sex.select("Male"); - sex.addStyleName("horizontal"); + sex.addStyleName(ValoTheme.OPTIONGROUP_HORIZONTAL); form.addComponent(sex); section = new Label("Contact Info"); - section.addStyleName("h3"); - section.addStyleName("colored"); + section.addStyleName(ValoTheme.LABEL_H3); + section.addStyleName(ValoTheme.LABEL_COLORED); form.addComponent(section); TextField email = new TextField("Email"); @@ -120,14 +121,14 @@ public class Forms extends VerticalLayout implements View { period.addItem("Montly"); period.setNullSelectionAllowed(false); period.select("Weekly"); - period.addStyleName("small"); + period.addStyleName(ValoTheme.COMBOBOX_SMALL); period.setWidth("10em"); wrap.addComponent(period); form.addComponent(wrap); section = new Label("Additional Info"); - section.addStyleName("h4"); - section.addStyleName("colored"); + section.addStyleName(ValoTheme.LABEL_H4); + section.addStyleName(ValoTheme.LABEL_COLORED); form.addComponent(section); TextField website = new TextField("Website"); @@ -156,15 +157,15 @@ public class Forms extends VerticalLayout implements View { if (readOnly) { bio.setReadOnly(false); form.setReadOnly(false); - form.removeStyleName("light"); + form.removeStyleName(ValoTheme.FORMLAYOUT_LIGHT); event.getButton().setCaption("Save"); - event.getButton().addStyleName("primary"); + event.getButton().addStyleName(ValoTheme.BUTTON_PRIMARY); } else { bio.setReadOnly(true); form.setReadOnly(true); - form.addStyleName("light"); + form.addStyleName(ValoTheme.FORMLAYOUT_LIGHT); event.getButton().setCaption("Edit"); - event.getButton().removeStyleName("primary"); + event.getButton().removeStyleName(ValoTheme.BUTTON_PRIMARY); } } }); @@ -177,7 +178,7 @@ public class Forms extends VerticalLayout implements View { footer.addComponent(edit); Label lastModified = new Label("Last modified by you a minute ago"); - lastModified.addStyleName("light"); + lastModified.addStyleName(ValoTheme.LABEL_LIGHT); footer.addComponent(lastModified); } diff --git a/uitest/src/com/vaadin/tests/themes/valo/Labels.java b/uitest/src/com/vaadin/tests/themes/valo/Labels.java index b5bab3a1d3..9954979d50 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/Labels.java +++ b/uitest/src/com/vaadin/tests/themes/valo/Labels.java @@ -23,6 +23,7 @@ import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.Panel; import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; /** * @@ -34,7 +35,7 @@ public class Labels extends VerticalLayout implements View { setMargin(true); Label h1 = new Label("Labels"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); HorizontalLayout split = new HorizontalLayout(); @@ -46,16 +47,16 @@ public class Labels extends VerticalLayout implements View { split.addComponent(left); Label huge = new Label("Huge type for display text."); - huge.addStyleName("huge"); + huge.addStyleName(ValoTheme.LABEL_HUGE); left.addComponent(huge); Label large = new Label( "Large type for introductory text. Etiam at risus et justo dignissim congue. Donec congue lacinia dui, a porttitor lectus condimentum laoreet. Nunc eu."); - large.addStyleName("large"); + large.addStyleName(ValoTheme.LABEL_LARGE); left.addComponent(large); Label h2 = new Label("Subtitle"); - h2.addStyleName("h2"); + h2.addStyleName(ValoTheme.LABEL_H2); left.addComponent(h2); Label normal = new Label( @@ -64,20 +65,20 @@ public class Labels extends VerticalLayout implements View { left.addComponent(normal); Label h3 = new Label("Small Title"); - h3.addStyleName("h3"); + h3.addStyleName(ValoTheme.LABEL_H3); left.addComponent(h3); Label small = new Label( "Small type for additional text. Etiam at risus et justo dignissim congue. Donec congue lacinia dui, a porttitor lectus condimentum laoreet. Nunc eu."); - small.addStyleName("small"); + small.addStyleName(ValoTheme.LABEL_SMALL); left.addComponent(small); Label tiny = new Label("Tiny type for minor text."); - tiny.addStyleName("tiny"); + tiny.addStyleName(ValoTheme.LABEL_TINY); left.addComponent(tiny); Label h4 = new Label("Section Title"); - h4.addStyleName("h4"); + h4.addStyleName(ValoTheme.LABEL_H4); left.addComponent(h4); normal = new Label( @@ -94,25 +95,25 @@ public class Labels extends VerticalLayout implements View { Label label = new Label( "Bold type for prominent text. Etiam at risus et justo dignissim congue. Donec congue lacinia dui, a porttitor lectus condimentum laoreet. Nunc eu."); - label.addStyleName("bold"); + label.addStyleName(ValoTheme.LABEL_BOLD); right.addComponent(label); label = new Label( "Light type for subtle text. Etiam at risus et justo dignissim congue. Donec congue lacinia dui, a porttitor lectus condimentum laoreet. Nunc eu."); - label.addStyleName("light"); + label.addStyleName(ValoTheme.LABEL_LIGHT); right.addComponent(label); label = new Label( "Colored type for highlighted text. Etiam at risus et justo dignissim congue. Donec congue lacinia dui, a porttitor lectus condimentum laoreet. Nunc eu."); - label.addStyleName("colored"); + label.addStyleName(ValoTheme.LABEL_COLORED); right.addComponent(label); label = new Label("A label for success"); - label.addStyleName("success"); + label.addStyleName(ValoTheme.LABEL_SUCCESS); right.addComponent(label); label = new Label("A label for failure"); - label.addStyleName("failure"); + label.addStyleName(ValoTheme.LABEL_FAILURE); right.addComponent(label); } diff --git a/uitest/src/com/vaadin/tests/themes/valo/MenuBars.java b/uitest/src/com/vaadin/tests/themes/valo/MenuBars.java index 4a0130931e..fc74166b29 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/MenuBars.java +++ b/uitest/src/com/vaadin/tests/themes/valo/MenuBars.java @@ -25,6 +25,7 @@ import com.vaadin.ui.MenuBar.Command; import com.vaadin.ui.MenuBar.MenuItem; import com.vaadin.ui.Notification; import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; public class MenuBars extends VerticalLayout implements View { public MenuBars() { @@ -32,7 +33,7 @@ public class MenuBars extends VerticalLayout implements View { setSpacing(true); Label h1 = new Label("Menu Bars"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); MenuBar menuBar = getMenuBar(); @@ -41,37 +42,37 @@ public class MenuBars extends VerticalLayout implements View { menuBar = getMenuBar(); menuBar.setCaption("Small style"); - menuBar.addStyleName("small"); + menuBar.addStyleName(ValoTheme.MENUBAR_SMALL); addComponent(menuBar); menuBar = getMenuBar(); menuBar.setCaption("Borderless style"); - menuBar.addStyleName("borderless"); + menuBar.addStyleName(ValoTheme.MENUBAR_BORDERLESS); addComponent(menuBar); menuBar = getMenuBar(); menuBar.setCaption("Small borderless style"); - menuBar.addStyleName("borderless"); - menuBar.addStyleName("small"); + menuBar.addStyleName(ValoTheme.MENUBAR_BORDERLESS); + menuBar.addStyleName(ValoTheme.MENUBAR_SMALL); addComponent(menuBar); Label h2 = new Label("Drop Down Button"); - h2.addStyleName("h2"); + h2.addStyleName(ValoTheme.LABEL_H2); addComponent(h2); HorizontalLayout wrap = new HorizontalLayout(); - wrap.addStyleName("wrapping"); + wrap.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); wrap.setSpacing(true); addComponent(wrap); wrap.addComponent(getMenuButton("Normal", false)); MenuBar split = getMenuButton("Small", false); - split.addStyleName("small"); + split.addStyleName(ValoTheme.MENUBAR_SMALL); wrap.addComponent(split); split = getMenuButton("Borderless", false); - split.addStyleName("borderless"); + split.addStyleName(ValoTheme.MENUBAR_BORDERLESS); wrap.addComponent(split); split = getMenuButton("Themed", false); @@ -80,26 +81,26 @@ public class MenuBars extends VerticalLayout implements View { split = getMenuButton("Small", false); split.addStyleName("color1"); - split.addStyleName("small"); + split.addStyleName(ValoTheme.MENUBAR_SMALL); wrap.addComponent(split); h2 = new Label("Split Button"); - h2.addStyleName("h2"); + h2.addStyleName(ValoTheme.LABEL_H2); addComponent(h2); wrap = new HorizontalLayout(); - wrap.addStyleName("wrapping"); + wrap.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); wrap.setSpacing(true); addComponent(wrap); wrap.addComponent(getMenuButton("Normal", true)); split = getMenuButton("Small", true); - split.addStyleName("small"); + split.addStyleName(ValoTheme.MENUBAR_SMALL); wrap.addComponent(split); split = getMenuButton("Borderless", true); - split.addStyleName("borderless"); + split.addStyleName(ValoTheme.MENUBAR_BORDERLESS); wrap.addComponent(split); split = getMenuButton("Themed", true); @@ -108,7 +109,7 @@ public class MenuBars extends VerticalLayout implements View { split = getMenuButton("Small", true); split.addStyleName("color1"); - split.addStyleName("small"); + split.addStyleName(ValoTheme.MENUBAR_SMALL); wrap.addComponent(split); } diff --git a/uitest/src/com/vaadin/tests/themes/valo/NativeSelects.java b/uitest/src/com/vaadin/tests/themes/valo/NativeSelects.java index 284f7c8d6e..e9c1c78049 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/NativeSelects.java +++ b/uitest/src/com/vaadin/tests/themes/valo/NativeSelects.java @@ -23,17 +23,18 @@ import com.vaadin.ui.ListSelect; import com.vaadin.ui.NativeSelect; import com.vaadin.ui.TwinColSelect; import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; public class NativeSelects extends VerticalLayout implements View { public NativeSelects() { setMargin(true); Label h1 = new Label("Selects"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); HorizontalLayout row = new HorizontalLayout(); - row.addStyleName("wrapping"); + row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); row.setSpacing(true); addComponent(row); diff --git a/uitest/src/com/vaadin/tests/themes/valo/NotificationStyleTest.java b/uitest/src/com/vaadin/tests/themes/valo/NotificationStyleTest.java index 7adae9ce65..5f9542b6f3 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/NotificationStyleTest.java +++ b/uitest/src/com/vaadin/tests/themes/valo/NotificationStyleTest.java @@ -27,6 +27,7 @@ import org.openqa.selenium.support.ui.ExpectedCondition; import com.vaadin.testbench.elements.ButtonElement; import com.vaadin.tests.tb3.MultiBrowserTest; +import com.vaadin.ui.themes.ValoTheme; /** * Test for H1 and P elements styles in Notifications. @@ -45,7 +46,8 @@ public class NotificationStyleTest extends MultiBrowserTest { waitUntil(notificationPresentCondition(), 2); WebElement notification = findElement(By.className("v-Notification")); - List headers = notification.findElements(By.tagName("h1")); + List headers = notification.findElements(By + .tagName(ValoTheme.LABEL_H1)); String textAlign = headers.get(0).getCssValue("text-align"); String textAlignInnerHeader = headers.get(1).getCssValue("text-align"); Assert.assertNotEquals("Styles for notification defined h1 tag " diff --git a/uitest/src/com/vaadin/tests/themes/valo/Panels.java b/uitest/src/com/vaadin/tests/themes/valo/Panels.java index 8a17244693..d98daf7b05 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/Panels.java +++ b/uitest/src/com/vaadin/tests/themes/valo/Panels.java @@ -27,17 +27,18 @@ import com.vaadin.ui.MenuBar; import com.vaadin.ui.MenuBar.MenuItem; import com.vaadin.ui.Panel; import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; public class Panels extends VerticalLayout implements View { public Panels() { setMargin(true); Label h1 = new Label("Panels & Layout panels"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); HorizontalLayout row = new HorizontalLayout(); - row.addStyleName("wrapping"); + row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); row.setSpacing(true); addComponent(row); TestIcon testIcon = new TestIcon(60); @@ -74,33 +75,33 @@ public class Panels extends VerticalLayout implements View { panel = new Panel("Borderless style"); panel.setIcon(testIcon.get()); - panel.addStyleName("borderless"); + panel.addStyleName(ValoTheme.PANEL_BORDERLESS); panel.setContent(panelContent()); row.addComponent(panel); panel = new Panel("Borderless + scroll divider"); panel.setIcon(testIcon.get()); - panel.addStyleName("borderless"); - panel.addStyleName("scroll-divider"); + panel.addStyleName(ValoTheme.PANEL_BORDERLESS); + panel.addStyleName(ValoTheme.PANEL_SCROLL_INDICATOR); panel.setContent(panelContentScroll()); panel.setHeight("17em"); row.addComponent(panel); panel = new Panel("Well style"); panel.setIcon(testIcon.get()); - panel.addStyleName("well"); + panel.addStyleName(ValoTheme.PANEL_WELL); panel.setContent(panelContent()); row.addComponent(panel); CssLayout layout = new CssLayout(); layout.setIcon(testIcon.get()); layout.setCaption("Panel style layout"); - layout.addStyleName("card"); + layout.addStyleName(ValoTheme.LAYOUT_CARD); layout.addComponent(panelContent()); row.addComponent(layout); layout = new CssLayout(); - layout.addStyleName("card"); + layout.addStyleName(ValoTheme.LAYOUT_CARD); row.addComponent(layout); HorizontalLayout panelCaption = new HorizontalLayout(); panelCaption.addStyleName("v-panel-caption"); @@ -112,13 +113,13 @@ public class Panels extends VerticalLayout implements View { Button action = new Button(); action.setIcon(FontAwesome.PENCIL); - action.addStyleName("borderless-colored"); - action.addStyleName("small"); - action.addStyleName("icon-only"); + action.addStyleName(ValoTheme.BUTTON_BORDERLESS_COLORED); + action.addStyleName(ValoTheme.BUTTON_SMALL); + action.addStyleName(ValoTheme.BUTTON_ICON_ONLY); panelCaption.addComponent(action); MenuBar dropdown = new MenuBar(); - dropdown.addStyleName("borderless"); - dropdown.addStyleName("small"); + dropdown.addStyleName(ValoTheme.MENUBAR_BORDERLESS); + dropdown.addStyleName(ValoTheme.MENUBAR_SMALL); MenuItem addItem = dropdown.addItem("", FontAwesome.CHEVRON_DOWN, null); addItem.setStyleName("icon-only"); addItem.addItem("Settings", null); @@ -134,7 +135,7 @@ public class Panels extends VerticalLayout implements View { layout = new CssLayout(); layout.setIcon(testIcon.get()); layout.setCaption("Well style layout"); - layout.addStyleName("well"); + layout.addStyleName(ValoTheme.LAYOUT_WELL); layout.addComponent(panelContent()); row.addComponent(layout); } diff --git a/uitest/src/com/vaadin/tests/themes/valo/PopupViews.java b/uitest/src/com/vaadin/tests/themes/valo/PopupViews.java index c15270400c..58988c06d6 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/PopupViews.java +++ b/uitest/src/com/vaadin/tests/themes/valo/PopupViews.java @@ -24,17 +24,18 @@ import com.vaadin.ui.Label; import com.vaadin.ui.PopupView; import com.vaadin.ui.PopupView.Content; import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; public class PopupViews extends VerticalLayout implements View { public PopupViews() { setMargin(true); Label h1 = new Label("Popup Views"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); HorizontalLayout row = new HorizontalLayout(); - row.addStyleName("wrapping"); + row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); row.setSpacing(true); addComponent(row); diff --git a/uitest/src/com/vaadin/tests/themes/valo/Sliders.java b/uitest/src/com/vaadin/tests/themes/valo/Sliders.java index 8ed846e39f..9642cb5ccf 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/Sliders.java +++ b/uitest/src/com/vaadin/tests/themes/valo/Sliders.java @@ -23,17 +23,18 @@ import com.vaadin.ui.Label; import com.vaadin.ui.ProgressBar; import com.vaadin.ui.Slider; import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; public class Sliders extends VerticalLayout implements View { public Sliders() { setMargin(true); Label h1 = new Label("Sliders"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); HorizontalLayout row = new HorizontalLayout(); - row.addStyleName("wrapping"); + row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); row.setSpacing(true); addComponent(row); @@ -67,7 +68,7 @@ public class Sliders extends VerticalLayout implements View { slider = new Slider("No indicator"); slider.setValue(50.0); slider.setWidth("200px"); - slider.addStyleName("no-indicator"); + slider.addStyleName(ValoTheme.SLIDER_NO_INDICATOR); row.addComponent(slider); slider = new Slider("With ticks (not in IE8 & IE9)"); @@ -119,7 +120,7 @@ public class Sliders extends VerticalLayout implements View { slider = new Slider("No indicator"); slider.setValue(50.0); slider.setHeight("200px"); - slider.addStyleName("no-indicator"); + slider.addStyleName(ValoTheme.SLIDER_NO_INDICATOR); slider.setOrientation(SliderOrientation.VERTICAL); row.addComponent(slider); @@ -137,11 +138,11 @@ public class Sliders extends VerticalLayout implements View { row.addComponent(slider); h1 = new Label("Progress Bars"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); row = new HorizontalLayout(); - row.addStyleName("wrapping"); + row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); row.setSpacing(true); addComponent(row); @@ -154,7 +155,7 @@ public class Sliders extends VerticalLayout implements View { pb2 = new ProgressBar(); pb2.setCaption("Point style"); pb2.setWidth("300px"); - pb2.addStyleName("point"); + pb2.addStyleName(ValoTheme.PROGRESSBAR_POINT); // pb2.setValue(0.6f); row.addComponent(pb2); diff --git a/uitest/src/com/vaadin/tests/themes/valo/SplitPanels.java b/uitest/src/com/vaadin/tests/themes/valo/SplitPanels.java index 9a6d86ae04..4983bc5813 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/SplitPanels.java +++ b/uitest/src/com/vaadin/tests/themes/valo/SplitPanels.java @@ -23,20 +23,21 @@ import com.vaadin.ui.HorizontalSplitPanel; import com.vaadin.ui.Label; import com.vaadin.ui.VerticalLayout; import com.vaadin.ui.VerticalSplitPanel; +import com.vaadin.ui.themes.ValoTheme; public class SplitPanels extends VerticalLayout implements View { public SplitPanels() { setMargin(true); Label h1 = new Label("Split Panels"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); addComponent(new Label( "Outlines are just to show the areas of the SplitPanels. They are not part of the actual component style.")); HorizontalLayout row = new HorizontalLayout(); - row.addStyleName("wrapping"); + row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); row.setSpacing(true); row.setMargin(new MarginInfo(true, false, false, false)); addComponent(row); @@ -61,7 +62,7 @@ public class SplitPanels extends VerticalLayout implements View { sp.setCaption("Large style"); sp.setWidth("300px"); sp.setHeight("200px"); - sp.addStyleName("large"); + sp.addStyleName(ValoTheme.SPLITPANEL_LARGE); sp.setFirstComponent(getContent()); sp.setSecondComponent(getContent()); row.addComponent(sp); @@ -70,7 +71,7 @@ public class SplitPanels extends VerticalLayout implements View { sp2.setCaption("Large style"); sp2.setWidth("300px"); sp2.setHeight("200px"); - sp2.addStyleName("large"); + sp2.addStyleName(ValoTheme.SPLITPANEL_LARGE); sp2.setFirstComponent(getContent()); sp2.setSecondComponent(getContent()); row.addComponent(sp2); diff --git a/uitest/src/com/vaadin/tests/themes/valo/Tables.java b/uitest/src/com/vaadin/tests/themes/valo/Tables.java index fb6638ee7d..071e6b746a 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/Tables.java +++ b/uitest/src/com/vaadin/tests/themes/valo/Tables.java @@ -42,6 +42,7 @@ import com.vaadin.ui.Table.TableDragMode; import com.vaadin.ui.TextField; import com.vaadin.ui.TreeTable; import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; public class Tables extends VerticalLayout implements View { @@ -72,11 +73,11 @@ public class Tables extends VerticalLayout implements View { setSpacing(true); Label h1 = new Label("Tables"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); HorizontalLayout wrap = new HorizontalLayout(); - wrap.addStyleName("wrapping"); + wrap.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); wrap.setSpacing(true); addComponent(wrap); @@ -189,9 +190,9 @@ public class Tables extends VerticalLayout implements View { Object columnId) { TextField tf = new TextField(); tf.setInputPrompt("Type here…"); - // tf.addStyleName("compact"); + // tf.addStyleName(ValoTheme.TABLE_COMPACT); if ((Integer) itemId % 2 == 0) { - tf.addStyleName("borderless"); + tf.addStyleName(ValoTheme.TABLE_BORDERLESS); } return tf; } @@ -203,9 +204,9 @@ public class Tables extends VerticalLayout implements View { public Object generateCell(Table source, Object itemId, Object columnId) { DateField tf = new DateField(); - tf.addStyleName("compact"); + tf.addStyleName(ValoTheme.TABLE_COMPACT); if ((Integer) itemId % 2 == 0) { - tf.addStyleName("borderless"); + tf.addStyleName(ValoTheme.DATEFIELD_BORDERLESS); } return tf; } @@ -218,9 +219,9 @@ public class Tables extends VerticalLayout implements View { Object columnId) { ComboBox tf = new ComboBox(); tf.setInputPrompt("Select"); - tf.addStyleName("compact"); + tf.addStyleName(ValoTheme.TABLE_COMPACT); if ((Integer) itemId % 2 == 0) { - tf.addStyleName("borderless"); + tf.addStyleName(ValoTheme.DATEFIELD_BORDERLESS); } return tf; } @@ -232,7 +233,7 @@ public class Tables extends VerticalLayout implements View { public Object generateCell(Table source, Object itemId, Object columnId) { Button b = new Button("Button"); - b.addStyleName("small"); + b.addStyleName(ValoTheme.BUTTON_SMALL); return b; } }); @@ -244,7 +245,7 @@ public class Tables extends VerticalLayout implements View { Object columnId) { Label label = new Label("Label component"); label.setSizeUndefined(); - label.addStyleName("bold"); + label.addStyleName(ValoTheme.LABEL_BOLD); return label; } }); @@ -267,7 +268,7 @@ public class Tables extends VerticalLayout implements View { OptionGroup op = new OptionGroup(); op.addItem("Male"); op.addItem("Female"); - op.addStyleName("horizontal"); + op.addStyleName(ValoTheme.OPTIONGROUP_HORIZONTAL); return op; } }); @@ -321,45 +322,45 @@ public class Tables extends VerticalLayout implements View { expandRatios ? 1.0f : 0); if (!stripes) { - table.addStyleName("no-stripes"); + table.addStyleName(ValoTheme.TABLE_NO_STRIPES); } else { - table.removeStyleName("no-stripes"); + table.removeStyleName(ValoTheme.TABLE_NO_STRIPES); } if (!verticalLines) { - table.addStyleName("no-vertical-lines"); + table.addStyleName(ValoTheme.TABLE_NO_VERTICAL_LINES); } else { - table.removeStyleName("no-vertical-lines"); + table.removeStyleName(ValoTheme.TABLE_NO_VERTICAL_LINES); } if (!horizontalLines) { - table.addStyleName("no-horizontal-lines"); + table.addStyleName(ValoTheme.TABLE_NO_HORIZONTAL_LINES); } else { - table.removeStyleName("no-horizontal-lines"); + table.removeStyleName(ValoTheme.TABLE_NO_HORIZONTAL_LINES); } if (borderless) { - table.addStyleName("borderless"); + table.addStyleName(ValoTheme.TABLE_BORDERLESS); } else { - table.removeStyleName("borderless"); + table.removeStyleName(ValoTheme.TABLE_BORDERLESS); } if (!headers) { - table.addStyleName("no-header"); + table.addStyleName(ValoTheme.TABLE_NO_HEADER); } else { - table.removeStyleName("no-header"); + table.removeStyleName(ValoTheme.TABLE_NO_HEADER); } if (compact) { - table.addStyleName("compact"); + table.addStyleName(ValoTheme.TABLE_COMPACT); } else { - table.removeStyleName("compact"); + table.removeStyleName(ValoTheme.TABLE_COMPACT); } if (small) { - table.addStyleName("small"); + table.addStyleName(ValoTheme.TABLE_SMALL); } else { - table.removeStyleName("small"); + table.removeStyleName(ValoTheme.TABLE_SMALL); } if (!rowIndex && !rowCaption && rowIcon) { diff --git a/uitest/src/com/vaadin/tests/themes/valo/Tabsheets.java b/uitest/src/com/vaadin/tests/themes/valo/Tabsheets.java index 5e77292471..421da5ffe7 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/Tabsheets.java +++ b/uitest/src/com/vaadin/tests/themes/valo/Tabsheets.java @@ -28,6 +28,7 @@ import com.vaadin.ui.TabSheet.SelectedTabChangeEvent; import com.vaadin.ui.TabSheet.SelectedTabChangeListener; import com.vaadin.ui.TabSheet.Tab; import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; public class Tabsheets extends VerticalLayout implements View { @@ -37,12 +38,12 @@ public class Tabsheets extends VerticalLayout implements View { setMargin(true); Label h1 = new Label("Tabs"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); HorizontalLayout wrap = new HorizontalLayout(); wrap.setSpacing(true); - wrap.addStyleName("wrapping"); + wrap.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); addComponent(wrap); final CheckBox closable = new CheckBox("Closable"); @@ -66,12 +67,12 @@ public class Tabsheets extends VerticalLayout implements View { wrap.addComponent(disable); Label h3 = new Label("Additional Styles"); - h3.addStyleName("h3"); + h3.addStyleName(ValoTheme.LABEL_H3); addComponent(h3); wrap = new HorizontalLayout(); wrap.setSpacing(true); - wrap.addStyleName("wrapping"); + wrap.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); wrap.setMargin(new MarginInfo(false, false, true, false)); addComponent(wrap); diff --git a/uitest/src/com/vaadin/tests/themes/valo/TextFields.java b/uitest/src/com/vaadin/tests/themes/valo/TextFields.java index 347a683673..be6e430b23 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/TextFields.java +++ b/uitest/src/com/vaadin/tests/themes/valo/TextFields.java @@ -28,6 +28,7 @@ import com.vaadin.ui.RichTextArea; import com.vaadin.ui.TextArea; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; public class TextFields extends VerticalLayout implements View { private TestIcon testIcon = new TestIcon(140); @@ -36,11 +37,11 @@ public class TextFields extends VerticalLayout implements View { setMargin(true); Label h1 = new Label("Text Fields"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); HorizontalLayout row = new HorizontalLayout(); - row.addStyleName("wrapping"); + row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); row.setSpacing(true); addComponent(row); @@ -72,7 +73,7 @@ public class TextFields extends VerticalLayout implements View { tf = new TextField("Error, borderless"); tf.setValue("Something’s wrong"); tf.setComponentError(new UserError("Fix it, now!")); - tf.addStyleName("borderless"); + tf.addStyleName(ValoTheme.TEXTFIELD_BORDERLESS); row.addComponent(tf); tf = new TextField("Read-only"); @@ -83,121 +84,121 @@ public class TextFields extends VerticalLayout implements View { tf = new TextField("Small"); tf.setValue("Field value"); - tf.addStyleName("small"); + tf.addStyleName(ValoTheme.TEXTFIELD_SMALL); row.addComponent(tf); tf = new TextField("Large"); tf.setValue("Field value"); - tf.addStyleName("large"); + tf.addStyleName(ValoTheme.TEXTFIELD_LARGE); tf.setIcon(testIcon.get(true)); row.addComponent(tf); tf = new TextField("Icon inside"); tf.setInputPrompt("Ooh, an icon"); - tf.addStyleName("inline-icon"); + tf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON); tf.setIcon(testIcon.get()); row.addComponent(tf); tf = new TextField("Large, Icon inside"); tf.setInputPrompt("Ooh, an icon"); - tf.addStyleName("large"); - tf.addStyleName("inline-icon"); + tf.addStyleName(ValoTheme.TEXTFIELD_LARGE); + tf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON); tf.setIcon(testIcon.get()); row.addComponent(tf); tf = new TextField("Small, Icon inside"); tf.setInputPrompt("Ooh, an icon"); - tf.addStyleName("small"); - tf.addStyleName("inline-icon"); + tf.addStyleName(ValoTheme.TEXTFIELD_SMALL); + tf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON); tf.setIcon(testIcon.get()); row.addComponent(tf); tf = new TextField("16px supported by default"); tf.setInputPrompt("Image icon"); - tf.addStyleName("inline-icon"); + tf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON); tf.setIcon(testIcon.get(true, 16)); row.addComponent(tf); tf = new TextField(); tf.setValue("Font, no caption"); - tf.addStyleName("inline-icon"); + tf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON); tf.setIcon(testIcon.get()); row.addComponent(tf); tf = new TextField(); tf.setValue("Image, no caption"); - tf.addStyleName("inline-icon"); + tf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON); tf.setIcon(testIcon.get(true, 16)); row.addComponent(tf); CssLayout group = new CssLayout(); - group.addStyleName("v-component-group"); + group.addStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP); row.addComponent(group); tf = new TextField(); tf.setInputPrompt("Grouped with a button"); - tf.addStyleName("inline-icon"); + tf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON); tf.setIcon(testIcon.get()); tf.setWidth("260px"); group.addComponent(tf); Button button = new Button("Do It"); - // button.addStyleName("primary"); + // button.addStyleName(ValoTheme.BUTTON_PRIMARY); group.addComponent(button); tf = new TextField("Borderless"); tf.setInputPrompt("Write here…"); - tf.addStyleName("inline-icon"); - tf.addStyleName("borderless"); + tf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON); + tf.addStyleName(ValoTheme.TEXTFIELD_BORDERLESS); tf.setIcon(testIcon.get()); row.addComponent(tf); tf = new TextField("Right-aligned"); tf.setValue("1,234"); - tf.addStyleName("align-right"); + tf.addStyleName(ValoTheme.TEXTFIELD_ALIGN_RIGHT); row.addComponent(tf); tf = new TextField("Centered"); tf.setInputPrompt("Guess what?"); - tf.addStyleName("align-center"); + tf.addStyleName(ValoTheme.TEXTFIELD_ALIGN_CENTER); row.addComponent(tf); PasswordField pwf = new PasswordField("Password"); pwf.setInputPrompt("Secret words"); - pwf.addStyleName("inline-icon"); + pwf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON); pwf.setIcon(FontAwesome.LOCK); row.addComponent(pwf); pwf = new PasswordField("Password, right-aligned"); pwf.setInputPrompt("Secret words"); - pwf.addStyleName("inline-icon"); - pwf.addStyleName("align-right"); + pwf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON); + pwf.addStyleName(ValoTheme.TEXTFIELD_ALIGN_RIGHT); pwf.setIcon(FontAwesome.LOCK); row.addComponent(pwf); pwf = new PasswordField("Password, centered"); pwf.setInputPrompt("Secret words"); - pwf.addStyleName("inline-icon"); - pwf.addStyleName("align-center"); + pwf.addStyleName(ValoTheme.TEXTFIELD_INLINE_ICON); + pwf.addStyleName(ValoTheme.TEXTFIELD_ALIGN_CENTER); pwf.setIcon(FontAwesome.LOCK); row.addComponent(pwf); tf = new TextField("Tiny"); tf.setValue("Field value"); - tf.addStyleName("tiny"); + tf.addStyleName(ValoTheme.TEXTFIELD_TINY); row.addComponent(tf); tf = new TextField("Huge"); tf.setValue("Field value"); - tf.addStyleName("huge"); + tf.addStyleName(ValoTheme.TEXTFIELD_HUGE); row.addComponent(tf); h1 = new Label("Text Areas"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); row = new HorizontalLayout(); - row.addStyleName("wrapping"); + row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); row.setSpacing(true); addComponent(row); @@ -228,37 +229,37 @@ public class TextFields extends VerticalLayout implements View { row.addComponent(ta); ta = new TextArea("Small"); - ta.addStyleName("small"); + ta.addStyleName(ValoTheme.TEXTAREA_SMALL); ta.setInputPrompt("Write your comment…"); row.addComponent(ta); ta = new TextArea("Large"); - ta.addStyleName("large"); + ta.addStyleName(ValoTheme.TEXTAREA_LARGE); ta.setInputPrompt("Write your comment…"); row.addComponent(ta); ta = new TextArea("Borderless"); - ta.addStyleName("borderless"); + ta.addStyleName(ValoTheme.TEXTAREA_BORDERLESS); ta.setInputPrompt("Write your comment…"); row.addComponent(ta); ta = new TextArea("Right-aligned"); - ta.addStyleName("align-right"); + ta.addStyleName(ValoTheme.TEXTAREA_ALIGN_RIGHT); ta.setValue("Field value, spanning multiple lines of text"); row.addComponent(ta); ta = new TextArea("Centered"); - ta.addStyleName("align-center"); + ta.addStyleName(ValoTheme.TEXTAREA_ALIGN_CENTER); ta.setValue("Field value, spanning multiple lines of text"); row.addComponent(ta); ta = new TextArea("Tiny"); - ta.addStyleName("tiny"); + ta.addStyleName(ValoTheme.TEXTAREA_TINY); ta.setInputPrompt("Write your comment…"); row.addComponent(ta); ta = new TextArea("Huge"); - ta.addStyleName("huge"); + ta.addStyleName(ValoTheme.TEXTAREA_HUGE); ta.setInputPrompt("Write your comment…"); row.addComponent(ta); diff --git a/uitest/src/com/vaadin/tests/themes/valo/Trees.java b/uitest/src/com/vaadin/tests/themes/valo/Trees.java index cb5657660a..02846d8921 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/Trees.java +++ b/uitest/src/com/vaadin/tests/themes/valo/Trees.java @@ -28,17 +28,18 @@ import com.vaadin.ui.Notification; import com.vaadin.ui.Tree; import com.vaadin.ui.Tree.TreeDragMode; import com.vaadin.ui.VerticalLayout; +import com.vaadin.ui.themes.ValoTheme; public class Trees extends VerticalLayout implements View { public Trees() { setMargin(true); Label h1 = new Label("Trees"); - h1.addStyleName("h1"); + h1.addStyleName(ValoTheme.LABEL_H1); addComponent(h1); HorizontalLayout row = new HorizontalLayout(); - row.addStyleName("wrapping"); + row.addStyleName(ValoTheme.LAYOUT_HORIZONTAL_WRAPPING); row.setSpacing(true); addComponent(row); diff --git a/uitest/src/com/vaadin/tests/themes/valo/ValoMenuLayout.java b/uitest/src/com/vaadin/tests/themes/valo/ValoMenuLayout.java index 3a3baa686c..0e62f983a6 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/ValoMenuLayout.java +++ b/uitest/src/com/vaadin/tests/themes/valo/ValoMenuLayout.java @@ -19,6 +19,7 @@ import com.vaadin.ui.Component; import com.vaadin.ui.ComponentContainer; import com.vaadin.ui.CssLayout; import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.themes.ValoTheme; /** * @@ -34,7 +35,7 @@ public class ValoMenuLayout extends HorizontalLayout { public ValoMenuLayout() { setSizeFull(); - menuArea.setPrimaryStyleName("valo-menu"); + menuArea.setPrimaryStyleName(ValoTheme.MENU_ROOT); contentArea.setPrimaryStyleName("valo-content"); contentArea.addStyleName("v-scrollable"); @@ -49,7 +50,7 @@ public class ValoMenuLayout extends HorizontalLayout { } public void addMenu(Component menu) { - menu.addStyleName("valo-menu-part"); + menu.addStyleName(ValoTheme.MENU_PART); menuArea.addComponent(menu); } diff --git a/uitest/src/com/vaadin/tests/themes/valo/ValoThemeUI.java b/uitest/src/com/vaadin/tests/themes/valo/ValoThemeUI.java index 988b3487bd..3bf6fd7ca3 100644 --- a/uitest/src/com/vaadin/tests/themes/valo/ValoThemeUI.java +++ b/uitest/src/com/vaadin/tests/themes/valo/ValoThemeUI.java @@ -194,29 +194,29 @@ public class ValoThemeUI extends UI { Component buildTestMenu() { CssLayout menu = new CssLayout(); - menu.addStyleName("large-icons"); + menu.addStyleName(ValoTheme.MENU_PART_LARGE_ICONS); Label logo = new Label("Va"); logo.setSizeUndefined(); - logo.setPrimaryStyleName("valo-menu-logo"); + logo.setPrimaryStyleName(ValoTheme.MENU_LOGO); menu.addComponent(logo); Button b = new Button( "Reference 3"); b.setIcon(FontAwesome.TH_LIST); - b.setPrimaryStyleName("valo-menu-item"); + b.setPrimaryStyleName(ValoTheme.MENU_ITEM); b.addStyleName("selected"); b.setHtmlContentAllowed(true); menu.addComponent(b); b = new Button("API"); b.setIcon(FontAwesome.BOOK); - b.setPrimaryStyleName("valo-menu-item"); + b.setPrimaryStyleName(ValoTheme.MENU_ITEM); menu.addComponent(b); b = new Button("Examples 12"); b.setIcon(FontAwesome.TABLE); - b.setPrimaryStyleName("valo-menu-item"); + b.setPrimaryStyleName(ValoTheme.MENU_ITEM); b.setHtmlContentAllowed(true); menu.addComponent(b); @@ -250,7 +250,7 @@ public class ValoThemeUI extends UI { HorizontalLayout top = new HorizontalLayout(); top.setWidth("100%"); top.setDefaultComponentAlignment(Alignment.MIDDLE_LEFT); - top.addStyleName("valo-menu-title"); + top.addStyleName(ValoTheme.MENU_TITLE); menu.addComponent(top); menu.addComponent(createThemeSelect()); @@ -297,8 +297,8 @@ public class ValoThemeUI extends UI { for (final Entry item : menuItems.entrySet()) { if (item.getKey().equals("labels")) { label = new Label("Components", ContentMode.HTML); - label.setPrimaryStyleName("valo-menu-subtitle"); - label.addStyleName("h4"); + label.setPrimaryStyleName(ValoTheme.MENU_SUBTITLE); + label.addStyleName(ValoTheme.LABEL_H4); label.setSizeUndefined(); menuItemsLayout.addComponent(label); } @@ -308,8 +308,8 @@ public class ValoThemeUI extends UI { + ""); count = 0; label = new Label("Containers", ContentMode.HTML); - label.setPrimaryStyleName("valo-menu-subtitle"); - label.addStyleName("h4"); + label.setPrimaryStyleName(ValoTheme.MENU_SUBTITLE); + label.addStyleName(ValoTheme.LABEL_H4); label.setSizeUndefined(); menuItemsLayout.addComponent(label); } @@ -319,8 +319,8 @@ public class ValoThemeUI extends UI { + ""); count = 0; label = new Label("Other", ContentMode.HTML); - label.setPrimaryStyleName("valo-menu-subtitle"); - label.addStyleName("h4"); + label.setPrimaryStyleName(ValoTheme.MENU_SUBTITLE); + label.addStyleName(ValoTheme.LABEL_H4); label.setSizeUndefined(); menuItemsLayout.addComponent(label); } @@ -335,7 +335,7 @@ public class ValoThemeUI extends UI { + " 123"); } b.setHtmlContentAllowed(true); - b.setPrimaryStyleName("valo-menu-item"); + b.setPrimaryStyleName(ValoTheme.MENU_ITEM); b.setIcon(testIcon.get()); menuItemsLayout.addComponent(b); count++; -- cgit v1.2.3 From 6322134bddd505d9cdf44f8554bb6d337dabe88a Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Wed, 19 Aug 2015 23:55:16 +0300 Subject: Update to Bourbon 3.2.4 (#15484) Change-Id: I052702fc9b5b714c0d748973f3146f0718298a97 --- .../VAADIN/themes/valo/util/bourbon/_bourbon.scss | 16 +- .../themes/valo/util/bourbon/addons/_button.scss | 183 ++++++++++++++++----- .../util/bourbon/addons/_directional-values.scss | 13 +- .../util/bourbon/addons/_html5-input-types.scss | 6 +- .../themes/valo/util/bourbon/addons/_position.scss | 8 +- .../themes/valo/util/bourbon/addons/_rem.scss | 33 ---- .../valo/util/bourbon/addons/_retina-image.scss | 2 +- .../util/bourbon/addons/_timing-functions.scss | 2 +- .../themes/valo/util/bourbon/addons/_triangle.scss | 67 ++++++-- .../valo/util/bourbon/addons/_word-wrap.scss | 8 + .../themes/valo/util/bourbon/css3/_columns.scss | 2 +- .../themes/valo/util/bourbon/css3/_filter.scss | 5 + .../themes/valo/util/bourbon/css3/_flex-box.scss | 28 ++-- .../themes/valo/util/bourbon/css3/_font-face.scss | 2 +- .../util/bourbon/css3/_font-feature-settings.scss | 10 ++ .../valo/util/bourbon/css3/_image-rendering.scss | 1 + .../themes/valo/util/bourbon/css3/_keyframes.scss | 15 +- .../valo/util/bourbon/css3/_placeholder.scss | 27 +-- .../themes/valo/util/bourbon/css3/_transition.scss | 51 +++++- .../util/bourbon/functions/_color-lightness.scss | 13 ++ .../util/bourbon/functions/_modular-scale.scss | 2 +- .../valo/util/bourbon/functions/_px-to-rem.scss | 15 ++ .../functions/_transition-property-name.scss | 26 +-- .../functions/_transition-property-name.scss~ | 22 +++ .../util/bourbon/helpers/_render-gradients.scss | 4 +- .../util/bourbon/settings/_asset-pipeline.scss | 1 + .../valo/util/bourbon/settings/_prefixer.scss | 10 +- 27 files changed, 391 insertions(+), 181 deletions(-) delete mode 100644 WebContent/VAADIN/themes/valo/util/bourbon/addons/_rem.scss create mode 100644 WebContent/VAADIN/themes/valo/util/bourbon/addons/_word-wrap.scss create mode 100644 WebContent/VAADIN/themes/valo/util/bourbon/css3/_filter.scss create mode 100644 WebContent/VAADIN/themes/valo/util/bourbon/css3/_font-feature-settings.scss create mode 100644 WebContent/VAADIN/themes/valo/util/bourbon/functions/_color-lightness.scss create mode 100644 WebContent/VAADIN/themes/valo/util/bourbon/functions/_px-to-rem.scss create mode 100644 WebContent/VAADIN/themes/valo/util/bourbon/functions/_transition-property-name.scss~ create mode 100644 WebContent/VAADIN/themes/valo/util/bourbon/settings/_asset-pipeline.scss diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/_bourbon.scss b/WebContent/VAADIN/themes/valo/util/bourbon/_bourbon.scss index e97b2fe8d4..c94d48ae14 100644 --- a/WebContent/VAADIN/themes/valo/util/bourbon/_bourbon.scss +++ b/WebContent/VAADIN/themes/valo/util/bourbon/_bourbon.scss @@ -1,6 +1,12 @@ +// Bourbon 3.2.4 +// http://bourbon.io +// Copyright 2011-2015 thoughtbot, inc. +// MIT License + // Settings @import "settings/prefixer"; @import "settings/px-to-em"; +@import "settings/asset-pipeline"; // Custom Helpers @import "helpers/gradient-positions-parser"; @@ -11,12 +17,14 @@ @import "helpers/shape-size-stripper"; // Custom Functions +@import "functions/color-lightness"; @import "functions/flex-grid"; -@import "functions/grid-width"; @import "functions/golden-ratio"; +@import "functions/grid-width"; @import "functions/linear-gradient"; @import "functions/modular-scale"; @import "functions/px-to-em"; +@import "functions/px-to-rem"; @import "functions/radial-gradient"; @import "functions/strip-units"; @import "functions/tint-shade"; @@ -34,8 +42,10 @@ @import "css3/box-sizing"; @import "css3/calc"; @import "css3/columns"; +@import "css3/filter"; @import "css3/flex-box"; @import "css3/font-face"; +@import "css3/font-feature-settings"; @import "css3/hyphens"; @import "css3/hidpi-media-query"; @import "css3/image-rendering"; @@ -56,14 +66,14 @@ @import "addons/ellipsis"; @import "addons/font-family"; @import "addons/hide-text"; -//@import "addons/html5-input-types"; +@import "addons/html5-input-types"; @import "addons/position"; @import "addons/prefixer"; -@import "addons/rem"; @import "addons/retina-image"; @import "addons/size"; @import "addons/timing-functions"; @import "addons/triangle"; +@import "addons/word-wrap"; // Soon to be deprecated Mixins @import "bourbon-deprecated-upcoming"; diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_button.scss b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_button.scss index fcc39fdf35..14a89e480c 100644 --- a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_button.scss +++ b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_button.scss @@ -1,38 +1,51 @@ -@mixin button ($style: simple, $base-color: #4294f0) { +@mixin button ($style: simple, $base-color: #4294f0, $text-size: inherit, $padding: 7px 18px) { - @if type-of($style) == color { + @if type-of($style) == string and type-of($base-color) == color { + @include buttonstyle($style, $base-color, $text-size, $padding); + } + + @if type-of($style) == string and type-of($base-color) == number { + $padding: $text-size; + $text-size: $base-color; + $base-color: #4294f0; + + @if $padding == inherit { + $padding: 7px 18px; + } + + @include buttonstyle($style, $base-color, $text-size, $padding); + } + + @if type-of($style) == color and type-of($base-color) == color { $base-color: $style; $style: simple; + @include buttonstyle($style, $base-color, $text-size, $padding); } - // Grayscale button - @if $base-color == grayscale($base-color) { - @if $style == simple { - @include simple($base-color, $grayscale: true); - } + @if type-of($style) == color and type-of($base-color) == number { + $padding: $text-size; + $text-size: $base-color; + $base-color: $style; + $style: simple; - @else if $style == shiny { - @include shiny($base-color, $grayscale: true); + @if $padding == inherit { + $padding: 7px 18px; } - @else if $style == pill { - @include pill($base-color, $grayscale: true); - } + @include buttonstyle($style, $base-color, $text-size, $padding); } - // Colored button - @else { - @if $style == simple { - @include simple($base-color); - } + @if type-of($style) == number { + $padding: $base-color; + $text-size: $style; + $base-color: #4294f0; + $style: simple; - @else if $style == shiny { - @include shiny($base-color); + @if $padding == #4294f0 { + $padding: 7px 18px; } - @else if $style == pill { - @include pill($base-color); - } + @include buttonstyle($style, $base-color, $text-size, $padding); } &:disabled { @@ -42,16 +55,55 @@ } +// Selector Style Button +//************************************************************************// +@mixin buttonstyle($type, $b-color, $t-size, $pad) { + // Grayscale button + @if $type == simple and $b-color == grayscale($b-color) { + @include simple($b-color, true, $t-size, $pad); + } + + @if $type == shiny and $b-color == grayscale($b-color) { + @include shiny($b-color, true, $t-size, $pad); + } + + @if $type == pill and $b-color == grayscale($b-color) { + @include pill($b-color, true, $t-size, $pad); + } + + @if $type == flat and $b-color == grayscale($b-color) { + @include flat($b-color, true, $t-size, $pad); + } + + // Colored button + @if $type == simple { + @include simple($b-color, false, $t-size, $pad); + } + + @else if $type == shiny { + @include shiny($b-color, false, $t-size, $pad); + } + + @else if $type == pill { + @include pill($b-color, false, $t-size, $pad); + } + + @else if $type == flat { + @include flat($b-color, false, $t-size, $pad); + } +} + + // Simple Button //************************************************************************// -@mixin simple($base-color, $grayscale: false) { +@mixin simple($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) { $color: hsl(0, 0, 100%); $border: adjust-color($base-color, $saturation: 9%, $lightness: -14%); $inset-shadow: adjust-color($base-color, $saturation: -8%, $lightness: 15%); $stop-gradient: adjust-color($base-color, $saturation: 9%, $lightness: -11%); $text-shadow: adjust-color($base-color, $saturation: 15%, $lightness: -18%); - @if lightness($base-color) > 70% { + @if is-light($base-color) { $color: hsl(0, 0, 20%); $text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%); } @@ -68,10 +120,10 @@ box-shadow: inset 0 1px 0 0 $inset-shadow; color: $color; display: inline-block; - font-size: inherit; + font-size: $textsize; font-weight: bold; @include linear-gradient ($base-color, $stop-gradient); - padding: 7px 18px; + padding: $padding; text-decoration: none; text-shadow: 0 1px 0 $text-shadow; background-clip: padding-box; @@ -92,7 +144,8 @@ @include linear-gradient ($base-color-hover, $stop-gradient-hover); } - &:active:not(:disabled) { + &:active:not(:disabled), + &:focus:not(:disabled) { $border-active: adjust-color($base-color, $saturation: 9%, $lightness: -14%); $inset-shadow-active: adjust-color($base-color, $saturation: 7%, $lightness: -17%); @@ -102,14 +155,14 @@ } border: 1px solid $border-active; - box-shadow: inset 0 0 8px 4px $inset-shadow-active, inset 0 0 8px 4px $inset-shadow-active, 0 1px 1px 0 #eee; + box-shadow: inset 0 0 8px 4px $inset-shadow-active, inset 0 0 8px 4px $inset-shadow-active; } } // Shiny Button //************************************************************************// -@mixin shiny($base-color, $grayscale: false) { +@mixin shiny($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) { $color: hsl(0, 0, 100%); $border: adjust-color($base-color, $red: -117, $green: -111, $blue: -81); $border-bottom: adjust-color($base-color, $red: -126, $green: -127, $blue: -122); @@ -119,7 +172,7 @@ $text-shadow: adjust-color($base-color, $red: -140, $green: -141, $blue: -114); $third-stop: adjust-color($base-color, $red: -86, $green: -75, $blue: -48); - @if lightness($base-color) > 70% { + @if is-light($base-color) { $color: hsl(0, 0, 20%); $text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%); } @@ -140,10 +193,10 @@ box-shadow: inset 0 1px 0 0 $inset-shadow; color: $color; display: inline-block; - font-size: inherit; + font-size: $textsize; font-weight: bold; @include linear-gradient(top, $base-color 0%, $second-stop 50%, $third-stop 50%, $fourth-stop 100%); - padding: 8px 20px; + padding: $padding; text-align: center; text-decoration: none; text-shadow: 0 -1px 1px $text-shadow; @@ -168,21 +221,22 @@ $fourth-stop-hover 100%); } - &:active:not(:disabled) { + &:active:not(:disabled), + &:focus:not(:disabled) { $inset-shadow-active: adjust-color($base-color, $red: -111, $green: -116, $blue: -122); @if $grayscale == true { $inset-shadow-active: grayscale($inset-shadow-active); } - box-shadow: inset 0 0 20px 0 $inset-shadow-active, 0 1px 0 #fff; + box-shadow: inset 0 0 20px 0 $inset-shadow-active; } } // Pill Button //************************************************************************// -@mixin pill($base-color, $grayscale: false) { +@mixin pill($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) { $color: hsl(0, 0, 100%); $border-bottom: adjust-color($base-color, $hue: 8, $saturation: -11%, $lightness: -26%); $border-sides: adjust-color($base-color, $hue: 4, $saturation: -21%, $lightness: -21%); @@ -191,7 +245,7 @@ $stop-gradient: adjust-color($base-color, $hue: 8, $saturation: 14%, $lightness: -10%); $text-shadow: adjust-color($base-color, $hue: 5, $saturation: -19%, $lightness: -15%); - @if lightness($base-color) > 70% { + @if is-light($base-color) { $color: hsl(0, 0, 20%); $text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%); } @@ -208,14 +262,14 @@ border: 1px solid $border-top; border-color: $border-top $border-sides $border-bottom; border-radius: 16px; - box-shadow: inset 0 1px 0 0 $inset-shadow, 0 1px 2px 0 #b3b3b3; + box-shadow: inset 0 1px 0 0 $inset-shadow; color: $color; display: inline-block; - font-size: inherit; + font-size: $textsize; font-weight: normal; line-height: 1; @include linear-gradient ($base-color, $stop-gradient); - padding: 5px 16px; + padding: $padding; text-align: center; text-decoration: none; text-shadow: 0 -1px 1px $text-shadow; @@ -249,7 +303,8 @@ background-clip: padding-box; } - &:active:not(:disabled) { + &:active:not(:disabled), + &:focus:not(:disabled) { $active-color: adjust-color($base-color, $hue: 4, $saturation: -12%, $lightness: -10%); $border-active: adjust-color($base-color, $hue: 6, $saturation: -2.5%, $lightness: -30%); $border-bottom-active: adjust-color($base-color, $hue: 11, $saturation: 6%, $lightness: -31%); @@ -267,7 +322,53 @@ background: $active-color; border: 1px solid $border-active; border-bottom: 1px solid $border-bottom-active; - box-shadow: inset 0 0 6px 3px $inset-shadow-active, 0 1px 0 0 #fff; + box-shadow: inset 0 0 6px 3px $inset-shadow-active; text-shadow: 0 -1px 1px $text-shadow-active; } } + + + +// Flat Button +//************************************************************************// +@mixin flat($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) { + $color: hsl(0, 0, 100%); + + @if is-light($base-color) { + $color: hsl(0, 0, 20%); + } + + background-color: $base-color; + border-radius: 3px; + border: none; + color: $color; + display: inline-block; + font-size: inherit; + font-weight: bold; + padding: 7px 18px; + text-decoration: none; + background-clip: padding-box; + + &:hover:not(:disabled){ + $base-color-hover: adjust-color($base-color, $saturation: 4%, $lightness: 5%); + + @if $grayscale == true { + $base-color-hover: grayscale($base-color-hover); + } + + background-color: $base-color-hover; + cursor: pointer; + } + + &:active:not(:disabled), + &:focus:not(:disabled) { + $base-color-active: adjust-color($base-color, $saturation: -4%, $lightness: -5%); + + @if $grayscale == true { + $base-color-active: grayscale($base-color-active); + } + + background-color: $base-color-active; + cursor: pointer; + } +} diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_directional-values.scss b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_directional-values.scss index 4818f62fd8..742f1031a4 100644 --- a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_directional-values.scss +++ b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_directional-values.scss @@ -57,9 +57,6 @@ $right: $pre + "-right" + if($suf, "-#{$suf}", ""); $all: $pre + if($suf, "-#{$suf}", ""); - // Get list inside $vals (is there a better way?) - @each $val in $vals { $vals: $val; } - $vals: collapse-directionals($vals); @if contains-falsy($vals) { @@ -94,21 +91,21 @@ } @mixin margin($vals...) { - @include directional-property(margin, false, $vals); + @include directional-property(margin, false, $vals...); } @mixin padding($vals...) { - @include directional-property(padding, false, $vals); + @include directional-property(padding, false, $vals...); } @mixin border-style($vals...) { - @include directional-property(border, style, $vals); + @include directional-property(border, style, $vals...); } @mixin border-color($vals...) { - @include directional-property(border, color, $vals); + @include directional-property(border, color, $vals...); } @mixin border-width($vals...) { - @include directional-property(border, width, $vals); + @include directional-property(border, width, $vals...); } diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_html5-input-types.scss b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_html5-input-types.scss index 26fc879021..8428e4e194 100644 --- a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_html5-input-types.scss +++ b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_html5-input-types.scss @@ -22,7 +22,7 @@ $inputs-list: 'input[type="email"]', $unquoted-inputs-list: (); @each $input-type in $inputs-list { - $unquoted-inputs-list: append($unquoted-inputs-list, unquote($input-type), comma) !global; + $unquoted-inputs-list: append($unquoted-inputs-list, unquote($input-type), comma); } $all-text-inputs: $unquoted-inputs-list; @@ -33,7 +33,7 @@ $all-text-inputs: $unquoted-inputs-list; $all-text-inputs-hover: (); @each $input-type in $unquoted-inputs-list { $input-type-hover: $input-type + ":hover"; - $all-text-inputs-hover: append($all-text-inputs-hover, $input-type-hover, comma) !global; + $all-text-inputs-hover: append($all-text-inputs-hover, $input-type-hover, comma); } // Focus Pseudo-class @@ -41,7 +41,7 @@ $all-text-inputs-hover: (); $all-text-inputs-focus: (); @each $input-type in $unquoted-inputs-list { $input-type-focus: $input-type + ":focus"; - $all-text-inputs-focus: append($all-text-inputs-focus, $input-type-focus, comma) !global; + $all-text-inputs-focus: append($all-text-inputs-focus, $input-type-focus, comma); } // You must use interpolation on the variable: diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_position.scss b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_position.scss index aba34edcd9..31a0699769 100644 --- a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_position.scss +++ b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_position.scss @@ -14,19 +14,19 @@ position: $position; - @if ($top and $top == auto) or (type-of($top) == number and not unitless($top)) { + @if ($top and $top == auto) or (type-of($top) == number and not(unitless($top))) { top: $top; } - @if ($right and $right == auto) or (type-of($right) == number and not unitless($right)) { + @if ($right and $right == auto) or (type-of($right) == number and not(unitless($right))) { right: $right; } - @if ($bottom and $bottom == auto) or (type-of($bottom) == number and not unitless($bottom)) { + @if ($bottom and $bottom == auto) or (type-of($bottom) == number and not(unitless($bottom))) { bottom: $bottom; } - @if ($left and $left == auto) or (type-of($left) == number and not unitless($left)) { + @if ($left and $left == auto) or (type-of($left) == number and not(unitless($left))) { left: $left; } } diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_rem.scss b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_rem.scss deleted file mode 100644 index ddd7022b44..0000000000 --- a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_rem.scss +++ /dev/null @@ -1,33 +0,0 @@ -@mixin rem($property, $size, $base: $em-base) { - @if not unitless($base) { - $base: strip-units($base); - } - - $unitless_values: (); - @each $num in $size { - @if not unitless($num) { - @if unit($num) == "em" { - $num: $num * $base; - } - - $num: strip-units($num); - } - - $unitless_values: append($unitless_values, $num); - } - $size: $unitless_values; - - $pixel_values: (); - $rem_values: (); - @each $value in $pxval { - $pixel_value: $value * 1px; - $pixel_values: append($pixel_values, $pixel_value); - - $rem_value: ($value / $base) * 1rem; - $rem_values: append($rem_values, $rem_value); - } - - #{$property}: $pixel_values; - #{$property}: $rem_values; -} - diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_retina-image.scss b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_retina-image.scss index 7931bd1333..3995c1970a 100644 --- a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_retina-image.scss +++ b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_retina-image.scss @@ -1,4 +1,4 @@ -@mixin retina-image($filename, $background-size, $extension: png, $retina-filename: null, $retina-suffix: _2x, $asset-pipeline: false) { +@mixin retina-image($filename, $background-size, $extension: png, $retina-filename: null, $retina-suffix: _2x, $asset-pipeline: $asset-pipeline) { @if $asset-pipeline { background-image: image-url("#{$filename}.#{$extension}"); } diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_timing-functions.scss b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_timing-functions.scss index 51b2410914..5ecc6f9dcf 100644 --- a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_timing-functions.scss +++ b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_timing-functions.scss @@ -1,5 +1,5 @@ // CSS cubic-bezier timing functions. Timing functions courtesy of jquery.easie (github.com/jaukia/easie) -// Timing functions are the same as demo'ed here: http://jqueryui.com/demos/effect/easing.html +// Timing functions are the same as demo'ed here: http://jqueryui.com/resources/demos/effect/easing.html // EASE IN $ease-in-quad: cubic-bezier(0.550, 0.085, 0.680, 0.530); diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_triangle.scss b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_triangle.scss index 0e02aca2ca..3b29e2c3c0 100644 --- a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_triangle.scss +++ b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_triangle.scss @@ -2,44 +2,85 @@ height: 0; width: 0; + $width: nth($size, 1); + $height: nth($size, length($size)); + + $foreground-color: nth($color, 1); + $background-color: transparent !default; + @if (length($color) == 2) { + $background-color: nth($color, 2); + } + @if ($direction == up) or ($direction == down) or ($direction == right) or ($direction == left) { - border-color: transparent; - border-style: solid; - border-width: $size / 2; + + $width: $width / 2; + $height: if(length($size) > 1, $height, $height/2); @if $direction == up { - border-bottom-color: $color; + border-left: $width solid $background-color; + border-right: $width solid $background-color; + border-bottom: $height solid $foreground-color; } @else if $direction == right { - border-left-color: $color; + border-top: $width solid $background-color; + border-bottom: $width solid $background-color; + border-left: $height solid $foreground-color; } @else if $direction == down { - border-top-color: $color; + border-left: $width solid $background-color; + border-right: $width solid $background-color; + border-top: $height solid $foreground-color; } @else if $direction == left { - border-right-color: $color; + border-top: $width solid $background-color; + border-bottom: $width solid $background-color; + border-right: $height solid $foreground-color; } } @else if ($direction == up-right) or ($direction == up-left) { - border-top: $size solid $color; + border-top: $height solid $foreground-color; @if $direction == up-right { - border-left: $size solid transparent; + border-left: $width solid $background-color; } @else if $direction == up-left { - border-right: $size solid transparent; + border-right: $width solid $background-color; } } @else if ($direction == down-right) or ($direction == down-left) { - border-bottom: $size solid $color; + border-bottom: $height solid $foreground-color; @if $direction == down-right { - border-left: $size solid transparent; + border-left: $width solid $background-color; } @else if $direction == down-left { - border-right: $size solid transparent; + border-right: $width solid $background-color; } } + + @else if ($direction == inset-up) { + border-width: $height $width; + border-style: solid; + border-color: $background-color $background-color $foreground-color; + } + + @else if ($direction == inset-down) { + border-width: $height $width; + border-style: solid; + border-color: $foreground-color $background-color $background-color; + } + + @else if ($direction == inset-right) { + border-width: $width $height; + border-style: solid; + border-color: $background-color $background-color $background-color $foreground-color; + } + + @else if ($direction == inset-left) { + border-width: $width $height; + border-style: solid; + border-color: $background-color $foreground-color $background-color $background-color; + } } diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/addons/_word-wrap.scss b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_word-wrap.scss new file mode 100644 index 0000000000..9734a597cd --- /dev/null +++ b/WebContent/VAADIN/themes/valo/util/bourbon/addons/_word-wrap.scss @@ -0,0 +1,8 @@ +@mixin word-wrap($wrap: break-word) { + word-wrap: $wrap; + + @if $wrap == break-word { + overflow-wrap: break-word; + word-break: break-all; + } +} diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/css3/_columns.scss b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_columns.scss index 42274a4eeb..96f601c1a8 100644 --- a/WebContent/VAADIN/themes/valo/util/bourbon/css3/_columns.scss +++ b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_columns.scss @@ -15,7 +15,7 @@ @mixin column-fill($arg: auto) { // auto || length - @include prefixer(columns-fill, $arg, webkit moz spec); + @include prefixer(column-fill, $arg, webkit moz spec); } @mixin column-rule($arg) { diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/css3/_filter.scss b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_filter.scss new file mode 100644 index 0000000000..8560d77676 --- /dev/null +++ b/WebContent/VAADIN/themes/valo/util/bourbon/css3/_filter.scss @@ -0,0 +1,5 @@ +@mixin filter($function: none) { + // [= 1 { - @include prefixer(transition, $properties, webkit moz spec); + // Fix for vendor-prefix transform property + $needs-prefixes: false; + $webkit: (); + $moz: (); + $spec: (); + + // Create lists for vendor-prefixed transform + @each $list in $properties { + @if nth($list, 1) == "transform" { + $needs-prefixes: true; + $list1: -webkit-transform; + $list2: -moz-transform; + $list3: (); + + @each $var in $list { + $list3: join($list3, $var); + + @if $var != "transform" { + $list1: join($list1, $var); + $list2: join($list2, $var); + } + } + + $webkit: append($webkit, $list1); + $moz: append($moz, $list2); + $spec: append($spec, $list3); + } + + // Create lists for non-prefixed transition properties + @else { + $webkit: append($webkit, $list, comma); + $moz: append($moz, $list, comma); + $spec: append($spec, $list, comma); + } } + @if $needs-prefixes { + -webkit-transition: $webkit; + -moz-transition: $moz; + transition: $spec; + } @else { - $properties: all 0.15s ease-out 0s; - @include prefixer(transition, $properties, webkit moz spec); + @if length($properties) >= 1 { + @include prefixer(transition, $properties, webkit moz spec); + } + + @else { + $properties: all 0.15s ease-out 0s; + @include prefixer(transition, $properties, webkit moz spec); + } } } diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/functions/_color-lightness.scss b/WebContent/VAADIN/themes/valo/util/bourbon/functions/_color-lightness.scss new file mode 100644 index 0000000000..8c6df4e256 --- /dev/null +++ b/WebContent/VAADIN/themes/valo/util/bourbon/functions/_color-lightness.scss @@ -0,0 +1,13 @@ +// Programatically determines whether a color is light or dark +// Returns a boolean +// More details here http://robots.thoughtbot.com/closer-look-color-lightness + +@function is-light($hex-color) { + $-local-red: red(rgba($hex-color, 1.0)); + $-local-green: green(rgba($hex-color, 1.0)); + $-local-blue: blue(rgba($hex-color, 1.0)); + + $-local-lightness: ($-local-red * 0.2126 + $-local-green * 0.7152 + $-local-blue * 0.0722) / 255; + + @return $-local-lightness > .6; +} diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/functions/_modular-scale.scss b/WebContent/VAADIN/themes/valo/util/bourbon/functions/_modular-scale.scss index 0a7185916c..afc59eb954 100644 --- a/WebContent/VAADIN/themes/valo/util/bourbon/functions/_modular-scale.scss +++ b/WebContent/VAADIN/themes/valo/util/bourbon/functions/_modular-scale.scss @@ -1,4 +1,4 @@ -// Scaling Varaibles +// Scaling Variables $golden: 1.618; $minor-second: 1.067; $major-second: 1.125; diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/functions/_px-to-rem.scss b/WebContent/VAADIN/themes/valo/util/bourbon/functions/_px-to-rem.scss new file mode 100644 index 0000000000..96b244e4cb --- /dev/null +++ b/WebContent/VAADIN/themes/valo/util/bourbon/functions/_px-to-rem.scss @@ -0,0 +1,15 @@ +// Convert pixels to rems +// eg. for a relational value of 12px write rem(12) +// Assumes $em-base is the font-size of + +@function rem($pxval) { + @if not unitless($pxval) { + $pxval: strip-units($pxval); + } + + $base: $em-base; + @if not unitless($base) { + $base: strip-units($base); + } + @return ($pxval / $base) * 1rem; +} diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/functions/_transition-property-name.scss b/WebContent/VAADIN/themes/valo/util/bourbon/functions/_transition-property-name.scss index 6ceae72102..49e621d63d 100644 --- a/WebContent/VAADIN/themes/valo/util/bourbon/functions/_transition-property-name.scss +++ b/WebContent/VAADIN/themes/valo/util/bourbon/functions/_transition-property-name.scss @@ -2,21 +2,21 @@ // Example: transition-property-names((transform, color, background), moz) -> -moz-transform, color, background //************************************************************************// @function transition-property-names($props, $vendor: false) { - $new-props: (); - - @each $prop in $props { - $new-props: append($new-props, transition-property-name($prop, $vendor), comma); - } + $new-props: (); + + @each $prop in $props { + $new-props: append($new-props, transition-property-name($prop, $vendor), comma); + } - @return $new-props; + @return $new-props; } @function transition-property-name($prop, $vendor: false) { - // put other properties that need to be prefixed here aswell - @if $vendor and $prop == transform { - @return unquote('-' + $vendor + '-' + $prop); - } - @else { - @return $prop; - } + // put other properties that need to be prefixed here aswell + @if $vendor and $prop == transform { + @return unquote('-' + $vendor + '-' + $prop); + } + @else { + @return $prop; + } } \ No newline at end of file diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/functions/_transition-property-name.scss~ b/WebContent/VAADIN/themes/valo/util/bourbon/functions/_transition-property-name.scss~ new file mode 100644 index 0000000000..4b23fccbed --- /dev/null +++ b/WebContent/VAADIN/themes/valo/util/bourbon/functions/_transition-property-name.scss~ @@ -0,0 +1,22 @@ +// Return vendor-prefixed property names if appropriate +// Example: transition-property-names((transform, color, background), moz) -> -moz-transform, color, background +//************************************************************************// +@function transition-property-names($props, $vendor: false) { + $new-props: (); + + @each $prop in $props { + $new-props: append($new-props, transition-property-name($prop, $vendor), comma); + } + + @return $new-props; +} + +@function transition-property-name($prop, $vendor: false) { + // put other properties that need to be prefixed here aswell + @if $vendor and $prop == transform { + @return unquote( '-' + $vendor + '-' + $prop); + } + @else { + @return $prop; + } +} \ No newline at end of file diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/helpers/_render-gradients.scss b/WebContent/VAADIN/themes/valo/util/bourbon/helpers/_render-gradients.scss index 5765676838..c145110a17 100644 --- a/WebContent/VAADIN/themes/valo/util/bourbon/helpers/_render-gradients.scss +++ b/WebContent/VAADIN/themes/valo/util/bourbon/helpers/_render-gradients.scss @@ -16,11 +16,11 @@ } @if $vendor { - $vendor-gradients: -#{$vendor}-#{$gradient-type}-gradient(#{$pre-spec} $gradients); + $vendor-gradients: "-#{$vendor}-#{$gradient-type}-gradient(#{$pre-spec} #{$gradients})"; } @else if $vendor == false { $vendor-gradients: "#{$gradient-type}-gradient(#{$spec} #{$gradients})"; - $vendor-gradients: unquote($vendor-gradients); } + $vendor-gradients: unquote($vendor-gradients); @return $vendor-gradients; } diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/settings/_asset-pipeline.scss b/WebContent/VAADIN/themes/valo/util/bourbon/settings/_asset-pipeline.scss new file mode 100644 index 0000000000..d481a6afb1 --- /dev/null +++ b/WebContent/VAADIN/themes/valo/util/bourbon/settings/_asset-pipeline.scss @@ -0,0 +1 @@ +$asset-pipeline: false !default; diff --git a/WebContent/VAADIN/themes/valo/util/bourbon/settings/_prefixer.scss b/WebContent/VAADIN/themes/valo/util/bourbon/settings/_prefixer.scss index c29a961919..ecab49fb54 100644 --- a/WebContent/VAADIN/themes/valo/util/bourbon/settings/_prefixer.scss +++ b/WebContent/VAADIN/themes/valo/util/bourbon/settings/_prefixer.scss @@ -1,6 +1,6 @@ // Variable settings for /addons/prefixer.scss -$prefix-for-webkit: true; -$prefix-for-mozilla: true; -$prefix-for-microsoft: true; -$prefix-for-opera: true; -$prefix-for-spec: true; // required for keyframe mixin +$prefix-for-webkit: true !default; +$prefix-for-mozilla: true !default; +$prefix-for-microsoft: true !default; +$prefix-for-opera: true !default; +$prefix-for-spec: true !default; // required for keyframe mixin -- cgit v1.2.3 From c954a7836ceb8410d6250256ddc3bc7584e76774 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Mon, 24 Aug 2015 13:57:27 +0300 Subject: Fix Grid column width calculation regression (#18617) Change-Id: I359240ff393428dd5d6764d5e01a40022ab94fc6 --- client/src/com/vaadin/client/widgets/Grid.java | 9 +++++++-- .../grid/basicfeatures/server/GridColumnMaxWidthTest.java | 6 +++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 3cc02e763c..8cd97715a8 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -2973,7 +2973,9 @@ public class Grid extends ResizeComposite implements for (Column column : visibleColumns) { final double widthAsIs = column.getWidth(); final boolean isFixedWidth = widthAsIs >= 0; - final double widthFixed = Math.max(widthAsIs, + // Check for max width just to be sure we don't break the limits + final double widthFixed = Math.max( + Math.min(getMaxWidth(column), widthAsIs), column.getMinimumWidth()); defaultExpandRatios = defaultExpandRatios && (column.getExpandRatio() == -1 || column == selectionColumn); @@ -3013,7 +3015,10 @@ public class Grid extends ResizeComposite implements double pixelsToDistribute = escalator.getInnerWidth() - reservedPixels; if (pixelsToDistribute <= 0 || totalRatios <= 0) { - setColumnSizes(columnSizes); + if (pixelsToDistribute <= 0) { + // Set column sizes for expanding columns + setColumnSizes(columnSizes); + } return; } diff --git a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnMaxWidthTest.java b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnMaxWidthTest.java index dffa22fdc6..7f19559aec 100644 --- a/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnMaxWidthTest.java +++ b/uitest/src/com/vaadin/tests/components/grid/basicfeatures/server/GridColumnMaxWidthTest.java @@ -24,14 +24,14 @@ import com.vaadin.tests.components.grid.basicfeatures.GridBasicFeaturesTest; public class GridColumnMaxWidthTest extends GridBasicFeaturesTest { @Test - public void testRemovingAllColumns() { + public void testMaxWidthAffectsColumnWidth() { setDebug(true); openTestURL(); selectMenuPath("Component", "Columns", "All columns expanding, Col 0 has max width of 30px"); - assertEquals("Column 0 did not obey max width of 30px.", "30px", - getGridElement().getCell(0, 0).getCssValue("width")); + assertEquals("Column 0 did not obey max width of 30px.", 30, + getGridElement().getCell(0, 0).getSize().getWidth()); } } \ No newline at end of file -- cgit v1.2.3 From c413b480663e9b3cbda00faf14eb4df224c6a10a Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Mon, 24 Aug 2015 14:38:19 +0300 Subject: Fix Table ColumnCollapseEvents to work with generated columns (#6914) Change-Id: Id2039cc4869695a8f4bbaa8f25f44f804433e909 --- server/src/com/vaadin/ui/Table.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/server/src/com/vaadin/ui/Table.java b/server/src/com/vaadin/ui/Table.java index 2cd4084ad9..10d1c45ab6 100644 --- a/server/src/com/vaadin/ui/Table.java +++ b/server/src/com/vaadin/ui/Table.java @@ -1322,7 +1322,8 @@ public class Table extends AbstractSelect implements Action.Container, if (collapsed && noncollapsibleColumns.contains(propertyId)) { throw new IllegalStateException("The column is noncollapsible!"); } - if (!getContainerPropertyIds().contains(propertyId)) { + if (!getContainerPropertyIds().contains(propertyId) + && !columnGenerators.containsKey(propertyId)) { throw new IllegalArgumentException("Property '" + propertyId + "' was not found in the container"); } @@ -5772,7 +5773,7 @@ public class Table extends AbstractSelect implements Action.Container, * @param source * The source of the event * @param propertyId - * The id of the coumn + * The id of the column */ public ColumnCollapseEvent(Component source, Object propertyId) { super(source); -- cgit v1.2.3 From 79694b4f8017acc33f302e63fd3c5e3679c73ddd Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 14 Jul 2015 18:04:09 +0300 Subject: Resynchronize everything after theme change (#18478) Change-Id: Id56d0ff7b2c675780c84efe999cb4b9d655df4cd --- .../com/vaadin/client/ApplicationConnection.java | 3 +- .../src/com/vaadin/client/ui/ui/UIConnector.java | 53 ++-------------------- .../tests/themes/LegacyComponentThemeChange.java | 6 ++- .../themes/LegacyComponentThemeChangeTest.java | 16 ++++++- 4 files changed, 26 insertions(+), 52 deletions(-) diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java index d9e705426b..cb780e7273 100644 --- a/client/src/com/vaadin/client/ApplicationConnection.java +++ b/client/src/com/vaadin/client/ApplicationConnection.java @@ -63,7 +63,6 @@ import com.google.gwt.user.client.Window.ClosingHandler; import com.google.gwt.user.client.ui.HasWidgets; import com.google.gwt.user.client.ui.Widget; import com.vaadin.client.ApplicationConfiguration.ErrorMessage; -import com.vaadin.client.ApplicationConnection.ApplicationStoppedEvent; import com.vaadin.client.ResourceLoader.ResourceLoadEvent; import com.vaadin.client.ResourceLoader.ResourceLoadListener; import com.vaadin.client.communication.HasJavaScriptConnectorHelper; @@ -804,7 +803,7 @@ public class ApplicationConnection implements HasHandlers { return parameters; } - protected void repaintAll() { + public void repaintAll() { makeUidlRequest(Json.createArray(), getRepaintAllParameters()); } diff --git a/client/src/com/vaadin/client/ui/ui/UIConnector.java b/client/src/com/vaadin/client/ui/ui/UIConnector.java index bcd90437a4..e0a4608505 100644 --- a/client/src/com/vaadin/client/ui/ui/UIConnector.java +++ b/client/src/com/vaadin/client/ui/ui/UIConnector.java @@ -1040,58 +1040,15 @@ public class UIConnector extends AbstractSingleComponentContainerConnector } - forceStateChangeRecursively(UIConnector.this); - // UIDL has no stored URL which we can repaint so we do some find and - // replace magic... - String newThemeBase = getConnection().translateVaadinUri("theme://"); - replaceThemeAttribute(oldThemeBase, newThemeBase); + // Request a full resynchronization from the server to deal with legacy + // components + getConnection().repaintAll(); + // Immediately update state and do layout while waiting for the resync + forceStateChangeRecursively(UIConnector.this); getLayoutManager().forceLayout(); } - /** - * Finds all attributes where theme:// urls have possibly been used and - * replaces any old theme url with a new one - * - * @param oldPrefix - * The start of the old theme URL - * @param newPrefix - * The start of the new theme URL - */ - private void replaceThemeAttribute(String oldPrefix, String newPrefix) { - // Images - replaceThemeAttribute("src", oldPrefix, newPrefix); - // Embedded flash - replaceThemeAttribute("value", oldPrefix, newPrefix); - replaceThemeAttribute("movie", oldPrefix, newPrefix); - } - - /** - * Finds any attribute of the given type where theme:// urls have possibly - * been used and replaces any old theme url with a new one - * - * @param attributeName - * The name of the attribute, e.g. "src" - * @param oldPrefix - * The start of the old theme URL - * @param newPrefix - * The start of the new theme URL - */ - private void replaceThemeAttribute(String attributeName, String oldPrefix, - String newPrefix) { - // Find all "attributeName=" which start with "oldPrefix" using e.g. - // [^src='http://oldpath'] - NodeList elements = querySelectorAll("[" + attributeName - + "^='" + oldPrefix + "']"); - for (int i = 0; i < elements.getLength(); i++) { - Element element = elements.getItem(i); - element.setAttribute( - attributeName, - element.getAttribute(attributeName).replace(oldPrefix, - newPrefix)); - } - } - /** * Force a full recursive recheck of every connector's state variables. * diff --git a/uitest/src/com/vaadin/tests/themes/LegacyComponentThemeChange.java b/uitest/src/com/vaadin/tests/themes/LegacyComponentThemeChange.java index 4582123f5f..0a57b77aa3 100644 --- a/uitest/src/com/vaadin/tests/themes/LegacyComponentThemeChange.java +++ b/uitest/src/com/vaadin/tests/themes/LegacyComponentThemeChange.java @@ -29,6 +29,7 @@ import com.vaadin.ui.ComboBox; import com.vaadin.ui.Embedded; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.MenuBar; +import com.vaadin.ui.MenuBar.MenuItem; import com.vaadin.ui.Table; import com.vaadin.ui.VerticalLayout; @@ -60,7 +61,10 @@ public class LegacyComponentThemeChange extends AbstractTestUIWithLog { ThemeResource varyingIcon = new ThemeResource("menubar-theme-icon.png"); MenuBar bar = new MenuBar(); bar.addItem("runo", alwaysTheSameIconImage, null); - bar.addItem("seletedtheme", varyingIcon, null); + bar.addItem("selectedtheme", varyingIcon, null); + MenuItem sub = bar.addItem("sub menu", null); + sub.addItem("runo", alwaysTheSameIconImage, null); + sub.addItem("selectedtheme", varyingIcon, null); vl.addComponent(bar); diff --git a/uitest/src/com/vaadin/tests/themes/LegacyComponentThemeChangeTest.java b/uitest/src/com/vaadin/tests/themes/LegacyComponentThemeChangeTest.java index c6593104da..3c992f3af5 100644 --- a/uitest/src/com/vaadin/tests/themes/LegacyComponentThemeChangeTest.java +++ b/uitest/src/com/vaadin/tests/themes/LegacyComponentThemeChangeTest.java @@ -122,8 +122,22 @@ public class LegacyComponentThemeChangeTest extends MultiBrowserTest { // The other image should change with the theme WebElement themeImage = $(MenuBarElement.class).first().findElement( - By.xpath(".//span[text()='seletedtheme']/img")); + By.xpath(".//span[text()='selectedtheme']/img")); assertAttributePrefix(themeImage, "src", theme); + + WebElement subMenuItem = $(MenuBarElement.class).first().findElement( + By.xpath(".//span[text()='sub menu']")); + subMenuItem.click(); + + WebElement subMenu = findElement(By.className("v-menubar-popup")); + WebElement subMenuRuno = subMenu.findElement(By + .xpath(".//span[text()='runo']/img")); + String subMenuRunoImageSrc = subMenuRuno.getAttribute("src"); + Assert.assertEquals(getThemeURL("runo") + "icons/16/ok.png", + subMenuRunoImageSrc); + WebElement subMenuThemeImage = subMenu.findElement(By + .xpath(".//span[text()='selectedtheme']/img")); + assertAttributePrefix(subMenuThemeImage, "src", theme); } private void assertAttributePrefix(WebElement element, String attribute, -- cgit v1.2.3 From 86cf519cd08693444ef3639aeb7b23b30e7aaf25 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Mon, 27 Jul 2015 21:48:32 +0300 Subject: Make checkbox inline-block like all other widgets (#18518) Change-Id: Ibec4c7162e9f51baff2534dfc763aa5a83cf915d --- WebContent/VAADIN/themes/base/button/checkbox.scss | 4 -- .../splitpanel/GridLayoutWithCheckbox.java | 58 +++++++++++++++++ .../splitpanel/GridLayoutWithCheckboxTest.java | 75 ++++++++++++++++++++++ 3 files changed, 133 insertions(+), 4 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/splitpanel/GridLayoutWithCheckbox.java create mode 100644 uitest/src/com/vaadin/tests/components/splitpanel/GridLayoutWithCheckboxTest.java diff --git a/WebContent/VAADIN/themes/base/button/checkbox.scss b/WebContent/VAADIN/themes/base/button/checkbox.scss index cc6143dbc1..e46d236035 100644 --- a/WebContent/VAADIN/themes/base/button/checkbox.scss +++ b/WebContent/VAADIN/themes/base/button/checkbox.scss @@ -1,9 +1,5 @@ @mixin base-checkbox($primaryStyleName : v-checkbox) { - .#{$primaryStyleName} { - display: block; - } - .#{$primaryStyleName}, .#{$primaryStyleName} label, .#{$primaryStyleName} input, diff --git a/uitest/src/com/vaadin/tests/components/splitpanel/GridLayoutWithCheckbox.java b/uitest/src/com/vaadin/tests/components/splitpanel/GridLayoutWithCheckbox.java new file mode 100644 index 0000000000..0dc371e57c --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/splitpanel/GridLayoutWithCheckbox.java @@ -0,0 +1,58 @@ +package com.vaadin.tests.components.splitpanel; + +import com.vaadin.annotations.Theme; +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.event.FieldEvents.TextChangeEvent; +import com.vaadin.event.FieldEvents.TextChangeListener; +import com.vaadin.server.VaadinRequest; +import com.vaadin.ui.AbstractTextField.TextChangeEventMode; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.GridLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.TextField; +import com.vaadin.ui.UI; +import com.vaadin.ui.Window; + +@Theme("reindeer") +public class GridLayoutWithCheckbox extends UI { + + @Override + protected void init(VaadinRequest request) { + GridLayout grid = new GridLayout(2, 3); + grid.setWidth(500, Unit.PIXELS); + + Label l = new Label("Textfield 1:"); + grid.addComponent(l, 0, 0); + TextField textfield = new TextField(); + textfield.addTextChangeListener(new TextChangeListener() { + + @Override + public void textChange(TextChangeEvent event) { + + } + }); + textfield.setTextChangeEventMode(TextChangeEventMode.EAGER); + grid.addComponent(textfield, 1, 0); + + l = new Label("CheckBox:"); + grid.addComponent(l, 0, 1); + CheckBox checkBox = new CheckBox(); + grid.addComponent(checkBox, 1, 2); + checkBox.addValueChangeListener(new ValueChangeListener() { + + @Override + public void valueChange(ValueChangeEvent event) { + + } + }); + Window window = new Window(); + window.setWidth(300.0f, Unit.PIXELS); + window.setContent(grid); + window.setResizable(false); + window.setWidth(550, Unit.PIXELS); + + // grid.setColumnExpandRatio(1, 1); + addWindow(window); + } +} \ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/components/splitpanel/GridLayoutWithCheckboxTest.java b/uitest/src/com/vaadin/tests/components/splitpanel/GridLayoutWithCheckboxTest.java new file mode 100644 index 0000000000..fee46c155a --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/splitpanel/GridLayoutWithCheckboxTest.java @@ -0,0 +1,75 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.components.splitpanel; + +import org.junit.Assert; +import org.junit.Test; +import org.openqa.selenium.By; +import org.openqa.selenium.Dimension; +import org.openqa.selenium.WebElement; + +import com.vaadin.testbench.elements.CheckBoxElement; +import com.vaadin.testbench.elements.TextFieldElement; +import com.vaadin.tests.tb3.MultiBrowserTest; + +public class GridLayoutWithCheckboxTest extends MultiBrowserTest { + + private TextFieldElement tf; + private WebElement tfSlot; + private CheckBoxElement cb; + private WebElement cbSlot; + private Dimension tfSize; + private Dimension tfSlotSize; + private Dimension cbSize; + private Dimension cbSlotSize; + + @Test + public void layoutShouldStayTheSame() { + openTestURL(); + tf = $(TextFieldElement.class).first(); + tfSlot = tf.findElement(By.xpath("..")); + cb = $(CheckBoxElement.class).first(); + cbSlot = cb.findElement(By.xpath("..")); + + // Doing anything with the textfield or checkbox should not affect + // layout + + tf.setValue("a"); + assertSizes(); + cb.click(); + assertSizes(); + tf.setValue("b"); + assertSizes(); + cb.click(); + assertSizes(); + + } + + private void assertSizes() { + if (tfSize == null) { + tfSize = tf.getSize(); + tfSlotSize = tfSlot.getSize(); + cbSize = cb.getSize(); + cbSlotSize = cbSlot.getSize(); + } else { + Assert.assertEquals(tfSize, tf.getSize()); + Assert.assertEquals(tfSlotSize, tfSlot.getSize()); + Assert.assertEquals(cbSize, cb.getSize()); + Assert.assertEquals(cbSlotSize, cbSlot.getSize()); + } + + } +} -- cgit v1.2.3 From 136e24ab7464c03b9c85abae3a431ff6f1195732 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Mon, 24 Aug 2015 21:13:14 +0300 Subject: Measure width exactly to avoid white padding at the right edge (#18648) Change-Id: Iaeb5fc84f08746967f664466c3e2e7d09d76e0cc --- client/src/com/vaadin/client/ComputedStyle.java | 27 ++++++++++++++++++++++ client/src/com/vaadin/client/ui/VFilterSelect.java | 13 ++++------- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/client/src/com/vaadin/client/ComputedStyle.java b/client/src/com/vaadin/client/ComputedStyle.java index cd90e0e78b..676d18d245 100644 --- a/client/src/com/vaadin/client/ComputedStyle.java +++ b/client/src/com/vaadin/client/ComputedStyle.java @@ -331,4 +331,31 @@ public class ComputedStyle { return paddingWidth; } + + /** + * Returns the sum of the top and bottom margin + * + * @since + * @return the sum of the top and bottom margin + */ + public double getMarginHeight() { + double marginHeight = getDoubleProperty("marginTop"); + marginHeight += getDoubleProperty("marginBottom"); + + return marginHeight; + } + + /** + * Returns the sum of the top and bottom margin + * + * @since + * @return the sum of the left and right margin + */ + public double getMarginWidth() { + double marginWidth = getDoubleProperty("marginLeft"); + marginWidth += getDoubleProperty("marginRight"); + + return marginWidth; + } + } diff --git a/client/src/com/vaadin/client/ui/VFilterSelect.java b/client/src/com/vaadin/client/ui/VFilterSelect.java index d756c88f79..cf03382333 100644 --- a/client/src/com/vaadin/client/ui/VFilterSelect.java +++ b/client/src/com/vaadin/client/ui/VFilterSelect.java @@ -617,14 +617,15 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, // Must take margin,border,padding manually into account for // menu element as we measure the element child and set width to // the element parent - int naturalMenuOuterWidth = naturalMenuWidth + double naturalMenuOuterWidth = WidgetUtil + .getRequiredWidthDouble(menuFirstChild) + getMarginBorderPaddingWidth(menu.getElement()); /* * IE requires us to specify the width for the container * element. Otherwise it will be 100% wide */ - int rootWidth = Math.max(desiredWidth - popupOuterPadding, + double rootWidth = Math.max(desiredWidth - popupOuterPadding, naturalMenuOuterWidth); getContainerElement().getStyle().setWidth(rootWidth, Unit.PX); } @@ -1291,13 +1292,9 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, sinkEvents(Event.ONPASTE); } - private static int getMarginBorderPaddingWidth(Element element) { + private static double getMarginBorderPaddingWidth(Element element) { final ComputedStyle s = new ComputedStyle(element); - int[] margin = s.getMargin(); - int[] border = s.getBorder(); - int[] padding = s.getPadding(); - return margin[1] + margin[3] + border[1] + border[3] + padding[1] - + padding[3]; + return s.getMarginWidth() + s.getBorderWidth() + s.getPaddingWidth(); } -- cgit v1.2.3 From 672e035c36f4bd2b38c69c2ef9b50428dbc266d7 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Wed, 29 Jul 2015 15:03:44 +0300 Subject: Helper method for enabling all Atmosphere logging Change-Id: Ibd26d84bd67a244e3a1837491652a84b85f40f65 --- .../communication/AtmospherePushConnection.java | 30 ++++++++++++++++++++++ .../tests/server/ClassesSerializableTest.java | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java index a45d9aa059..e1bc8e212b 100644 --- a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java +++ b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java @@ -26,7 +26,9 @@ import java.io.Writer; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.logging.ConsoleHandler; import java.util.logging.Level; +import java.util.logging.LogRecord; import java.util.logging.Logger; import org.atmosphere.cpr.AtmosphereResource; @@ -352,4 +354,32 @@ public class AtmospherePushConnection implements PushConnection { private static Logger getLogger() { return Logger.getLogger(AtmospherePushConnection.class.getName()); } + + /** + * Internal method used for reconfiguring loggers to show all Atmosphere log + * messages in the console. + * + * @since + */ + public static void enableAtmosphereDebugLogging() { + Level level = Level.FINEST; + + Logger atmosphereLogger = Logger.getLogger("org.atmosphere"); + if (atmosphereLogger.getLevel() == level) { + // Already enabled + return; + } + + atmosphereLogger.setLevel(level); + + // Without this logging, we will have a ClassCircularityError + LogRecord record = new LogRecord(Level.INFO, + "Enabling Atmosphere debug logging"); + atmosphereLogger.log(record); + + ConsoleHandler ch = new ConsoleHandler(); + ch.setLevel(Level.ALL); + atmosphereLogger.addHandler(ch); + } + } diff --git a/server/tests/src/com/vaadin/tests/server/ClassesSerializableTest.java b/server/tests/src/com/vaadin/tests/server/ClassesSerializableTest.java index 9603032ce5..829ad0455d 100644 --- a/server/tests/src/com/vaadin/tests/server/ClassesSerializableTest.java +++ b/server/tests/src/com/vaadin/tests/server/ClassesSerializableTest.java @@ -73,7 +73,7 @@ public class ClassesSerializableTest extends TestCase { "com\\.vaadin\\.server\\.AbstractClientConnector\\$1\\$1", // "com\\.vaadin\\.server\\.JsonCodec\\$1", // "com\\.vaadin\\.server\\.communication\\.PushConnection", // - "com\\.vaadin\\.server\\.communication\\.AtmospherePushConnection", // + "com\\.vaadin\\.server\\.communication\\.AtmospherePushConnection.*", // "com\\.vaadin\\.util\\.ConnectorHelper", // "com\\.vaadin\\.server\\.VaadinSession\\$FutureAccess", // "com\\.vaadin\\.external\\..*", // -- cgit v1.2.3 From 1cef2d2f428ee1555c8b933314582b16112941bd Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Wed, 8 Jul 2015 20:04:43 +0300 Subject: Fix multiple book keeping problems in ContainerOrderedWrapper (#5934, #18422) Change-Id: Ia749252ebf7034da5f3273ef117ab4ba35ad39b6 --- .../vaadin/data/util/ContainerOrderedWrapper.java | 24 +++- .../data/util/AbstractContainerTestBase.java | 153 ++++++++++++++++----- .../AbstractHierarchicalContainerTestBase.java | 29 ++++ .../util/ContainerHierarchicalWrapperTest.java | 20 --- .../data/util/ContainerOrderedWrapperTest.java | 102 ++++++++++++++ .../HierarchicalContainerOrderedWrapperTest.java | 27 ++++ 6 files changed, 291 insertions(+), 64 deletions(-) create mode 100644 server/tests/src/com/vaadin/data/util/ContainerOrderedWrapperTest.java create mode 100644 server/tests/src/com/vaadin/data/util/HierarchicalContainerOrderedWrapperTest.java diff --git a/server/src/com/vaadin/data/util/ContainerOrderedWrapper.java b/server/src/com/vaadin/data/util/ContainerOrderedWrapper.java index 4bb4e4c1b2..4329219e96 100644 --- a/server/src/com/vaadin/data/util/ContainerOrderedWrapper.java +++ b/server/src/com/vaadin/data/util/ContainerOrderedWrapper.java @@ -51,12 +51,14 @@ public class ContainerOrderedWrapper implements Container.Ordered, private final Container container; /** - * Ordering information, ie. the mapping from Item ID to the next item ID + * Ordering information, ie. the mapping from Item ID to the next item ID. + * The last item id should not be present */ private Hashtable next; /** - * Reverse ordering information for convenience and performance reasons. + * Reverse ordering information for convenience and performance reasons. The + * first item id should not be present */ private Hashtable prev; @@ -124,13 +126,21 @@ public class ContainerOrderedWrapper implements Container.Ordered, first = nid; } if (last.equals(id)) { - first = pid; + last = pid; } if (nid != null) { - prev.put(nid, pid); + if (pid == null) { + prev.remove(nid); + } else { + prev.put(nid, pid); + } } if (pid != null) { - next.put(pid, nid); + if (nid == null) { + next.remove(pid); + } else { + next.put(pid, nid); + } } next.remove(id); prev.remove(id); @@ -200,7 +210,7 @@ public class ContainerOrderedWrapper implements Container.Ordered, final Collection ids = container.getItemIds(); // Recreates ordering if some parts of it are missing - if (next == null || first == null || last == null || prev != null) { + if (next == null || first == null || last == null || prev == null) { first = null; last = null; next = new Hashtable(); @@ -219,7 +229,7 @@ public class ContainerOrderedWrapper implements Container.Ordered, // Adds missing items for (final Iterator i = ids.iterator(); i.hasNext();) { final Object id = i.next(); - if (!next.containsKey(id)) { + if (!next.containsKey(id) && last != id) { addToOrderWrapper(id); } } diff --git a/server/tests/src/com/vaadin/data/util/AbstractContainerTestBase.java b/server/tests/src/com/vaadin/data/util/AbstractContainerTestBase.java index 54cbc5305d..55dccc6455 100644 --- a/server/tests/src/com/vaadin/data/util/AbstractContainerTestBase.java +++ b/server/tests/src/com/vaadin/data/util/AbstractContainerTestBase.java @@ -11,6 +11,7 @@ import com.vaadin.data.Container; import com.vaadin.data.Container.Filterable; import com.vaadin.data.Container.ItemSetChangeEvent; import com.vaadin.data.Container.ItemSetChangeListener; +import com.vaadin.data.Container.Ordered; import com.vaadin.data.Container.Sortable; import com.vaadin.data.Item; import com.vaadin.data.util.filter.SimpleStringFilter; @@ -161,54 +162,54 @@ public abstract class AbstractContainerTestBase extends TestCase { validateContainer(container, sampleData[0], sampleData[sampleData.length - 1], sampleData[10], "abc", true, sampleData.length); + + validateRemovingItems(container); + } + + protected void validateRemovingItems(Container container) { + int sizeBeforeRemoving = container.size(); + + List itemIdList = new ArrayList(container.getItemIds()); + // There should be at least four items in the list + Object first = itemIdList.get(0); + Object middle = itemIdList.get(2); + Object last = itemIdList.get(itemIdList.size() - 1); + + container.removeItem(first); + container.removeItem(middle); // Middle now that first has been removed + container.removeItem(last); + + assertEquals(sizeBeforeRemoving - 3, container.size()); + + container.removeAllItems(); + + assertEquals(0, container.size()); } protected void testContainerOrdered(Container.Ordered container) { + // addItem with empty container Object id = container.addItem(); - assertNotNull(id); + assertOrderedContents(container, id); Item item = container.getItem(id); assertNotNull(item); - assertEquals(id, container.firstItemId()); - assertEquals(id, container.lastItemId()); - - // isFirstId - assertTrue(container.isFirstId(id)); - assertTrue(container.isFirstId(container.firstItemId())); - // isLastId - assertTrue(container.isLastId(id)); - assertTrue(container.isLastId(container.lastItemId())); + // addItemAfter with empty container + container.removeAllItems(); + assertOrderedContents(container); + id = container.addItemAfter(null); + assertOrderedContents(container, id); + item = container.getItem(id); + assertNotNull(item); // Add a new item before the first // addItemAfter Object newFirstId = container.addItemAfter(null); - assertNotNull(newFirstId); - assertNotNull(container.getItem(newFirstId)); - - // isFirstId - assertTrue(container.isFirstId(newFirstId)); - assertTrue(container.isFirstId(container.firstItemId())); - // isLastId - assertTrue(container.isLastId(id)); - assertTrue(container.isLastId(container.lastItemId())); - - // nextItemId - assertEquals(id, container.nextItemId(newFirstId)); - assertNull(container.nextItemId(id)); - assertNull(container.nextItemId("not-in-container")); - - // prevItemId - assertEquals(newFirstId, container.prevItemId(id)); - assertNull(container.prevItemId(newFirstId)); - assertNull(container.prevItemId("not-in-container")); + assertOrderedContents(container, newFirstId, id); // addItemAfter(Object) Object newSecondItemId = container.addItemAfter(newFirstId); // order is now: newFirstId, newSecondItemId, id - assertNotNull(newSecondItemId); - assertNotNull(container.getItem(newSecondItemId)); - assertEquals(id, container.nextItemId(newSecondItemId)); - assertEquals(newFirstId, container.prevItemId(newSecondItemId)); + assertOrderedContents(container, newFirstId, newSecondItemId, id); // addItemAfter(Object,Object) String fourthId = "id of the fourth item"; @@ -216,8 +217,8 @@ public abstract class AbstractContainerTestBase extends TestCase { // order is now: newFirstId, fourthId, newSecondItemId, id assertNotNull(fourth); assertEquals(fourth, container.getItem(fourthId)); - assertEquals(newSecondItemId, container.nextItemId(fourthId)); - assertEquals(newFirstId, container.prevItemId(fourthId)); + assertOrderedContents(container, newFirstId, fourthId, newSecondItemId, + id); // addItemAfter(Object,Object) Object fifthId = new Object(); @@ -225,8 +226,86 @@ public abstract class AbstractContainerTestBase extends TestCase { // order is now: fifthId, newFirstId, fourthId, newSecondItemId, id assertNotNull(fifth); assertEquals(fifth, container.getItem(fifthId)); - assertEquals(newFirstId, container.nextItemId(fifthId)); - assertNull(container.prevItemId(fifthId)); + assertOrderedContents(container, fifthId, newFirstId, fourthId, + newSecondItemId, id); + + // addItemAfter(Object,Object) + Object sixthId = new Object(); + Item sixth = container.addItemAfter(id, sixthId); + // order is now: fifthId, newFirstId, fourthId, newSecondItemId, id, + // sixthId + assertNotNull(sixth); + assertEquals(sixth, container.getItem(sixthId)); + assertOrderedContents(container, fifthId, newFirstId, fourthId, + newSecondItemId, id, sixthId); + + // Test order after removing first item 'fifthId' + container.removeItem(fifthId); + // order is now: newFirstId, fourthId, newSecondItemId, id, sixthId + assertOrderedContents(container, newFirstId, fourthId, newSecondItemId, + id, sixthId); + + // Test order after removing last item 'sixthId' + container.removeItem(sixthId); + // order is now: newFirstId, fourthId, newSecondItemId, id + assertOrderedContents(container, newFirstId, fourthId, newSecondItemId, + id); + + // Test order after removing item from the middle 'fourthId' + container.removeItem(fourthId); + // order is now: newFirstId, newSecondItemId, id + assertOrderedContents(container, newFirstId, newSecondItemId, id); + + // Delete remaining items + container.removeItem(newFirstId); + container.removeItem(newSecondItemId); + container.removeItem(id); + assertOrderedContents(container); + + Object finalItem = container.addItem(); + assertOrderedContents(container, finalItem); + } + + private void assertOrderedContents(Ordered container, Object... ids) { + assertEquals(ids.length, container.size()); + for (int i = 0; i < ids.length - 1; i++) { + assertNotNull("The item id should not be null", ids[i]); + } + if (ids.length == 0) { + assertNull("The first id is wrong", container.firstItemId()); + assertNull("The last id is wrong", container.lastItemId()); + return; + } + + assertEquals("The first id is wrong", ids[0], container.firstItemId()); + assertEquals("The last id is wrong", ids[ids.length - 1], + container.lastItemId()); + + // isFirstId & isLastId + assertTrue(container.isFirstId(container.firstItemId())); + assertTrue(container.isLastId(container.lastItemId())); + + // nextId + Object ref = container.firstItemId(); + for (int i = 1; i < ids.length; i++) { + Object next = container.nextItemId(ref); + assertEquals("The id after " + ref + " is wrong", ids[i], next); + ref = next; + } + assertNull("The last id should not have a next id", + container.nextItemId(ids[ids.length - 1])); + assertNull(container.nextItemId("not-in-container")); + + // prevId + ref = container.lastItemId(); + for (int i = ids.length - 2; i >= 0; i--) { + Object prev = container.prevItemId(ref); + assertEquals("The id before " + ref + " is wrong", ids[i], prev); + ref = prev; + } + assertNull("The first id should not have a prev id", + container.prevItemId(ids[0])); + assertNull(container.prevItemId("not-in-container")); } diff --git a/server/tests/src/com/vaadin/data/util/AbstractHierarchicalContainerTestBase.java b/server/tests/src/com/vaadin/data/util/AbstractHierarchicalContainerTestBase.java index 3bd00cce3c..9cede77162 100644 --- a/server/tests/src/com/vaadin/data/util/AbstractHierarchicalContainerTestBase.java +++ b/server/tests/src/com/vaadin/data/util/AbstractHierarchicalContainerTestBase.java @@ -253,4 +253,33 @@ public abstract class AbstractHierarchicalContainerTestBase extends } } + protected void testRemoveHierarchicalWrapperSubtree( + Container.Hierarchical container) { + initializeContainer(container); + + // remove root item + removeItemRecursively(container, "org"); + + int packages = 21 + 3 - 3; + int expectedSize = sampleData.length + packages - 1; + + validateContainer(container, "com", "com.vaadin.util.SerializerHelper", + "com.vaadin.server.ApplicationResource", "blah", true, + expectedSize); + + // rootItemIds + Collection rootIds = container.rootItemIds(); + assertEquals(1, rootIds.size()); + } + + private void removeItemRecursively(Container.Hierarchical container, + Object itemId) { + if (container instanceof ContainerHierarchicalWrapper) { + ((ContainerHierarchicalWrapper) container) + .removeItemRecursively("org"); + } else { + HierarchicalContainer.removeItemRecursively(container, itemId); + } + } + } diff --git a/server/tests/src/com/vaadin/data/util/ContainerHierarchicalWrapperTest.java b/server/tests/src/com/vaadin/data/util/ContainerHierarchicalWrapperTest.java index 2fd21ef118..8e554d5030 100644 --- a/server/tests/src/com/vaadin/data/util/ContainerHierarchicalWrapperTest.java +++ b/server/tests/src/com/vaadin/data/util/ContainerHierarchicalWrapperTest.java @@ -1,6 +1,5 @@ package com.vaadin.data.util; -import java.util.Collection; public class ContainerHierarchicalWrapperTest extends AbstractHierarchicalContainerTestBase { @@ -20,23 +19,4 @@ public class ContainerHierarchicalWrapperTest extends new IndexedContainer())); } - protected void testRemoveHierarchicalWrapperSubtree( - ContainerHierarchicalWrapper container) { - initializeContainer(container); - - // remove root item - container.removeItemRecursively("org"); - - int packages = 21 + 3 - 3; - int expectedSize = sampleData.length + packages - 1; - - validateContainer(container, "com", "com.vaadin.util.SerializerHelper", - "com.vaadin.server.ApplicationResource", "blah", true, - expectedSize); - - // rootItemIds - Collection rootIds = container.rootItemIds(); - assertEquals(1, rootIds.size()); - } - } diff --git a/server/tests/src/com/vaadin/data/util/ContainerOrderedWrapperTest.java b/server/tests/src/com/vaadin/data/util/ContainerOrderedWrapperTest.java new file mode 100644 index 0000000000..422e9756f8 --- /dev/null +++ b/server/tests/src/com/vaadin/data/util/ContainerOrderedWrapperTest.java @@ -0,0 +1,102 @@ +package com.vaadin.data.util; + +import java.util.Collection; + +import com.vaadin.data.Container; +import com.vaadin.data.Item; +import com.vaadin.data.Property; + +public class ContainerOrderedWrapperTest extends AbstractContainerTestBase { + + // This class is needed to get an implementation of container + // which is not an implementation of Ordered interface. + private class NotOrderedContainer implements Container { + + private IndexedContainer container; + + public NotOrderedContainer() { + container = new IndexedContainer(); + } + + @Override + public Item getItem(Object itemId) { + return container.getItem(itemId); + } + + @Override + public Collection getContainerPropertyIds() { + return container.getContainerPropertyIds(); + } + + @Override + public Collection getItemIds() { + return container.getItemIds(); + } + + @Override + public Property getContainerProperty(Object itemId, Object propertyId) { + return container.getContainerProperty(itemId, propertyId); + } + + @Override + public Class getType(Object propertyId) { + return container.getType(propertyId); + } + + @Override + public int size() { + return container.size(); + } + + @Override + public boolean containsId(Object itemId) { + return container.containsId(itemId); + } + + @Override + public Item addItem(Object itemId) throws UnsupportedOperationException { + return container.addItem(itemId); + } + + @Override + public Object addItem() throws UnsupportedOperationException { + return container.addItem(); + } + + @Override + public boolean removeItem(Object itemId) + throws UnsupportedOperationException { + return container.removeItem(itemId); + } + + @Override + public boolean addContainerProperty(Object propertyId, Class type, + Object defaultValue) throws UnsupportedOperationException { + return container.addContainerProperty(propertyId, type, + defaultValue); + } + + @Override + public boolean removeContainerProperty(Object propertyId) + throws UnsupportedOperationException { + return container.removeContainerProperty(propertyId); + } + + @Override + public boolean removeAllItems() throws UnsupportedOperationException { + return container.removeAllItems(); + } + + } + + public void testBasicOperations() { + testBasicContainerOperations(new ContainerOrderedWrapper( + new NotOrderedContainer())); + } + + public void testOrdered() { + testContainerOrdered(new ContainerOrderedWrapper( + new NotOrderedContainer())); + } + +} diff --git a/server/tests/src/com/vaadin/data/util/HierarchicalContainerOrderedWrapperTest.java b/server/tests/src/com/vaadin/data/util/HierarchicalContainerOrderedWrapperTest.java new file mode 100644 index 0000000000..7ecf59c309 --- /dev/null +++ b/server/tests/src/com/vaadin/data/util/HierarchicalContainerOrderedWrapperTest.java @@ -0,0 +1,27 @@ +package com.vaadin.data.util; + +public class HierarchicalContainerOrderedWrapperTest extends + AbstractHierarchicalContainerTestBase { + + private HierarchicalContainerOrderedWrapper createContainer() { + return new HierarchicalContainerOrderedWrapper( + new ContainerHierarchicalWrapper(new IndexedContainer())); + } + + public void testBasicOperations() { + testBasicContainerOperations(createContainer()); + } + + public void testHierarchicalContainer() { + testHierarchicalContainer(createContainer()); + } + + public void testContainerOrdered() { + testContainerOrdered(createContainer()); + } + + public void testRemoveSubtree() { + testRemoveHierarchicalWrapperSubtree(createContainer()); + } + +} -- cgit v1.2.3 From 71e8630e00a7f70885e26c47426c42e395992fe1 Mon Sep 17 00:00:00 2001 From: Artur Signell Date: Tue, 25 Aug 2015 14:18:46 +0300 Subject: Do not include Chrome version in test output Change-Id: I885ca2fb0d7ef23385107cdf700bb0b5d25e8d8a --- uitest/src/com/vaadin/tests/integration/JSR286Portlet.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/uitest/src/com/vaadin/tests/integration/JSR286Portlet.java b/uitest/src/com/vaadin/tests/integration/JSR286Portlet.java index 37f8e21c50..3fbf5b57ef 100644 --- a/uitest/src/com/vaadin/tests/integration/JSR286Portlet.java +++ b/uitest/src/com/vaadin/tests/integration/JSR286Portlet.java @@ -110,10 +110,16 @@ public class JSR286Portlet extends UI { } private void possiblyChangedModeOrState() { - VaadinPortletRequest request = (VaadinPortletRequest) VaadinPortletService - .getCurrentRequest(); - - userAgent.setValue(getPage().getWebBrowser().getBrowserApplication()); + VaadinPortletRequest request = VaadinPortletService.getCurrentRequest(); + + String censoredUserAgent = getPage().getWebBrowser() + .getBrowserApplication(); + if (censoredUserAgent.contains("Chrome/")) { + // Censor version info as it tends to change + censoredUserAgent = censoredUserAgent.replaceAll("Chrome/[^ ]* ", + "Chrome/xyz "); + } + userAgent.setValue(censoredUserAgent); screenWidth.setValue(String.valueOf(getPage().getBrowserWindowWidth())); screenHeight.setValue(String .valueOf(getPage().getBrowserWindowHeight())); -- cgit v1.2.3 From a5506fd68b81a9b1e53d88a1880b66a8a50eb148 Mon Sep 17 00:00:00 2001 From: Teemu Suo-Anttila Date: Wed, 26 Aug 2015 15:40:22 +0300 Subject: Remove unused Sidebar code from Grid (#18659) Change-Id: I5476579668c3bf8d05e92862bcd40237bd58b95c --- client/src/com/vaadin/client/widgets/Grid.java | 68 +++----------------------- 1 file changed, 7 insertions(+), 61 deletions(-) diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 8cd97715a8..580d0da72b 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -3494,46 +3494,6 @@ public class Grid extends ResizeComposite implements return content.getParent() == rootContainer; } - /** - * Adds or moves the given widget to the end of the sidebar. - * - * @param widget - * the widget to add or move - */ - public void add(Widget widget) { - content.add(widget); - updateVisibility(); - } - - /** - * Removes the given widget from the sidebar. - * - * @param widget - * the widget to remove - */ - public void remove(Widget widget) { - content.remove(widget); - // updateVisibility is called by remove listener - } - - /** - * Inserts given widget to the given index inside the sidebar. If the - * widget is already in the sidebar, then it is moved to the new index. - *

- * See - * {@link FlowPanel#insert(com.google.gwt.user.client.ui.IsWidget, int)} - * for further details. - * - * @param widget - * the widget to insert - * @param beforeIndex - * 0-based index position for the widget. - */ - public void insert(Widget widget, int beforeIndex) { - content.insert(widget, beforeIndex); - updateVisibility(); - } - @Override public void setStylePrimaryName(String styleName) { super.setStylePrimaryName(styleName); @@ -3968,8 +3928,8 @@ public class Grid extends ResizeComposite implements } private boolean isSidebarOnDraggedRow() { - return eventCell.getRowIndex() == 0 && getSidebar().isInDOM() - && !getSidebar().isOpen(); + return eventCell.getRowIndex() == 0 && sidebar.isInDOM() + && !sidebar.isOpen(); } /** @@ -3979,8 +3939,7 @@ public class Grid extends ResizeComposite implements private double getSidebarBoundaryComparedTo(double left) { if (isSidebarOnDraggedRow()) { double absoluteLeft = left + getElement().getAbsoluteLeft(); - double sidebarLeft = getSidebar().getElement() - .getAbsoluteLeft(); + double sidebarLeft = sidebar.getElement().getAbsoluteLeft(); double diff = absoluteLeft - sidebarLeft; if (diff > 0) { @@ -8104,15 +8063,15 @@ public class Grid extends ResizeComposite implements @Override protected void doAttachChildren() { - if (getSidebar().getParent() == this) { - onAttach(getSidebar()); + if (sidebar.getParent() == this) { + onAttach(sidebar); } } @Override protected void doDetachChildren() { - if (getSidebar().getParent() == this) { - onDetach(getSidebar()); + if (sidebar.getParent() == this) { + onDetach(sidebar); } } @@ -8232,19 +8191,6 @@ public class Grid extends ResizeComposite implements autoColumnWidthsRecalculator.schedule(); } - /** - * Returns the sidebar for this grid. - *

- * The grid's sidebar shows the column hiding options for those columns that - * have been set as {@link Column#setHidable(boolean) hidable}. - * - * @since 7.5.0 - * @return the sidebar widget for this grid - */ - private Sidebar getSidebar() { - return sidebar; - } - /** * Gets the customizable menu bar that is by default used for toggling * column hidability. The application developer is allowed to add their -- cgit v1.2.3 From b6f2bb0ceeb2e903e3c457f480ebd66450597644 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Wed, 26 Aug 2015 16:47:19 +0300 Subject: Fix empty @since tags for 7.6.0.alpha4 Change-Id: I9f223ec2d49a4a851f5e5808cc325c52717191ee --- client/src/com/vaadin/client/ComputedStyle.java | 4 ++-- .../com/vaadin/client/connectors/RpcDataSourceConnector.java | 2 +- .../src/com/vaadin/client/data/AbstractRemoteDataSource.java | 2 +- client/src/com/vaadin/client/widgets/Grid.java | 2 +- server/src/com/vaadin/data/DataGenerator.java | 2 +- server/src/com/vaadin/data/RpcDataProviderExtension.java | 12 ++++++------ .../server/communication/AtmospherePushConnection.java | 2 +- server/src/com/vaadin/ui/Grid.java | 12 ++++++------ shared/src/com/vaadin/shared/data/DataProviderRpc.java | 2 +- shared/src/com/vaadin/shared/data/DataRequestRpc.java | 2 +- 10 files changed, 21 insertions(+), 21 deletions(-) diff --git a/client/src/com/vaadin/client/ComputedStyle.java b/client/src/com/vaadin/client/ComputedStyle.java index 676d18d245..66404eeeed 100644 --- a/client/src/com/vaadin/client/ComputedStyle.java +++ b/client/src/com/vaadin/client/ComputedStyle.java @@ -335,7 +335,7 @@ public class ComputedStyle { /** * Returns the sum of the top and bottom margin * - * @since + * @since 7.6 * @return the sum of the top and bottom margin */ public double getMarginHeight() { @@ -348,7 +348,7 @@ public class ComputedStyle { /** * Returns the sum of the top and bottom margin * - * @since + * @since 7.6 * @return the sum of the left and right margin */ public double getMarginWidth() { diff --git a/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java b/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java index 79838f3252..78aaebaca1 100644 --- a/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java +++ b/client/src/com/vaadin/client/connectors/RpcDataSourceConnector.java @@ -229,7 +229,7 @@ public class RpcDataSourceConnector extends AbstractExtensionConnector { /** * Updates row data based on row key. * - * @since + * @since 7.6 * @param row * new row object */ diff --git a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java index 256bc5ff6a..2438bec8df 100644 --- a/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java +++ b/client/src/com/vaadin/client/data/AbstractRemoteDataSource.java @@ -360,7 +360,7 @@ public abstract class AbstractRemoteDataSource implements DataSource { * dropped from the cache. DataSource no longer has anything in the given * index. * - * @since + * @since 7.6 * @param rowIndex * the index of the dropped row * @param removed diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 580d0da72b..45d14fac30 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -8302,7 +8302,7 @@ public class Grid extends ResizeComposite implements * Returns a CellReference for the cell to which the given element belongs * to. * - * @since + * @since 7.6 * @param element * Element to find from the cell's content. * @return CellReference or null if cell was not found. diff --git a/server/src/com/vaadin/data/DataGenerator.java b/server/src/com/vaadin/data/DataGenerator.java index f025623a3e..a5333b8523 100644 --- a/server/src/com/vaadin/data/DataGenerator.java +++ b/server/src/com/vaadin/data/DataGenerator.java @@ -29,7 +29,7 @@ import elemental.json.JsonObject; * {@link AbstractRenderer} implements this interface to provide encoded data to * client for {@link Renderer}s automatically. * - * @since + * @since 7.6 * @author Vaadin Ltd */ public interface DataGenerator extends Serializable { diff --git a/server/src/com/vaadin/data/RpcDataProviderExtension.java b/server/src/com/vaadin/data/RpcDataProviderExtension.java index 2ec100eba6..f5d712f6b2 100644 --- a/server/src/com/vaadin/data/RpcDataProviderExtension.java +++ b/server/src/com/vaadin/data/RpcDataProviderExtension.java @@ -243,7 +243,7 @@ public class RpcDataProviderExtension extends AbstractExtension { /** * {@inheritDoc} * - * @since + * @since 7.6 */ @Override public void generateData(Object itemId, Item item, JsonObject rowData) { @@ -253,7 +253,7 @@ public class RpcDataProviderExtension extends AbstractExtension { /** * Removes all inactive item id to key mapping from the key mapper. * - * @since + * @since 7.6 */ public void dropInactiveItems() { Collection active = activeItemHandler.getActiveItemIds(); @@ -270,7 +270,7 @@ public class RpcDataProviderExtension extends AbstractExtension { /** * Class for keeping track of current items and ValueChangeListeners. * - * @since + * @since 7.6 */ private class ActiveItemHandler implements Serializable { @@ -545,7 +545,7 @@ public class RpcDataProviderExtension extends AbstractExtension { /** * {@inheritDoc} * - * @since + * @since 7.6 */ @Override public void generateData(Object itemId, Item item, JsonObject rowData) { @@ -823,7 +823,7 @@ public class RpcDataProviderExtension extends AbstractExtension { * DataGenerators are called when sending row data to client. If given * DataGenerator is already added, this method does nothing. * - * @since + * @since 7.6 * @param generator * generator to add */ @@ -836,7 +836,7 @@ public class RpcDataProviderExtension extends AbstractExtension { * {@code RpcDataProviderExtension}. If given DataGenerator is not added to * this data provider, this method does nothing. * - * @since + * @since 7.6 * @param generator * generator to remove */ diff --git a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java index e1bc8e212b..05e4f6479f 100644 --- a/server/src/com/vaadin/server/communication/AtmospherePushConnection.java +++ b/server/src/com/vaadin/server/communication/AtmospherePushConnection.java @@ -359,7 +359,7 @@ public class AtmospherePushConnection implements PushConnection { * Internal method used for reconfiguring loggers to show all Atmosphere log * messages in the console. * - * @since + * @since 7.6 */ public static void enableAtmosphereDebugLogging() { Level level = Level.FINEST; diff --git a/server/src/com/vaadin/ui/Grid.java b/server/src/com/vaadin/ui/Grid.java index c7ad9632fa..cea89d24e8 100644 --- a/server/src/com/vaadin/ui/Grid.java +++ b/server/src/com/vaadin/ui/Grid.java @@ -1574,7 +1574,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, * * @see Grid#setRowDescriptionGenerator(CellDescriptionGenerator) * - * @since + * @since 7.6 */ public interface RowDescriptionGenerator extends Serializable { @@ -1598,7 +1598,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, * * @see Grid#setCellDescriptionGenerator(CellDescriptionGenerator) * - * @since + * @since 7.6 */ public interface CellDescriptionGenerator extends Serializable { @@ -5877,7 +5877,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, * * @see #setRowDescriptionGenerator(RowDescriptionGenerator) * - * @since + * @since 7.6 */ public void setCellDescriptionGenerator(CellDescriptionGenerator generator) { cellDescriptionGenerator = generator; @@ -5891,7 +5891,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, * * @return the description generator or {@code null} if no generator is set * - * @since + * @since 7.6 */ public CellDescriptionGenerator getCellDescriptionGenerator() { return cellDescriptionGenerator; @@ -5911,7 +5911,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, * * @see #setCellDescriptionGenerator(CellDescriptionGenerator) * - * @since + * @since 7.6 */ public void setRowDescriptionGenerator(RowDescriptionGenerator generator) { rowDescriptionGenerator = generator; @@ -5925,7 +5925,7 @@ public class Grid extends AbstractFocusable implements SelectionNotifier, * * @return the description generator or {@code} null if no generator is set * - * @since + * @since 7.6 */ public RowDescriptionGenerator getRowDescriptionGenerator() { return rowDescriptionGenerator; diff --git a/shared/src/com/vaadin/shared/data/DataProviderRpc.java b/shared/src/com/vaadin/shared/data/DataProviderRpc.java index bddbdd113d..28e50d9747 100644 --- a/shared/src/com/vaadin/shared/data/DataProviderRpc.java +++ b/shared/src/com/vaadin/shared/data/DataProviderRpc.java @@ -97,7 +97,7 @@ public interface DataProviderRpc extends ClientRpc { * Informs the client that a row has updated. The client-side DataSource * will map the given data to correct index if it should be in the cache. * - * @since + * @since 7.6 * @param row * the updated row data */ diff --git a/shared/src/com/vaadin/shared/data/DataRequestRpc.java b/shared/src/com/vaadin/shared/data/DataRequestRpc.java index 041e92d05c..b66965fae9 100644 --- a/shared/src/com/vaadin/shared/data/DataRequestRpc.java +++ b/shared/src/com/vaadin/shared/data/DataRequestRpc.java @@ -63,7 +63,7 @@ public interface DataRequestRpc extends ServerRpc { /** * Informs the server that items have been dropped from the client cache. * - * @since + * @since 7.6 * @param rowKeys * array of dropped keys mapping to items */ -- cgit v1.2.3 From 4afe7d033d345abc2dd1140afd09ec848fd460e7 Mon Sep 17 00:00:00 2001 From: Henri Sara Date: Wed, 26 Aug 2015 16:25:48 +0300 Subject: Update menu indices in TabSheetBasicOperations test Change-Id: Ibfead15a5c0a63776fcccea3b3374bfad8736fae --- .../components/tabsheet/TabSheetBasicOperations.html | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/uitest/tb2/com/vaadin/tests/components/tabsheet/TabSheetBasicOperations.html b/uitest/tb2/com/vaadin/tests/components/tabsheet/TabSheetBasicOperations.html index f0f08efb58..92e2e05197 100644 --- a/uitest/tb2/com/vaadin/tests/components/tabsheet/TabSheetBasicOperations.html +++ b/uitest/tb2/com/vaadin/tests/components/tabsheet/TabSheetBasicOperations.html @@ -35,7 +35,7 @@ mouseClick - vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item3 + vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item4 49,10 @@ -60,7 +60,7 @@ mouseClick - vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item3 + vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item4 49,5 @@ -85,7 +85,7 @@ mouseClick - vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item3 + vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item4 74,11 @@ -110,7 +110,7 @@ mouseClick - vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item3 + vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item4 89,4 @@ -252,12 +252,12 @@ mouseClick - vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item4 + vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item3 49,4 mouseClick - vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[1]/VMenuBar[0]#item2 + vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[1]/VMenuBar[0]#item4 80,12 @@ -267,12 +267,12 @@ mouseClick - vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item4 + vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[0]/VMenuBar[0]#item3 67,14 mouseClick - vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[1]/VMenuBar[0]#item3 + vaadin=runcomvaadintestscomponentstabsheetTabSheetTest::Root/VOverlay[1]/VMenuBar[0]#item5 71,9 -- cgit v1.2.3 From c6622ac5cbf4ddbcec35e02f92f74cf46d147e71 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Wed, 19 Aug 2015 13:11:21 +0300 Subject: Make Grid editor event handling more customizable The event handling is factored to a separate EventHandler interface, with the default behavior contained in class DefaultEditorEventHandler. The latter is made easily extensible by providing several customization points. Change-Id: I653d37197cc9314980a8d36983783f227af0cd5e --- .../widget/grid/DefaultEditorEventHandler.java | 225 +++++++++++++++++++++ client/src/com/vaadin/client/widgets/Grid.java | 222 +++++++++++++------- 2 files changed, 371 insertions(+), 76 deletions(-) create mode 100644 client/src/com/vaadin/client/widget/grid/DefaultEditorEventHandler.java diff --git a/client/src/com/vaadin/client/widget/grid/DefaultEditorEventHandler.java b/client/src/com/vaadin/client/widget/grid/DefaultEditorEventHandler.java new file mode 100644 index 0000000000..564b0f1a03 --- /dev/null +++ b/client/src/com/vaadin/client/widget/grid/DefaultEditorEventHandler.java @@ -0,0 +1,225 @@ +/* + * Copyright 2000-2014 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.client.widget.grid; + +import com.google.gwt.core.client.Duration; +import com.google.gwt.event.dom.client.KeyCodes; +import com.google.gwt.user.client.Event; +import com.vaadin.client.WidgetUtil; +import com.vaadin.client.ui.FocusUtil; +import com.vaadin.client.widget.grid.events.EditorMoveEvent; +import com.vaadin.client.widget.grid.events.EditorOpenEvent; +import com.vaadin.client.widgets.Grid.Editor; +import com.vaadin.client.widgets.Grid.EditorDomEvent; + +/** + * The default handler for Grid editor events. Offers several overridable + * protected methods for easier customization. + * + * @since + * @author Vaadin Ltd + */ +public class DefaultEditorEventHandler implements Editor.EventHandler { + + public static final int KEYCODE_OPEN = KeyCodes.KEY_ENTER; + public static final int KEYCODE_MOVE = KeyCodes.KEY_ENTER; + public static final int KEYCODE_CLOSE = KeyCodes.KEY_ESCAPE; + + private double lastTouchEventTime = 0; + private int lastTouchEventX = -1; + private int lastTouchEventY = -1; + private int lastTouchEventRow = -1; + + /** + * Returns whether the given event is a touch event that should open the + * editor. + * + * @param event + * the received event + * @return whether the event is a touch open event + */ + protected boolean isTouchOpenEvent(EditorDomEvent event) { + final Event e = event.getDomEvent(); + final int type = e.getTypeInt(); + + final double now = Duration.currentTimeMillis(); + final int currentX = WidgetUtil.getTouchOrMouseClientX(e); + final int currentY = WidgetUtil.getTouchOrMouseClientY(e); + + final boolean validTouchOpenEvent = type == Event.ONTOUCHEND + && now - lastTouchEventTime < 500 + && lastTouchEventRow == event.getCell().getRowIndex() + && Math.abs(lastTouchEventX - currentX) < 20 + && Math.abs(lastTouchEventY - currentY) < 20; + + if (type == Event.ONTOUCHSTART) { + lastTouchEventX = currentX; + lastTouchEventY = currentY; + } + + if (type == Event.ONTOUCHEND) { + lastTouchEventTime = now; + lastTouchEventRow = event.getCell().getRowIndex(); + } + + return validTouchOpenEvent; + } + + /** + * Returns whether the given event should open the editor. The default + * implementation returns true if and only if the event is a doubleclick or + * if it is a keydown event and the keycode is {@link #KEYCODE_OPEN}. + * + * @param event + * the received event + * @return true if the event is an open event, false otherwise + */ + protected boolean isOpenEvent(EditorDomEvent event) { + final Event e = event.getDomEvent(); + return e.getTypeInt() == Event.ONDBLCLICK + || (e.getTypeInt() == Event.ONKEYDOWN && e.getKeyCode() == KEYCODE_OPEN) + || isTouchOpenEvent(event); + } + + /** + * Opens the editor on the appropriate row if the received event is an open + * event. The default implementation uses + * {@link #isOpenEvent(EditorDomEvent) isOpenEvent}. + * + * @param event + * the received event + * @return true if this method handled the event and nothing else should be + * done, false otherwise + */ + protected boolean handleOpenEvent(EditorDomEvent event) { + if (isOpenEvent(event)) { + final EventCellReference cell = event.getCell(); + + editRow(event, cell.getRowIndex(), cell.getColumnIndexDOM()); + + // FIXME should be in editRow + event.getGrid().fireEvent(new EditorOpenEvent(cell)); + + event.getDomEvent().preventDefault(); + + return true; + } + return false; + } + + /** + * Moves the editor to another row if the received event is a move event. + * The default implementation moves the editor to the clicked row if the + * event is a click; otherwise, if the event is a keydown and the keycode is + * {@link #KEYCODE_MOVE}, moves the editor one row up or down if the shift + * key is pressed or not, respectively. + * + * @param event + * the received event + * @return true if this method handled the event and nothing else should be + * done, false otherwise + */ + protected boolean handleMoveEvent(EditorDomEvent event) { + Event e = event.getDomEvent(); + final EventCellReference cell = event.getCell(); + + // TODO: Move on touch events + if (e.getTypeInt() == Event.ONCLICK) { + + editRow(event, cell.getRowIndex(), cell.getColumnIndexDOM()); + + // FIXME should be in editRow + event.getGrid().fireEvent(new EditorMoveEvent(cell)); + + return true; + } + + else if (e.getTypeInt() == Event.ONKEYDOWN + && e.getKeyCode() == KEYCODE_MOVE) { + + editRow(event, event.getRowIndex() + (e.getShiftKey() ? -1 : +1), + event.getFocusedColumnIndex()); + + // FIXME should be in editRow + event.getGrid().fireEvent(new EditorMoveEvent(cell)); + + return true; + } + + return false; + } + + /** + * Returns whether the given event should close the editor. The default + * implementation returns true if and only if the event is a keydown event + * and the keycode is {@link #KEYCODE_CLOSE}. + * + * @param event + * the received event + * @return true if the event is a close event, false otherwise + */ + protected boolean isCloseEvent(EditorDomEvent event) { + final Event e = event.getDomEvent(); + return e.getTypeInt() == Event.ONKEYDOWN + && e.getKeyCode() == KEYCODE_CLOSE; + } + + /** + * Closes the editor if the received event is a close event. The default + * implementation uses {@link #isCloseEvent(EditorDomEvent) isCloseEvent}. + * + * @param event + * the received event + * @return true if this method handled the event and nothing else should be + * done, false otherwise + */ + protected boolean handleCloseEvent(EditorDomEvent event) { + if (isCloseEvent(event)) { + event.getEditor().cancel(); + FocusUtil.setFocus(event.getGrid(), true); + return true; + } + return false; + } + + protected void editRow(EditorDomEvent event, int rowIndex, int colIndex) { + int rowCount = event.getGrid().getDataSource().size(); + // Limit rowIndex between 0 and rowCount - 1 + rowIndex = Math.max(0, Math.min(rowCount - 1, rowIndex)); + + int colCount = event.getGrid().getVisibleColumns().size(); + // Limit colIndex between 0 and colCount - 1 + colIndex = Math.max(0, Math.min(colCount - 1, colIndex)); + + event.getEditor().editRow(rowIndex, colIndex); + } + + @Override + public boolean handleEvent(EditorDomEvent event) { + final Editor editor = event.getEditor(); + final boolean isBody = event.getCell().isBody(); + + if (event.getGrid().isEditorActive()) { + return (!editor.isBuffered() && isBody && handleMoveEvent(event)) + || handleCloseEvent(event) + // Swallow events if editor is open and buffered (modal) + || editor.isBuffered(); + } else { + return event.getGrid().isEnabled() && isBody + && handleOpenEvent(event); + } + } +} \ No newline at end of file diff --git a/client/src/com/vaadin/client/widgets/Grid.java b/client/src/com/vaadin/client/widgets/Grid.java index 45d14fac30..7250ed76be 100644 --- a/client/src/com/vaadin/client/widgets/Grid.java +++ b/client/src/com/vaadin/client/widgets/Grid.java @@ -31,7 +31,6 @@ import java.util.TreeMap; import java.util.logging.Level; import java.util.logging.Logger; -import com.google.gwt.core.client.Duration; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.core.shared.GWT; @@ -108,6 +107,7 @@ import com.vaadin.client.widget.grid.CellReference; import com.vaadin.client.widget.grid.CellStyleGenerator; import com.vaadin.client.widget.grid.DataAvailableEvent; import com.vaadin.client.widget.grid.DataAvailableHandler; +import com.vaadin.client.widget.grid.DefaultEditorEventHandler; import com.vaadin.client.widget.grid.DetailsGenerator; import com.vaadin.client.widget.grid.EditorHandler; import com.vaadin.client.widget.grid.EditorHandler.EditorRequest; @@ -129,8 +129,6 @@ import com.vaadin.client.widget.grid.events.ColumnVisibilityChangeHandler; import com.vaadin.client.widget.grid.events.EditorCloseEvent; import com.vaadin.client.widget.grid.events.EditorEvent; import com.vaadin.client.widget.grid.events.EditorEventHandler; -import com.vaadin.client.widget.grid.events.EditorMoveEvent; -import com.vaadin.client.widget.grid.events.EditorOpenEvent; import com.vaadin.client.widget.grid.events.FooterClickHandler; import com.vaadin.client.widget.grid.events.FooterDoubleClickHandler; import com.vaadin.client.widget.grid.events.FooterKeyDownHandler; @@ -1126,24 +1124,139 @@ public class Grid extends ResizeComposite implements } } + /** + * A wrapper for native DOM events originating from Grid. In addition to the + * native event, contains a {@link CellReference} instance specifying which + * cell the event originated from. + * + * @since + * @param + * The row type of the grid + */ + public static class GridEvent { + private Event event; + private EventCellReference cell; + + protected GridEvent(Event event, EventCellReference cell) { + this.event = event; + this.cell = cell; + } + + /** + * Returns the wrapped DOM event. + * + * @return the DOM event + */ + public Event getDomEvent() { + return event; + } + + /** + * Returns the Grid cell this event originated from. + * + * @return the event cell + */ + public EventCellReference getCell() { + return cell; + } + + /** + * Returns the Grid instance this event originated from. + * + * @return the grid + */ + public Grid getGrid() { + return cell.getGrid(); + } + } + + /** + * A wrapper for native DOM events related to the {@link Editor Grid editor} + * . + * + * @since + * @param + * the row type of the grid + */ + public static class EditorDomEvent extends GridEvent { + + protected EditorDomEvent(Event event, EventCellReference cell) { + super(event, cell); + } + + /** + * Returns the editor of the Grid this event originated from. + * + * @return the related editor instance + */ + public Editor getEditor() { + return getGrid().getEditor(); + } + + /** + * Returns the row index the editor is open at. If the editor is not + * open, returns -1. + * + * @return the index of the edited row or -1 if editor is not open + */ + public int getRowIndex() { + return getEditor().rowIndex; + } + + /** + * Returns the column index the editor was opened at. If the editor is + * not open, returns -1. + * + * @return the column index or -1 if editor is not open + */ + public int getFocusedColumnIndex() { + return getEditor().focusedColumnIndex; + } + } + /** * An editor UI for Grid rows. A single Grid row at a time can be opened for * editing. + * + * @since + * @param + * the row type of the grid */ - protected static class Editor { - - public static final int KEYCODE_SHOW = KeyCodes.KEY_ENTER; - public static final int KEYCODE_HIDE = KeyCodes.KEY_ESCAPE; + public static class Editor { private static final String ERROR_CLASS_NAME = "error"; private static final String NOT_EDITABLE_CLASS_NAME = "not-editable"; + /** + * A handler for events related to the Grid editor. Responsible for + * opening, moving or closing the editor based on the received event. + * + * @since + * @author Vaadin Ltd + * @param + * the row type of the grid + */ + public interface EventHandler { + /** + * Handles editor-related events in an appropriate way. Opens, + * moves, or closes the editor based on the given event. + * + * @param event + * the received event + * @return true if the event was handled and nothing else should be + * done, false otherwise + */ + boolean handleEvent(EditorDomEvent event); + } + protected enum State { INACTIVE, ACTIVATING, BINDING, ACTIVE, SAVING } private Grid grid; private EditorHandler handler; + private EventHandler eventHandler = GWT + .create(DefaultEditorEventHandler.class); private DivElement editorOverlay = DivElement.as(DOM.createDiv()); private DivElement cellWrapper = DivElement.as(DOM.createDiv()); @@ -1998,6 +2111,27 @@ public class Grid extends ResizeComposite implements messageAndButtonsWrapper.getStyle().setDisplay(Display.NONE); } } + + /** + * Sets the event handler for this Editor. + * + * @since + * @param handler + * the new event handler + */ + public void setEventHandler(EventHandler handler) { + eventHandler = handler; + } + + /** + * Returns the event handler of this Editor. + * + * @since + * @return the current event handler + */ + public EventHandler getEventHandler() { + return eventHandler; + } } public static abstract class AbstractGridKeyEvent @@ -3739,10 +3873,6 @@ public class Grid extends ResizeComposite implements private final AutoColumnWidthsRecalculator autoColumnWidthsRecalculator = new AutoColumnWidthsRecalculator(); private boolean enabled = true; - private double lastTouchEventTime = 0; - private int lastTouchEventX = -1; - private int lastTouchEventY = -1; - private int lastTouchEventRow = -1; private DetailsGenerator detailsGenerator = DetailsGenerator.NULL; private GridSpacerUpdater gridSpacerUpdater = new GridSpacerUpdater(); @@ -5570,8 +5700,8 @@ public class Grid extends ResizeComposite implements if (visibleRows.contains(rowIndex)) { rowElement = escalator.getBody().getRowElement(rowIndex); } else { - rowElement = null; getLogger().warning("Row index was not among visible row range"); + return; } row.set(rowIndex, dataSource.getRow(rowIndex), rowElement); @@ -6114,7 +6244,7 @@ public class Grid extends ResizeComposite implements return footer.isVisible(); } - protected Editor getEditor() { + public Editor getEditor() { return editor; } @@ -6641,7 +6771,7 @@ public class Grid extends ResizeComposite implements eventCell.set(cell, getSectionFromContainer(container)); // Editor can steal focus from Grid and is still handled - if (handleEditorEvent(event, container)) { + if (isEditorEnabled() && handleEditorEvent(event, container)) { return; } @@ -6719,68 +6849,8 @@ public class Grid extends ResizeComposite implements } private boolean handleEditorEvent(Event event, RowContainer container) { - final int type = event.getTypeInt(); - final int key = event.getKeyCode(); - final boolean editorIsActive = editor.getState() != Editor.State.INACTIVE; - - double now = Duration.currentTimeMillis(); - int currentX = WidgetUtil.getTouchOrMouseClientX(event); - int currentY = WidgetUtil.getTouchOrMouseClientY(event); - - final boolean validTouchOpenEvent = type == Event.ONTOUCHEND - && now - lastTouchEventTime < 500 - && lastTouchEventRow == eventCell.getRowIndex() - && Math.abs(lastTouchEventX - currentX) < 20 - && Math.abs(lastTouchEventY - currentY) < 20; - - final boolean openEvent = eventCell.isBody() - && (type == Event.ONDBLCLICK - || (type == Event.ONKEYDOWN && key == Editor.KEYCODE_SHOW) || validTouchOpenEvent); - - if (type == Event.ONTOUCHSTART) { - lastTouchEventX = currentX; - lastTouchEventY = currentY; - } - - if (type == Event.ONTOUCHEND) { - lastTouchEventTime = now; - lastTouchEventRow = eventCell.getRowIndex(); - } - - // TODO: Move on touch events - final boolean moveEvent = eventCell.isBody() && type == Event.ONCLICK; - - final boolean closeEvent = type == Event.ONKEYDOWN - && key == Editor.KEYCODE_HIDE; - - if (!editorIsActive && editor.isEnabled() && openEvent) { - - editor.editRow(eventCell.getRowIndex(), - eventCell.getColumnIndexDOM()); - fireEvent(new EditorOpenEvent(eventCell)); - event.preventDefault(); - - return true; - - } else if (editorIsActive && !editor.isBuffered() && moveEvent) { - - cellFocusHandler.setCellFocus(eventCell); - editor.editRow(eventCell.getRowIndex(), - eventCell.getColumnIndexDOM()); - fireEvent(new EditorMoveEvent(eventCell)); - - return true; - - } else if (editorIsActive && closeEvent) { - - editor.cancel(); - FocusUtil.setFocus(this, true); - - return true; - } - - // Swallow events if editor is open and buffered (modal) - return editor.isBuffered() && editorIsActive; + return getEditor().getEventHandler().handleEvent( + new EditorDomEvent(event, getEventCell())); } private boolean handleRendererEvent(Event event, RowContainer container) { -- cgit v1.2.3 From 1d36db6d112c818a9c75e7cd10eb6b3519119406 Mon Sep 17 00:00:00 2001 From: patrik Date: Thu, 6 Aug 2015 14:08:38 +0300 Subject: Add better keyboard Close Shortcut API for Window (#17383) Change-Id: I29c7d288fe35f6801cf3576ba06751adce821340 --- WebContent/release-notes.html | 5 + client/src/com/vaadin/client/ui/VWindow.java | 13 +- server/src/com/vaadin/event/ShortcutAction.java | 30 ++- server/src/com/vaadin/ui/Window.java | 238 +++++++++++++++++---- .../vaadin/tests/design/DesignFormatterTest.java | 4 +- .../component/button/ButtonDeclarativeTest.java | 2 +- .../component/window/WindowDeclarativeTest.java | 39 +++- .../components/window/WindowCloseShortcuts.java | 199 +++++++++++++++++ 8 files changed, 467 insertions(+), 63 deletions(-) create mode 100644 uitest/src/com/vaadin/tests/components/window/WindowCloseShortcuts.java diff --git a/WebContent/release-notes.html b/WebContent/release-notes.html index b7cdba7887..61511b3002 100644 --- a/WebContent/release-notes.html +++ b/WebContent/release-notes.html @@ -109,6 +109,11 @@

Incompatible or Behavior-altering Changes in @version-minor@