From f743e042f03f2c72d2f71507e475e3d26109024a Mon Sep 17 00:00:00 2001
From: Anthony Guerreiro
Date: Wed, 2 Jul 2014 11:58:34 +0300
Subject: Fix NativeButton clickEvent coordinates in IE11 (#14022)
Two clicks were being triggered for IE11,
the first with coordinates (0,0) and the
second with the correct coordinates.
Change-Id: I6f0feb520710b254eac6542f082a5012de2c5f85
---
client/src/com/vaadin/client/ui/VNativeButton.java | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
(limited to 'client')
diff --git a/client/src/com/vaadin/client/ui/VNativeButton.java b/client/src/com/vaadin/client/ui/VNativeButton.java
index 93d8d958d6..8e0dd2bce1 100644
--- a/client/src/com/vaadin/client/ui/VNativeButton.java
+++ b/client/src/com/vaadin/client/ui/VNativeButton.java
@@ -104,7 +104,9 @@ public class VNativeButton extends Button implements ClickHandler {
}
clickPending = false;
} else if (event.getTypeInt() == Event.ONFOCUS) {
- if (BrowserInfo.get().isIE() && clickPending) {
+ if (BrowserInfo.get().isIE()
+ && BrowserInfo.get().getBrowserMajorVersion() < 11
+ && clickPending) {
/*
* The focus event will mess up IE and IE will not trigger the
* mouse up event (which in turn triggers the click event) until
--
cgit v1.2.3
From 9b19675dffec603bc7e8fe6d973ed4edafaff136 Mon Sep 17 00:00:00 2001
From: Bogdan Udrescu
Date: Tue, 8 Jul 2014 09:58:45 +0300
Subject: Bottom component click scroll up the parent panel in a window
(#12943)
Due to old fix for (#11994) the v-scrollable div of the window would
expand to 110% of its size then immediately back to the original size.
The first action, expanding the v-scrollable to 110% would decrease
the scrollTop value of our panel, while increasing its height. When
the revert back action would set the v-scrollable to its own size,
the panel's scrollTop would remain decreased, causing the scroll bar
to move up, hiding the ~10% at the bottom.
Fixed by calling Util.runWebkitOverflowAutoFix(); instead of changing
the height.
Change-Id: I79eafd1f9500c2e4c10dadbfc7100608c0732e04
---
.../html-tests/BottomComponentScrollsUp.html | 96 +++++++++++++++++++
.../com/vaadin/client/ApplicationConnection.java | 1 -
client/src/com/vaadin/client/Util.java | 18 ++++
client/src/com/vaadin/client/ui/VScrollTable.java | 23 +----
client/src/com/vaadin/client/ui/VWindow.java | 90 ++++++------------
.../com/vaadin/client/ui/table/TableConnector.java | 10 +-
.../window/BottomComponentScrollsUp.java | 103 +++++++++++++++++++++
.../window/BottomComponentScrollsUpTest.java | 71 ++++++++++++++
8 files changed, 323 insertions(+), 89 deletions(-)
create mode 100644 WebContent/html-tests/BottomComponentScrollsUp.html
create mode 100644 uitest/src/com/vaadin/tests/components/window/BottomComponentScrollsUp.java
create mode 100644 uitest/src/com/vaadin/tests/components/window/BottomComponentScrollsUpTest.java
(limited to 'client')
diff --git a/WebContent/html-tests/BottomComponentScrollsUp.html b/WebContent/html-tests/BottomComponentScrollsUp.html
new file mode 100644
index 0000000000..a264b38ba8
--- /dev/null
+++ b/WebContent/html-tests/BottomComponentScrollsUp.html
@@ -0,0 +1,96 @@
+
+
+
+Bottom component scroll when focus - test with plain html to see the default behaviour
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Press me
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java
index 6abcdac487..5fcb2070ec 100644
--- a/client/src/com/vaadin/client/ApplicationConnection.java
+++ b/client/src/com/vaadin/client/ApplicationConnection.java
@@ -66,7 +66,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;
diff --git a/client/src/com/vaadin/client/Util.java b/client/src/com/vaadin/client/Util.java
index f175bbe714..f9243dafe9 100644
--- a/client/src/com/vaadin/client/Util.java
+++ b/client/src/com/vaadin/client/Util.java
@@ -468,6 +468,24 @@ public class Util {
return detectedScrollbarSize;
}
+ /**
+ * Defers the execution of {@link #runWebkitOverflowAutoFix(Element)}
+ *
+ * @since
+ * @param elem
+ * with overflow auto
+ */
+ public static void runWebkitOverflowAutoFixDeferred(final Element elem) {
+ Scheduler.get().scheduleDeferred(new Command() {
+
+ @Override
+ public void execute() {
+ Util.runWebkitOverflowAutoFix(elem);
+ }
+ });
+
+ }
+
/**
* Run workaround for webkits overflow auto issue.
*
diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java
index d88f7426ef..59645aa6d3 100644
--- a/client/src/com/vaadin/client/ui/VScrollTable.java
+++ b/client/src/com/vaadin/client/ui/VScrollTable.java
@@ -2251,13 +2251,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
* Ensures the column alignments are correct at initial loading.
* (child components widths are correct)
*/
- Scheduler.get().scheduleDeferred(new Command() {
-
- @Override
- public void execute() {
- Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement());
- }
- });
+ Util.runWebkitOverflowAutoFixDeferred(scrollBodyPanel.getElement());
hadScrollBars = willHaveScrollbarz;
}
@@ -6720,13 +6714,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
Util.notifyParentOfSizeChange(VScrollTable.this, rendering);
}
}
- Scheduler.get().scheduleDeferred(new Command() {
- @Override
- public void execute() {
- Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement());
- }
- });
+ Util.runWebkitOverflowAutoFixDeferred(scrollBodyPanel.getElement());
forceRealignColumnHeaders();
}
@@ -6863,13 +6852,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
// We must run the fix as a deferred command to prevent it from
// overwriting the scroll position with an outdated value, see
// #7607.
- Scheduler.get().scheduleDeferred(new Command() {
-
- @Override
- public void execute() {
- Util.runWebkitOverflowAutoFix(scrollBodyPanel.getElement());
- }
- });
+ Util.runWebkitOverflowAutoFixDeferred(scrollBodyPanel.getElement());
}
triggerLazyColumnAdjustment(false);
diff --git a/client/src/com/vaadin/client/ui/VWindow.java b/client/src/com/vaadin/client/ui/VWindow.java
index 1cee727bc9..83a0001ad8 100644
--- a/client/src/com/vaadin/client/ui/VWindow.java
+++ b/client/src/com/vaadin/client/ui/VWindow.java
@@ -1,12 +1,12 @@
/*
* 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
@@ -73,7 +73,7 @@ import com.vaadin.shared.ui.window.WindowRole;
/**
* "Sub window" component.
- *
+ *
* @author Vaadin Ltd
*/
public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
@@ -295,7 +295,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/**
* Returns true if this window is the topmost VWindow
- *
+ *
* @return
*/
private boolean isActive() {
@@ -437,7 +437,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
* is prevented.
*
* This message is not visible on the screen.
- *
+ *
* @param topMessage
* String provided when the user navigates with Shift-Tab keys to
* the top of the window
@@ -452,7 +452,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
* key is prevented.
*
* This message is not visible on the screen.
- *
+ *
* @param bottomMessage
* String provided when the user navigates with the Tab key to
* the bottom of the window
@@ -465,7 +465,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
* Gets the message that is provided to users of assistive devices when the
* user reaches the top of the window when leaving a window with the tab key
* is prevented.
- *
+ *
* @return the top message
*/
public String getTabStopTopAssistiveText() {
@@ -476,7 +476,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
* Gets the message that is provided to users of assistive devices when the
* user reaches the bottom of the window when leaving a window with the tab
* key is prevented.
- *
+ *
* @return the bottom message
*/
public String getTabStopBottomAssistiveText() {
@@ -554,41 +554,11 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/*
* Shake up the DOM a bit to make the window shed unnecessary
- * scrollbars and resize correctly afterwards. This resulting code
- * took over a week to summon forth, and involved some pretty hairy
- * black magic. Don't touch it unless you know what you're doing!
- * Fixes ticket #11994
+ * scrollbars and resize correctly afterwards. The version fixing
+ * ticket #11994 which was changing the size to 110% was replaced
+ * with this due to ticket #12943
*/
- Scheduler.get().scheduleFinally(new ScheduledCommand() {
- @Override
- public void execute() {
- final com.google.gwt.dom.client.Element scrollable = contents
- .getFirstChildElement();
-
- // Adjusting the width or height may change the scroll
- // position, so store the current position
- int horizontalScrollPosition = scrollable.getScrollLeft();
- int verticalScrollPosition = scrollable.getScrollTop();
-
- final String oldWidth = scrollable.getStyle().getWidth();
- final String oldHeight = scrollable.getStyle().getHeight();
-
- scrollable.getStyle().setWidth(110, Unit.PCT);
- scrollable.getOffsetWidth();
- scrollable.getStyle().setProperty("width", oldWidth);
-
- scrollable.getStyle().setHeight(110, Unit.PCT);
- scrollable.getOffsetHeight();
- scrollable.getStyle().setProperty("height", oldHeight);
-
- // Restore the scroll position
- scrollable.setScrollLeft(horizontalScrollPosition);
- scrollable.setScrollTop(verticalScrollPosition);
-
- updateContentsSize();
- positionOrSizeUpdated();
- }
- });
+ Util.runWebkitOverflowAutoFix(contents.getFirstChildElement());
}
}
@@ -616,7 +586,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/**
* Sets the closable state of the window. Additionally hides/shows the close
* button according to the new state.
- *
+ *
* @param closable
* true if the window can be closed by the user
*/
@@ -638,7 +608,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
* Returns the closable state of the sub window. If the sub window is
* closable a decoration (typically an X) is shown to the user. By clicking
* on the X the user can close the window.
- *
+ *
* @return true if the sub window is closable
*/
protected boolean isClosable() {
@@ -902,7 +872,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/**
* Setter for the text for assistive devices the window caption is prefixed
* with.
- *
+ *
* @param assistivePrefix
* the assistivePrefix to set
*/
@@ -913,7 +883,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/**
* Getter for the text for assistive devices the window caption is prefixed
* with.
- *
+ *
* @return the assistivePrefix
*/
public String getAssistivePrefix() {
@@ -923,7 +893,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/**
* Setter for the text for assistive devices the window caption is postfixed
* with.
- *
+ *
* @param assistivePostfix
* the assistivePostfix to set
*/
@@ -934,7 +904,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/**
* Getter for the text for assistive devices the window caption is postfixed
* with.
- *
+ *
* @return the assistivePostfix
*/
public String getAssistivePostfix() {
@@ -1086,14 +1056,14 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/**
* TODO check if we need to support this with touch based devices.
- *
+ *
* Checks if the cursor was inside the browser content area when the event
* happened.
- *
+ *
* @param event
* The event to be checked
* @return true, if the cursor is inside the browser content area
- *
+ *
* false, otherwise
*/
private boolean cursorInsideBrowserContentArea(Event event) {
@@ -1382,7 +1352,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
* assistive devices when it is opened.
*
* When the provided array is empty, an existing description is removed.
- *
+ *
* @param connectors
* with the connectors of the widgets to use as description
*/
@@ -1420,7 +1390,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
* Gets the connectors that are used as assistive description. Text
* contained in these connectors will be read by assistive devices when the
* window is opened.
- *
+ *
* @return list of previously set connectors
*/
public List getAssistiveDescription() {
@@ -1429,14 +1399,14 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/**
* Sets the WAI-ARIA role the window.
- *
+ *
* This role defines how an assistive device handles a window. Available
* roles are alertdialog and dialog (@see Roles
* Model).
- *
+ *
* The default role is dialog.
- *
+ *
* @param role
* WAI-ARIA role to set for the window
*/
@@ -1455,7 +1425,7 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
* The value of the parameter doTabStop is stored and used for non-modal
* windows. For modal windows, the handlers are always registered, while
* preserving the stored value.
- *
+ *
* @param doTabStop
* true to prevent leaving the window, false to allow leaving the
* window for non modal windows
@@ -1472,9 +1442,9 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner,
/**
* Adds a Handler for when user moves the window.
- *
+ *
* @since 7.1.9
- *
+ *
* @return {@link HandlerRegistration} used to remove the handler
*/
public HandlerRegistration addMoveHandler(WindowMoveHandler handler) {
diff --git a/client/src/com/vaadin/client/ui/table/TableConnector.java b/client/src/com/vaadin/client/ui/table/TableConnector.java
index 017d1d1024..d37fd36522 100644
--- a/client/src/com/vaadin/client/ui/table/TableConnector.java
+++ b/client/src/com/vaadin/client/ui/table/TableConnector.java
@@ -21,7 +21,6 @@ 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.Style.Position;
-import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.BrowserInfo;
@@ -210,13 +209,8 @@ public class TableConnector extends AbstractHasComponentsConnector implements
// by changing overflows as the length of the contents
// *shouldn't* have changed (unless the number of rows
// or the height of the widget has also changed)
- Scheduler.get().scheduleDeferred(new Command() {
- @Override
- public void execute() {
- Util.runWebkitOverflowAutoFix(getWidget().scrollBodyPanel
- .getElement());
- }
- });
+ Util.runWebkitOverflowAutoFixDeferred(getWidget().scrollBodyPanel
+ .getElement());
}
} else {
getWidget().initializeRows(uidl, rowData);
diff --git a/uitest/src/com/vaadin/tests/components/window/BottomComponentScrollsUp.java b/uitest/src/com/vaadin/tests/components/window/BottomComponentScrollsUp.java
new file mode 100644
index 0000000000..2c5e415408
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/window/BottomComponentScrollsUp.java
@@ -0,0 +1,103 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.List;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Alignment;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+
+/**
+ * Reproducing bug #12943 where an action on a Button or ComboBox placed at the
+ * bottom of a window in a scroll panel, will scroll up the parent panel.
+ *
+ * This was due to the fact that with the state confirmation notification from
+ * the server, the window.setVisible would be call again, and the hack that
+ * solved the scrollbars in a window (#11994) would cause the our bug.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+@SuppressWarnings("serial")
+public class BottomComponentScrollsUp extends AbstractTestUI {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ Button b = new Button("Open window");
+ addComponent(b);
+ b.addClickListener(new ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ openWindow();
+ }
+
+ });
+
+ openWindow();
+ }
+
+ private void openWindow() {
+ Window w = new Window();
+ w.setWidth("300px");
+ w.setHeight("300px");
+ w.center();
+
+ Panel p = createPanel();
+ p.setSizeFull();
+
+ w.setContent(p);
+
+ addWindow(w);
+ }
+
+ private Panel createPanel() {
+ Panel p = new Panel();
+
+ VerticalLayout content = new VerticalLayout();
+ p.setContent(content);
+ content.setHeight("500px");
+
+ List items = new ArrayList();
+ items.add("1");
+ items.add("2");
+ items.add("3");
+
+ Button button = new Button("Press me");
+ content.addComponent(button);
+ content.setComponentAlignment(button, Alignment.BOTTOM_CENTER);
+ return p;
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Interacting with a component at the bottom of scrollable panel within a subwindow scrolls up";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 12943;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/window/BottomComponentScrollsUpTest.java b/uitest/src/com/vaadin/tests/components/window/BottomComponentScrollsUpTest.java
new file mode 100644
index 0000000000..3d0da2677b
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/window/BottomComponentScrollsUpTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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 java.io.IOException;
+
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.Dimension;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.interactions.Actions;
+
+import com.vaadin.testbench.TestBenchElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+/**
+ * Automatic test for fix for #12943.
+ *
+ * While testing without the fix, the test failed on both Chrome and PhantomJS.
+ *
+ * @since
+ * @author Vaadin Ltd
+ */
+public class BottomComponentScrollsUpTest extends MultiBrowserTest {
+
+ @Override
+ public void setup() throws Exception {
+ super.setup();
+
+ openTestURL();
+ }
+
+ @Test
+ public void windowScrollTest() throws IOException, InterruptedException {
+ TestBenchElement panelScrollable = (TestBenchElement) getDriver()
+ .findElement(By.className("v-panel-content"));
+ Dimension panelScrollableSize = panelScrollable.getSize();
+
+ WebElement verticalLayout = panelScrollable.findElement(By
+ .className("v-verticallayout"));
+ Dimension verticalLayoutSize = verticalLayout.getSize();
+
+ panelScrollable.scroll(verticalLayoutSize.height);
+
+ WebElement button = verticalLayout
+ .findElement(By.className("v-button"));
+
+ button.click();
+
+ // Loose the focus from the button.
+ new Actions(getDriver())
+ .moveToElement(panelScrollable, panelScrollableSize.width / 2,
+ panelScrollableSize.height / 2).click().build()
+ .perform();
+
+ compareScreen("window");
+ }
+}
--
cgit v1.2.3
From 28702c006fe124988c03c99eea4e2d609407e47e Mon Sep 17 00:00:00 2001
From: Antti Tanhuanpää
Date: Mon, 30 Jun 2014 17:07:50 +0300
Subject: Add scrollbars to ComboBox suggestion popup if low on screen estate
(#11929)
Change-Id: Idfeb20a385fc68c6527f1947bdbf238d9d4af918
---
client/src/com/vaadin/client/ui/VFilterSelect.java | 381 ++++++++++++++-------
.../client/ui/combobox/ComboBoxConnector.java | 39 ++-
.../src/com/vaadin/client/ui/menubar/MenuBar.java | 108 +++++-
.../components/combobox/ComboBoxOnSmallScreen.java | 76 ++++
.../combobox/ComboBoxOnSmallScreenTest.java | 84 +++++
.../com/vaadin/tests/components/combobox/fi.png | Bin 0 -> 25094 bytes
.../vaadin/tests/components/combobox/fi_small.png | Bin 0 -> 3576 bytes
7 files changed, 552 insertions(+), 136 deletions(-)
create mode 100644 uitest/src/com/vaadin/tests/components/combobox/ComboBoxOnSmallScreen.java
create mode 100644 uitest/src/com/vaadin/tests/components/combobox/ComboBoxOnSmallScreenTest.java
create mode 100644 uitest/src/com/vaadin/tests/components/combobox/fi.png
create mode 100644 uitest/src/com/vaadin/tests/components/combobox/fi_small.png
(limited to 'client')
diff --git a/client/src/com/vaadin/client/ui/VFilterSelect.java b/client/src/com/vaadin/client/ui/VFilterSelect.java
index 7f67c39500..46f90c07fa 100644
--- a/client/src/com/vaadin/client/ui/VFilterSelect.java
+++ b/client/src/com/vaadin/client/ui/VFilterSelect.java
@@ -62,6 +62,7 @@ import com.google.gwt.user.client.ui.Widget;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.ComponentConnector;
+import com.vaadin.client.ComputedStyle;
import com.vaadin.client.ConnectorMap;
import com.vaadin.client.Focusable;
import com.vaadin.client.UIDL;
@@ -252,7 +253,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
/**
* Shows the popup where the user can see the filtered options
- *
+ *
* @param currentSuggestions
* The filtered suggestions
* @param currentPage
@@ -264,10 +265,8 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
final Collection currentSuggestions,
final int currentPage, final int totalSuggestions) {
- if (enableDebug) {
- debug("VFS.SP: showSuggestions(" + currentSuggestions + ", "
- + currentPage + ", " + totalSuggestions + ")");
- }
+ debug("VFS.SP: showSuggestions(" + currentSuggestions + ", "
+ + currentPage + ", " + totalSuggestions + ")");
/*
* We need to defer the opening of the popup so that the parent DOM
@@ -316,8 +315,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
status.setInnerText("");
}
// We don't need to show arrows or statusbar if there is
- // only one
- // page
+ // only one page
if (totalSuggestions <= pageLength || pageLength == 0) {
setPagingEnabled(false);
} else {
@@ -346,7 +344,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
/**
* Should the next page button be visible to the user?
- *
+ *
* @param active
*/
private void setNextButtonActive(boolean active) {
@@ -366,7 +364,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
/**
* Should the previous page button be visible to the user
- *
+ *
* @param active
*/
private void setPrevButtonActive(boolean active) {
@@ -391,18 +389,13 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
*/
public void selectNextItem() {
debug("VFS.SP: selectNextItem()");
- final MenuItem cur = menu.getSelectedItem();
- final int index = 1 + menu.getItems().indexOf(cur);
+
+ final int index = menu.getSelectedIndex() + 1;
if (menu.getItems().size() > index) {
- final MenuItem newSelectedItem = menu.getItems().get(index);
- menu.selectItem(newSelectedItem);
- tb.setText(newSelectedItem.getText());
- tb.setSelectionRange(lastFilter.length(), newSelectedItem
- .getText().length() - lastFilter.length());
-
- } else if (hasNextPage()) {
- selectPopupItemWhenResponseIsReceived = Select.FIRST;
- filterOptions(currentPage + 1, lastFilter);
+ selectItem(menu.getItems().get(index));
+
+ } else {
+ selectNextPage();
}
}
@@ -411,29 +404,61 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
*/
public void selectPrevItem() {
debug("VFS.SP: selectPrevItem()");
- final MenuItem cur = menu.getSelectedItem();
- final int index = -1 + menu.getItems().indexOf(cur);
+
+ final int index = menu.getSelectedIndex() - 1;
if (index > -1) {
- final MenuItem newSelectedItem = menu.getItems().get(index);
- menu.selectItem(newSelectedItem);
- tb.setText(newSelectedItem.getText());
- tb.setSelectionRange(lastFilter.length(), newSelectedItem
- .getText().length() - lastFilter.length());
+ selectItem(menu.getItems().get(index));
+
} else if (index == -1) {
- if (currentPage > 0) {
- selectPopupItemWhenResponseIsReceived = Select.LAST;
- filterOptions(currentPage - 1, lastFilter);
- }
+ selectPrevPage();
+
} else {
- final MenuItem newSelectedItem = menu.getItems().get(
- menu.getItems().size() - 1);
- menu.selectItem(newSelectedItem);
- tb.setText(newSelectedItem.getText());
- tb.setSelectionRange(lastFilter.length(), newSelectedItem
- .getText().length() - lastFilter.length());
+ selectItem(menu.getItems().get(menu.getItems().size() - 1));
}
}
+ /**
+ * Select the first item of the suggestions list popup.
+ *
+ * @since
+ */
+ public void selectFirstItem() {
+ debug("VFS.SP: selectFirstItem()");
+ selectItem(menu.getFirstItem());
+ }
+
+ /**
+ * Select the last item of the suggestions list popup.
+ *
+ * @since
+ */
+ public void selectLastItem() {
+ debug("VFS.SP: selectLastItem()");
+ selectItem(menu.getLastItem());
+ }
+
+ /*
+ * Sets the selected item in the popup menu.
+ */
+ private void selectItem(final MenuItem newSelectedItem) {
+ menu.selectItem(newSelectedItem);
+
+ String text = newSelectedItem != null ? newSelectedItem.getText()
+ : "";
+
+ // Set the icon.
+ FilterSelectSuggestion suggestion = (FilterSelectSuggestion) newSelectedItem
+ .getCommand();
+ setSelectedItemIcon(suggestion.getIconUri());
+
+ // Set the text.
+ tb.setText(text);
+ tb.setSelectionRange(lastFilter.length(), text.length()
+ - lastFilter.length());
+
+ menu.updateKeyboardSelectedItem();
+ }
+
/*
* Using a timer to scroll up or down the pages so when we receive lots
* of consecutive mouse wheel events the pages does not flicker.
@@ -486,17 +511,10 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
}
}
- /*
- * (non-Javadoc)
- *
- * @see
- * com.google.gwt.user.client.ui.Widget#onBrowserEvent(com.google.gwt
- * .user.client.Event)
- */
-
@Override
public void onBrowserEvent(Event event) {
debug("VFS.SP: onBrowserEvent()");
+
if (event.getTypeInt() == Event.ONCLICK) {
final Element target = DOM.eventGetTarget(event);
if (target == up || target == DOM.getChild(up, 0)) {
@@ -504,12 +522,24 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
} else if (target == down || target == DOM.getChild(down, 0)) {
lazyPageScroller.scrollDown();
}
+
} else if (event.getTypeInt() == Event.ONMOUSEWHEEL) {
- int velocity = event.getMouseWheelVelocityY();
- if (velocity > 0) {
- lazyPageScroller.scrollDown();
- } else {
- lazyPageScroller.scrollUp();
+
+ boolean scrollNotActive = !menu.isScrollActive();
+
+ debug("VFS.SP: onBrowserEvent() scrollNotActive: "
+ + scrollNotActive);
+
+ if (scrollNotActive) {
+ int velocity = event.getMouseWheelVelocityY();
+
+ debug("VFS.SP: onBrowserEvent() velocity: " + velocity);
+
+ if (velocity > 0) {
+ lazyPageScroller.scrollDown();
+ } else {
+ lazyPageScroller.scrollUp();
+ }
}
}
@@ -525,7 +555,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
* amount of items are visible at a time and a scrollbar or buttons are
* visible to change page. If paging is turned of then all options are
* rendered into the popup menu.
- *
+ *
* @param paging
* Should the paging be turned on?
*/
@@ -546,32 +576,29 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
isPagingEnabled = paging;
}
- /*
- * (non-Javadoc)
- *
- * @see
- * com.google.gwt.user.client.ui.PopupPanel$PositionCallback#setPosition
- * (int, int)
- */
-
@Override
public void setPosition(int offsetWidth, int offsetHeight) {
- debug("VFS.SP: setPosition()");
+ debug("VFS.SP: setPosition(" + offsetWidth + ", " + offsetHeight
+ + ")");
- int top = -1;
- int left = -1;
+ int top = topPosition;
+ int left = getPopupLeft();
// reset menu size and retrieve its "natural" size
menu.setHeight("");
- if (currentPage > 0) {
+ if (currentPage > 0 && !hasNextPage()) {
// fix height to avoid height change when getting to last page
menu.fixHeightTo(pageLength);
}
- offsetHeight = getOffsetHeight();
+ final int desiredHeight = offsetHeight = getOffsetHeight();
final int desiredWidth = getMainWidth();
+
+ debug("VFS.SP: desired[" + desiredWidth + ", " + desiredHeight
+ + "]");
+
Element menuFirstChild = menu.getElement().getFirstChildElement();
- int naturalMenuWidth = menuFirstChild.getOffsetWidth();
+ final int naturalMenuWidth = menuFirstChild.getOffsetWidth();
if (popupOuterPadding == -1) {
popupOuterPadding = Util.measureHorizontalPaddingAndBorder(
@@ -581,7 +608,6 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
if (naturalMenuWidth < desiredWidth) {
menu.setWidth((desiredWidth - popupOuterPadding) + "px");
menuFirstChild.getStyle().setWidth(100, Unit.PCT);
- naturalMenuWidth = desiredWidth;
}
if (BrowserInfo.get().isIE()) {
@@ -589,48 +615,72 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
* IE requires us to specify the width for the container
* element. Otherwise it will be 100% wide
*/
- int rootWidth = naturalMenuWidth - popupOuterPadding;
+ int rootWidth = Math.max(desiredWidth, naturalMenuWidth)
+ - popupOuterPadding;
getContainerElement().getStyle().setWidth(rootWidth, Unit.PX);
}
- if (offsetHeight + getPopupTop() > Window.getClientHeight()
- + Window.getScrollTop()) {
+ final int vfsHeight = VFilterSelect.this.getOffsetHeight();
+ final int spaceAvailableAbove = top - vfsHeight;
+ final int spaceAvailableBelow = Window.getClientHeight() - top;
+ if (spaceAvailableBelow < offsetHeight
+ && spaceAvailableBelow < spaceAvailableAbove) {
// popup on top of input instead
- top = getPopupTop() - offsetHeight
- - VFilterSelect.this.getOffsetHeight();
+ top -= offsetHeight + vfsHeight;
if (top < 0) {
+ offsetHeight += top;
top = 0;
}
} else {
- top = getPopupTop();
- /*
- * Take popup top margin into account. getPopupTop() returns the
- * top value including the margin but the value we give must not
- * include the margin.
- */
- int topMargin = (top - topPosition);
- top -= topMargin;
+ offsetHeight = Math.min(offsetHeight, spaceAvailableBelow);
}
// fetch real width (mac FF bugs here due GWT popups overflow:auto )
offsetWidth = menuFirstChild.getOffsetWidth();
- if (offsetWidth + getPopupLeft() > Window.getClientWidth()
- + Window.getScrollLeft()) {
+
+ if (offsetHeight < desiredHeight) {
+ int menuHeight = offsetHeight;
+ if (isPagingEnabled) {
+ menuHeight -= up.getOffsetHeight() + down.getOffsetHeight()
+ + status.getOffsetHeight();
+ } else {
+ final ComputedStyle s = new ComputedStyle(menu.getElement());
+ menuHeight -= s.getIntProperty("marginBottom")
+ + s.getIntProperty("marginTop");
+ }
+
+ // If the available page height is really tiny then this will be
+ // negative and an exception will be thrown on setHeight.
+ int menuElementHeight = menu.getItemOffsetHeight();
+ if (menuHeight < menuElementHeight) {
+ menuHeight = menuElementHeight;
+ }
+
+ menu.setHeight(menuHeight + "px");
+
+ final int naturalMenuWidthPlusScrollBar = naturalMenuWidth
+ + Util.getNativeScrollbarSize();
+ if (offsetWidth < naturalMenuWidthPlusScrollBar) {
+ menu.setWidth(naturalMenuWidthPlusScrollBar + "px");
+ }
+ }
+
+ if (offsetWidth + left > Window.getClientWidth()) {
left = VFilterSelect.this.getAbsoluteLeft()
- + VFilterSelect.this.getOffsetWidth()
- + Window.getScrollLeft() - offsetWidth;
+ + VFilterSelect.this.getOffsetWidth() - offsetWidth;
if (left < 0) {
left = 0;
+ menu.setWidth(Window.getClientWidth() + "px");
}
- } else {
- left = getPopupLeft();
}
+
setPopupPosition(left, top);
+ menu.scrollSelectionIntoView();
}
/**
* Was the popup just closed?
- *
+ *
* @return true if popup was just closed
*/
public boolean isJustClosed() {
@@ -659,7 +709,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
/**
* Updates style names in suggestion popup to help theme building.
- *
+ *
* @param uidl
* UIDL for the whole combo box
* @param componentState
@@ -723,23 +773,34 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
super(true);
debug("VFS.SM: constructor()");
addDomHandler(this, LoadEvent.getType());
+
+ setScrollEnabled(true);
}
/**
* Fixes menus height to use same space as full page would use. Needed
- * to avoid height changes when quickly "scrolling" to last page
+ * to avoid height changes when quickly "scrolling" to last page.
+ */
+ public void fixHeightTo(int pageItemsCount) {
+ setHeight(getPreferredHeight(pageItemsCount));
+ }
+
+ /*
+ * Gets the preferred height of the menu including pageItemsCount items.
*/
- public void fixHeightTo(int pagelenth) {
+ String getPreferredHeight(int pageItemsCount) {
if (currentSuggestions.size() > 0) {
- final int pixels = pagelenth * (getOffsetHeight() - 2)
- / currentSuggestions.size();
- setHeight((pixels + 2) + "px");
+ final int pixels = (getPreferredHeight() / currentSuggestions
+ .size()) * pageItemsCount;
+ return pixels + "px";
+ } else {
+ return "";
}
}
/**
* Sets the suggestions rendered in the menu
- *
+ *
* @param suggestions
* The suggestions to be rendered in the menu
*/
@@ -789,6 +850,8 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
client.updateVariable(paintableId, "page", 0, false);
client.updateVariable(paintableId, "selected", new String[] {},
immediate);
+ afterUpdateClientVariables();
+
suggestionPopup.hide();
return;
}
@@ -837,6 +900,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
lastNewItemString = enteredItemValue;
client.updateVariable(paintableId, "newitem",
enteredItemValue, immediate);
+ afterUpdateClientVariables();
}
} else if (item != null
&& !"".equals(lastFilter)
@@ -909,26 +973,75 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
}
- public void selectFirstItem() {
- debug("VFS.SM: selectFirstItem()");
- MenuItem firstItem = getItems().get(0);
- selectItem(firstItem);
- }
-
private MenuItem getKeyboardSelectedItem() {
return keyboardSelectedItem;
}
- public void setKeyboardSelectedItem(MenuItem firstItem) {
- keyboardSelectedItem = firstItem;
+ public void setKeyboardSelectedItem(MenuItem menuItem) {
+ keyboardSelectedItem = menuItem;
+ }
+
+ /**
+ * @deprecated use {@link SuggestionPopup#selectFirstItem()} instead.
+ */
+ @Deprecated
+ public void selectFirstItem() {
+ debug("VFS.SM: selectFirstItem()");
+ MenuItem firstItem = getItems().get(0);
+ selectItem(firstItem);
}
+ /**
+ * @deprecated use {@link SuggestionPopup#selectLastItem()} instead.
+ */
+ @Deprecated
public void selectLastItem() {
debug("VFS.SM: selectLastItem()");
List
- *
+ *
* @param
* The type of the ancestor
* @param parentType
@@ -511,7 +512,7 @@ public abstract class AbstractComponent extends AbstractClientConnector
/**
* Gets the error message for this component.
- *
+ *
* @return ErrorMessage containing the description of the error state of the
* component or null, if the component contains no errors. Extending
* classes should override this method if they support other error
@@ -524,9 +525,9 @@ public abstract class AbstractComponent extends AbstractClientConnector
/**
* Gets the component's error message.
- *
+ *
* @link Terminal.ErrorMessage#ErrorMessage(String, int)
- *
+ *
* @return the component's error message.
*/
public ErrorMessage getComponentError() {
@@ -536,9 +537,9 @@ public abstract class AbstractComponent extends AbstractClientConnector
/**
* Sets the component's error message. The message may contain certain XML
* tags, for more information see
- *
+ *
* @link Component.ErrorMessage#ErrorMessage(String, int)
- *
+ *
* @param componentError
* the new ErrorMessage of the component.
*/
@@ -615,7 +616,7 @@ public abstract class AbstractComponent extends AbstractClientConnector
/**
* Build CSS compatible string representation of height.
- *
+ *
* @return CSS height
*/
private String getCSSHeight() {
@@ -624,7 +625,7 @@ public abstract class AbstractComponent extends AbstractClientConnector
/**
* Build CSS compatible string representation of width.
- *
+ *
* @return CSS width
*/
private String getCSSWidth() {
@@ -634,12 +635,12 @@ public abstract class AbstractComponent extends AbstractClientConnector
/**
* Returns the shared state bean with information to be sent from the server
* to the client.
- *
+ *
* Subclasses should override this method and set any relevant fields of the
* state returned by super.getState().
- *
+ *
* @since 7.0
- *
+ *
* @return updated component shared state
*/
@Override
@@ -730,7 +731,7 @@ public abstract class AbstractComponent extends AbstractClientConnector
/**
* Sets the data object, that can be used for any application specific data.
* The component does not use or modify this data.
- *
+ *
* @param data
* the Application specific data.
* @since 3.1
@@ -741,7 +742,7 @@ public abstract class AbstractComponent extends AbstractClientConnector
/**
* Gets the application specific data. See {@link #setData(Object)}.
- *
+ *
* @return the Application specific data set with setData function.
* @since 3.1
*/
@@ -916,7 +917,7 @@ public abstract class AbstractComponent extends AbstractClientConnector
size = -1;
unit = Unit.PIXELS;
} else {
- String symbol = matcher.group(3);
+ String symbol = matcher.group(2);
unit = Unit.getUnitFromSymbol(symbol);
}
} else {
@@ -951,7 +952,7 @@ public abstract class AbstractComponent extends AbstractClientConnector
/**
* Gets the {@link ActionManager} used to manage the
* {@link ShortcutListener}s added to this {@link Field}.
- *
+ *
* @return the ActionManager in use
*/
protected ActionManager getActionManager() {
@@ -995,7 +996,7 @@ public abstract class AbstractComponent extends AbstractClientConnector
/**
* Determine whether a content component is equal to, or the
* ancestor of this component.
- *
+ *
* @param content
* the potential ancestor element
* @return true if the relationship holds
diff --git a/server/src/com/vaadin/ui/AbstractTextField.java b/server/src/com/vaadin/ui/AbstractTextField.java
index e0318ddf2b..9293d38119 100644
--- a/server/src/com/vaadin/ui/AbstractTextField.java
+++ b/server/src/com/vaadin/ui/AbstractTextField.java
@@ -147,6 +147,18 @@ public abstract class AbstractTextField extends AbstractField implements
try {
+ // Sets the height set by the user when resize the
- *
+ *
* @see com.vaadin.data.Container.Sortable#getSortableContainerPropertyIds()
*/
@@ -4811,7 +4826,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Gets the currently sorted column property ID.
- *
+ *
* @return the Container property id of the currently sorted column.
*/
public Object getSortContainerPropertyId() {
@@ -4820,7 +4835,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Sets the currently sorted column property id.
- *
+ *
* @param propertyId
* the Container property id of the currently sorted column.
*/
@@ -4831,7 +4846,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Internal method to set currently sorted column property id. With doSort
* flag actual sorting may be bypassed.
- *
+ *
* @param propertyId
* @param doSort
*/
@@ -4852,7 +4867,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Is the table currently sorted in ascending order.
- *
+ *
* @return true if ascending, false if descending.
*/
public boolean isSortAscending() {
@@ -4861,7 +4876,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Sets the table in ascending order.
- *
+ *
* @param ascending
* true if ascending, false if
* descending.
@@ -4873,7 +4888,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Internal method to set sort ascending. With doSort flag actual sort can
* be bypassed.
- *
+ *
* @param ascending
* @param doSort
*/
@@ -4891,10 +4906,10 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Is sorting disabled altogether.
- *
+ *
* True iff no sortable columns are given even in the case where data source
* would support this.
- *
+ *
* @return True iff sorting is disabled.
* @deprecated As of 7.0, use {@link #isSortEnabled()} instead
*/
@@ -4905,7 +4920,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Checks if sorting is enabled.
- *
+ *
* @return true if sorting by the user is allowed, false otherwise
*/
public boolean isSortEnabled() {
@@ -4914,7 +4929,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Disables the sorting by the user altogether.
- *
+ *
* @param sortDisabled
* True iff sorting is disabled.
* @deprecated As of 7.0, use {@link #setSortEnabled(boolean)} instead
@@ -4930,7 +4945,7 @@ public class Table extends AbstractSelect implements Action.Container,
* Setting this to false disallows sorting by the user. It is still possible
* to call {@link #sort()}.
*
- *
+ *
* @param sortEnabled
* true to allow the user to sort the table, false to disallow it
*/
@@ -4945,14 +4960,14 @@ public class Table extends AbstractSelect implements Action.Container,
* Used to create "generated columns"; columns that exist only in the Table,
* not in the underlying Container. Implement this interface and pass it to
* Table.addGeneratedColumn along with an id for the column to be generated.
- *
+ *
*/
public interface ColumnGenerator extends Serializable {
/**
* Called by Table when a cell in a generated column needs to be
* generated.
- *
+ *
* @param source
* the source Table
* @param itemId
@@ -4970,7 +4985,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Set cell style generator for Table.
- *
+ *
* @param cellStyleGenerator
* New cell style generator or null to remove generator.
*/
@@ -4984,7 +4999,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Get the current cell style generator.
- *
+ *
*/
public CellStyleGenerator getCellStyleGenerator() {
return cellStyleGenerator;
@@ -5001,7 +5016,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Called by Table when a cell (and row) is painted.
- *
+ *
* @param source
* the source Table
* @param itemId
@@ -5064,7 +5079,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Sets the drag start mode of the Table. Drag start mode controls how Table
* behaves as a drag source.
- *
+ *
* @param newDragMode
*/
public void setDragMode(TableDragMode newDragMode) {
@@ -5083,9 +5098,9 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Concrete implementation of {@link DataBoundTransferable} for data
* transferred from a table.
- *
+ *
* @see {@link DataBoundTransferable}.
- *
+ *
* @since 6.3
*/
public class TableTransferable extends DataBoundTransferable {
@@ -5147,7 +5162,7 @@ public class Table extends AbstractSelect implements Action.Container,
* Note, that on some clients the mode may not be respected. E.g. on touch
* based devices CTRL/SHIFT base selection method is invalid, so touch based
* browsers always use the {@link MultiSelectMode#SIMPLE}.
- *
+ *
* @param mode
* The select mode of the table
*/
@@ -5158,7 +5173,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Returns the select mode in which multi-select is used.
- *
+ *
* @return The multi select mode
*/
public MultiSelectMode getMultiSelectMode() {
@@ -5170,7 +5185,7 @@ public class Table extends AbstractSelect implements Action.Container,
* from server once per drag and drop operation. Developer must override one
* method that decides on which rows the currently dragged data can be
* dropped.
- *
+ *
*
* Initially pretty much no data is sent to client. On first required
* criterion check (per drag request) the client side data structure is
@@ -5287,7 +5302,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Gets the property id of the column which header was pressed
- *
+ *
* @return The column propety id
*/
public Object getPropertyId() {
@@ -5321,7 +5336,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Constructor
- *
+ *
* @param source
* The source of the component
* @param propertyId
@@ -5337,7 +5352,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Gets the property id of the column which header was pressed
- *
+ *
* @return The column propety id
*/
public Object getPropertyId() {
@@ -5353,7 +5368,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Called when a user clicks a header column cell
- *
+ *
* @param event
* The event which contains information about the column and
* the mouse click event
@@ -5369,7 +5384,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Called when a user clicks a footer column cell
- *
+ *
* @param event
* The event which contains information about the column and
* the mouse click event
@@ -5384,7 +5399,7 @@ public class Table extends AbstractSelect implements Action.Container,
* The listener will receive events which contain information about which
* column was clicked and some details about the mouse event.
*
- *
+ *
* @param listener
* The handler which should handle the header click events.
*/
@@ -5405,7 +5420,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Removes a header click listener
- *
+ *
* @param listener
* The listener to remove.
*/
@@ -5430,7 +5445,7 @@ public class Table extends AbstractSelect implements Action.Container,
* The listener will receive events which contain information about which
* column was clicked and some details about the mouse event.
*
- *
+ *
* @param listener
* The handler which should handle the footer click events.
*/
@@ -5451,7 +5466,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Removes a footer click listener
- *
+ *
* @param listener
* The listener to remove.
*/
@@ -5471,7 +5486,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Gets the footer caption beneath the rows
- *
+ *
* @param propertyId
* The propertyId of the column *
* @return The caption of the footer or NULL if not set
@@ -5483,10 +5498,10 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Sets the column footer caption. The column footer caption is the text
* displayed beneath the column if footers have been set visible.
- *
+ *
* @param propertyId
* The properyId of the column
- *
+ *
* @param footer
* The caption of the footer
*/
@@ -5506,7 +5521,7 @@ public class Table extends AbstractSelect implements Action.Container,
* The footer can be used to add column related data like sums to the bottom
* of the Table using setColumnFooter(Object propertyId, String footer).
*
- *
+ *
* @param visible
* Should the footer be visible
*/
@@ -5519,7 +5534,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Is the footer currently visible?
- *
+ *
* @return Returns true if visible else false
*/
public boolean isFooterVisible() {
@@ -5551,7 +5566,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Constructor
- *
+ *
* @param source
* The source of the event
* @param propertyId
@@ -5571,7 +5586,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Get the column property id of the column that was resized.
- *
+ *
* @return The column property id
*/
public Object getPropertyId() {
@@ -5580,7 +5595,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Get the width in pixels of the column before the resize event
- *
+ *
* @return Width in pixels
*/
public int getPreviousWidth() {
@@ -5589,7 +5604,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Get the width in pixels of the column after the resize event
- *
+ *
* @return Width in pixels
*/
public int getCurrentWidth() {
@@ -5604,7 +5619,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* This method is triggered when the column has been resized
- *
+ *
* @param event
* The event which contains the column property id, the
* previous width of the column and the current width of the
@@ -5616,7 +5631,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Adds a column resize listener to the Table. A column resize listener is
* called when a user resizes a columns width.
- *
+ *
* @param listener
* The listener to attach to the Table
*/
@@ -5637,7 +5652,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Removes a column resize listener from the Table.
- *
+ *
* @param listener
* The listener to remove
*/
@@ -5674,7 +5689,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Constructor
- *
+ *
* @param source
* The source of the event
*/
@@ -5691,7 +5706,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* This method is triggered when the column has been reordered
- *
+ *
* @param event
*/
public void columnReorder(ColumnReorderEvent event);
@@ -5700,7 +5715,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Adds a column reorder listener to the Table. A column reorder listener is
* called when a user reorders columns.
- *
+ *
* @param listener
* The listener to attach to the Table
*/
@@ -5720,7 +5735,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Removes a column reorder listener from the Table.
- *
+ *
* @param listener
* The listener to remove
*/
@@ -5741,7 +5756,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Set the item description generator which generates tooltips for cells and
* rows in the Table
- *
+ *
* @param generator
* The generator to use or null to disable
*/
@@ -5766,7 +5781,7 @@ public class Table extends AbstractSelect implements Action.Container,
* Row generators can be used to replace certain items in a table with a
* generated string. The generator is called each time the table is
* rendered, which means that new strings can be generated each time.
- *
+ *
* Row generators can be used for e.g. summary rows or grouping of items.
*/
public interface RowGenerator extends Serializable {
@@ -5792,7 +5807,7 @@ public class Table extends AbstractSelect implements Action.Container,
* For custom styling of a generated row you can combine a RowGenerator
* with a CellStyleGenerator.
*
- *
+ *
* @param table
* The Table that is being painted
* @param itemId
@@ -5811,7 +5826,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Creates a new generated row. If only one string is passed in, columns
* are automatically spanned.
- *
+ *
* @param text
*/
public GeneratedRow(String... text) {
@@ -5846,7 +5861,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* If set to true, all strings passed to {@link #setText(String...)}
* will be rendered as HTML.
- *
+ *
* @param htmlContentAllowed
*/
public void setHtmlContentAllowed(boolean htmlContentAllowed) {
@@ -5860,7 +5875,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* If set to true, only one string will be rendered, spanning the entire
* row.
- *
+ *
* @param spanColumns
*/
public void setSpanColumns(boolean spanColumns) {
@@ -5871,7 +5886,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Assigns a row generator to the table. The row generator will be able to
* replace rows in the table when it is rendered.
- *
+ *
* @param generator
* the new row generator
*/
@@ -5893,7 +5908,7 @@ public class Table extends AbstractSelect implements Action.Container,
* The converter is used to format the the data for the given property id
* before displaying it in the table.
*
- *
+ *
* @param propertyId
* The propertyId to format using the converter
* @param converter
@@ -5918,7 +5933,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Checks if there is a converter set explicitly for the given property id.
- *
+ *
* @param propertyId
* The propertyId to check
* @return true if a converter has been set for the property id, false
@@ -5930,7 +5945,7 @@ public class Table extends AbstractSelect implements Action.Container,
/**
* Returns the converter used to format the given propertyId.
- *
+ *
* @param propertyId
* The propertyId to check
* @return The converter used to format the propertyId or null if no
diff --git a/uitest/src/com/vaadin/tests/components/table/TableScrollAfterAddRow.java b/uitest/src/com/vaadin/tests/components/table/TableScrollAfterAddRow.java
new file mode 100644
index 0000000000..d1d6edaa67
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/table/TableScrollAfterAddRow.java
@@ -0,0 +1,167 @@
+/*
+ * 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;
+
+/**
+ *
+ * @author Vaadin Ltd
+ */
+import com.vaadin.data.Item;
+import com.vaadin.data.util.IndexedContainer;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.NativeButton;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.VerticalLayout;
+
+/*
+ * 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.
+ */
+
+/**
+ *
+ * @author Vaadin Ltd
+ */
+@SuppressWarnings("serial")
+public class TableScrollAfterAddRow extends AbstractTestUI {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.ui.UI#init(com.vaadin.server.VaadinRequest)
+ */
+ @Override
+ protected void setup(VaadinRequest request) {
+
+ final int totalRows = 100;
+
+ final VerticalLayout layout = new VerticalLayout();
+
+ final IndexedContainer datasource = new IndexedContainer();
+
+ datasource.addContainerProperty("value", Integer.class, -1);
+ for (int i = 0; i < totalRows; i++) {
+ addRow(datasource);
+ }
+
+ final Table table = new Table();
+ table.setContainerDataSource(datasource);
+ layout.addComponent(table);
+ addComponent(layout);
+
+ final Label label = new Label("");
+ layout.addComponent(label);
+
+ NativeButton addRowButton = new NativeButton("Add row",
+ new NativeButton.ClickListener() {
+
+ @Override
+ public void buttonClick(ClickEvent event) {
+ addRow(datasource);
+ }
+ });
+
+ NativeButton jumpToLastRowButton = new NativeButton("Jump to last row",
+ new NativeButton.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ jumpToLastRow(table);
+ }
+ });
+ NativeButton jumpTo15thRowButton = new NativeButton("Jump to 15th row",
+ new NativeButton.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ jumpToFifteenthRow(table);
+ }
+ });
+ NativeButton jumpToFirstRowButton = new NativeButton(
+ "Jump to first row", new NativeButton.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ jumpToFirstRow(table);
+ }
+ });
+
+ NativeButton updateLabelButton = new NativeButton("UpdateLabel",
+ new NativeButton.ClickListener() {
+ @Override
+ public void buttonClick(ClickEvent event) {
+ label.setValue(Integer.toString(table
+ .getCurrentPageFirstItemIndex()));
+ }
+ });
+ layout.addComponent(addRowButton);
+ layout.addComponent(jumpToLastRowButton);
+ layout.addComponent(jumpTo15thRowButton);
+ layout.addComponent(jumpToFirstRowButton);
+ layout.addComponent(updateLabelButton);
+ }
+
+ private void jumpToFifteenthRow(Table table) {
+ table.setCurrentPageFirstItemIndex(14);
+ }
+
+ private void jumpToLastRow(Table table) {
+ int visibleRows = table.getContainerDataSource().size();
+ table.setCurrentPageFirstItemIndex(visibleRows - 1);
+ }
+
+ private void jumpToFirstRow(Table table) {
+ table.setCurrentPageFirstItemIndex(0);
+ }
+
+ private void addRow(IndexedContainer datasource) {
+ int rowNumber = datasource.size();
+ Item row = datasource.addItem(rowNumber);
+ row.getItemProperty("value").setValue(rowNumber);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription()
+ */
+ @Override
+ protected String getTestDescription() {
+ // TODO Auto-generated method stub
+ return "";
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber()
+ */
+ @Override
+ protected Integer getTicketNumber() {
+ return 14147;
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/table/TableScrollAfterAddRowTest.java b/uitest/src/com/vaadin/tests/components/table/TableScrollAfterAddRowTest.java
new file mode 100644
index 0000000000..9242bae3d8
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/table/TableScrollAfterAddRowTest.java
@@ -0,0 +1,105 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+
+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.WebElement;
+
+import com.vaadin.testbench.commands.TestBenchCommandExecutor;
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.testbench.elements.LabelElement;
+import com.vaadin.testbench.screenshot.ImageComparison;
+import com.vaadin.testbench.screenshot.ReferenceNameGenerator;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+/**
+ *
+ * @author Vaadin Ltd
+ */
+public class TableScrollAfterAddRowTest extends MultiBrowserTest {
+
+ @Before
+ public void init() {
+ openTestURL();
+ }
+
+ @Test
+ public void testJumpToFirstRow() throws InterruptedException {
+ jumpToFifteenthRow();
+ jumpToFirstRow();
+ assertEquals("0", getCurrentPageFirstItemIndex());
+ }
+
+ @Test
+ public void testAddRowAfterJumpToLastRow() throws InterruptedException {
+ jumpToLastRow();
+ addRow();
+ sleep(200);
+ assertEquals("85", getCurrentPageFirstItemIndex());
+ }
+
+ @Test
+ public void testAddRowAfterJumpingToLastRowAndScrollingUp()
+ throws InterruptedException {
+ jumpToLastRow();
+ scrollUp();
+ addRow();
+ sleep(200);
+ Assert.assertNotEquals("86", getCurrentPageFirstItemIndex());
+ }
+
+ private void scrollUp() {
+ WebElement actualElement = getDriver().findElement(
+ By.className("v-table-body-wrapper"));
+ JavascriptExecutor js = new TestBenchCommandExecutor(getDriver(),
+ new ImageComparison(), new ReferenceNameGenerator());
+ js.executeScript("arguments[0].scrollTop = " + 30, actualElement);
+ }
+
+ private String getCurrentPageFirstItemIndex() throws InterruptedException {
+ ButtonElement updateLabelButton = $(ButtonElement.class).get(4);
+ LabelElement label = $(LabelElement.class).get(1);
+ updateLabelButton.click();
+ sleep(200);
+ return label.getText();
+ }
+
+ private void addRow() {
+ ButtonElement button = $(ButtonElement.class).get(0);
+ button.click();
+ }
+
+ private void jumpToFirstRow() {
+ ButtonElement button = $(ButtonElement.class).get(3);
+ button.click();
+ }
+
+ private void jumpToFifteenthRow() {
+ ButtonElement button = $(ButtonElement.class).get(2);
+ button.click();
+ }
+
+ private void jumpToLastRow() {
+ ButtonElement button = $(ButtonElement.class).get(1);
+ button.click();
+ }
+}
--
cgit v1.2.3
From 54707a7219d39e4b60d7cccac3d0f613dc4f1824 Mon Sep 17 00:00:00 2001
From: Dmitrii Rogozin
Date: Tue, 5 Aug 2014 12:36:37 +0300
Subject: Add method for widgets to tell there is work to be done (#13565)
Change-Id: I4b961443f6c175aaf2e2272f1257670fe6bc9607
---
.../com/vaadin/client/ApplicationConnection.java | 39 ++++++++++++++++++++--
client/src/com/vaadin/client/DeferredWorker.java | 30 +++++++++++++++++
client/src/com/vaadin/client/ui/VScrollTable.java | 11 +++++-
3 files changed, 77 insertions(+), 3 deletions(-)
create mode 100644 client/src/com/vaadin/client/DeferredWorker.java
(limited to 'client')
diff --git a/client/src/com/vaadin/client/ApplicationConnection.java b/client/src/com/vaadin/client/ApplicationConnection.java
index 6e2c6e757c..90aa0a14d6 100644
--- a/client/src/com/vaadin/client/ApplicationConnection.java
+++ b/client/src/com/vaadin/client/ApplicationConnection.java
@@ -598,14 +598,23 @@ public class ApplicationConnection implements HasHandlers {
}
}
+ /**
+ * Checks if there is some work to be done on the client side
+ *
+ * @return true if the client has some work to be done, false otherwise
+ */
+ private boolean isActive() {
+ return isWorkPending() || hasActiveRequest()
+ || isExecutingDeferredCommands();
+ }
+
private native void initializeTestbenchHooks(
ComponentLocator componentLocator, String TTAppId)
/*-{
var ap = this;
var client = {};
client.isActive = $entry(function() {
- return ap.@com.vaadin.client.ApplicationConnection::hasActiveRequest()()
- || ap.@com.vaadin.client.ApplicationConnection::isExecutingDeferredCommands()();
+ return ap.@com.vaadin.client.ApplicationConnection::isActive()();
});
var vi = ap.@com.vaadin.client.ApplicationConnection::getVersionInfo()();
if (vi) {
@@ -1319,6 +1328,30 @@ public class ApplicationConnection implements HasHandlers {
}
}
+ /**
+ * Checks if the client has running or scheduled commands
+ */
+ private boolean isWorkPending() {
+ ConnectorMap connectorMap = getConnectorMap();
+ JsArrayObject connectors = connectorMap
+ .getConnectorsAsJsArray();
+ int size = connectors.size();
+ for (int i = 0; i < size; i++) {
+ ServerConnector conn = connectors.get(i);
+ ComponentConnector compConn = null;
+ if (conn instanceof ComponentConnector) {
+ compConn = (ComponentConnector) conn;
+ Widget wgt = compConn.getWidget();
+ if (wgt instanceof DeferredWorker) {
+ if (((DeferredWorker) wgt).isWorkPending()) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
/**
* Checks if deferred commands are (potentially) still being executed as a
* result of an update from the server. Returns true if a deferred command
@@ -1483,6 +1516,7 @@ public class ApplicationConnection implements HasHandlers {
if (json.containsKey("typeMappings")) {
configuration.addComponentMappings(
json.getValueMap("typeMappings"), widgetSet);
+
}
VConsole.log("Handling resource dependencies");
@@ -1717,6 +1751,7 @@ public class ApplicationConnection implements HasHandlers {
for (int i = 0; i < needsUpdateLength; i++) {
String childId = dump.get(i);
ServerConnector child = connectorMap.getConnector(childId);
+
if (child instanceof ComponentConnector
&& ((ComponentConnector) child)
.delegateCaptionHandling()) {
diff --git a/client/src/com/vaadin/client/DeferredWorker.java b/client/src/com/vaadin/client/DeferredWorker.java
new file mode 100644
index 0000000000..53f7c79fe6
--- /dev/null
+++ b/client/src/com/vaadin/client/DeferredWorker.java
@@ -0,0 +1,30 @@
+/*
+ * 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;
+
+/**
+ * Give widgets the possibility to indicate to the framework that there is work
+ * scheduled to be executed in the near future and that the framework should
+ * wait for this work to complete before assuming the UI has reached a steady
+ * state.
+ */
+public interface DeferredWorker {
+ /**
+ * @returns true, if there are operations pending which must be executed
+ * before reaching a steady state
+ */
+ public boolean isWorkPending();
+}
diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java
index 8c1a92830d..6a2a753d0e 100644
--- a/client/src/com/vaadin/client/ui/VScrollTable.java
+++ b/client/src/com/vaadin/client/ui/VScrollTable.java
@@ -80,6 +80,7 @@ import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.ConnectorMap;
+import com.vaadin.client.DeferredWorker;
import com.vaadin.client.Focusable;
import com.vaadin.client.MouseEventDetailsBuilder;
import com.vaadin.client.StyleConstants;
@@ -126,7 +127,7 @@ import com.vaadin.shared.ui.table.TableConstants;
*/
public class VScrollTable extends FlowPanel implements HasWidgets,
ScrollHandler, VHasDropHandler, FocusHandler, BlurHandler, Focusable,
- ActionOwner, SubPartAware {
+ ActionOwner, SubPartAware, DeferredWorker {
public static final String STYLENAME = "v-table";
@@ -7924,4 +7925,12 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
addCloseHandler.removeHandler();
}
}
+
+ /*
+ * Return true if component need to perform some work and false otherwise.
+ */
+ @Override
+ public boolean isWorkPending() {
+ return lazyAdjustColumnWidths.isRunning();
+ }
}
--
cgit v1.2.3
From 97d80510edf06d954c7589864e707d89d60b3e97 Mon Sep 17 00:00:00 2001
From: Anthony Guerreiro
Date: Wed, 9 Jul 2014 16:48:28 +0300
Subject: Fix table.setCurrentPageFirstItemIndex(n) to load only needed rows
(#14135)
Change-Id: I0186ce32f915b39a012bb653e501b0cad72a9f32
---
client/src/com/vaadin/client/ui/VScrollTable.java | 37 ++++++-
.../table/SetPageFirstItemLoadsNeededRowsOnly.java | 109 +++++++++++++++++++++
.../SetPageFirstItemLoadsNeededRowsOnlyTest.java | 58 +++++++++++
3 files changed, 202 insertions(+), 2 deletions(-)
create mode 100644 uitest/src/com/vaadin/tests/components/table/SetPageFirstItemLoadsNeededRowsOnly.java
create mode 100644 uitest/src/com/vaadin/tests/components/table/SetPageFirstItemLoadsNeededRowsOnlyTest.java
(limited to 'client')
diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java
index 6a2a753d0e..6a1e8664ed 100644
--- a/client/src/com/vaadin/client/ui/VScrollTable.java
+++ b/client/src/com/vaadin/client/ui/VScrollTable.java
@@ -196,6 +196,8 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
/** For internal use only. May be removed or replaced in the future. */
public boolean immediate;
+ private boolean updatedReqRows = true;
+
private boolean nullSelectionAllowed = true;
private SelectMode selectMode = SelectMode.NONE;
@@ -2393,10 +2395,32 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
// if client connection is busy, don't bother loading it more
VConsole.log("Postponed rowfetch");
schedule(250);
+ } else if (!updatedReqRows && allRenderedRowsAreNew()) {
+
+ /*
+ * If all rows are new, there might have been a server-side call
+ * to Table.setCurrentPageFirstItemIndex(int) In this case,
+ * scrolling event takes way too late, and all the rows from
+ * previous viewport to this one were requested.
+ *
+ * This should prevent requesting unneeded rows by updating
+ * reqFirstRow and reqRows before needing them. See (#14135)
+ */
+
+ setReqFirstRow((firstRowInViewPort - (int) (pageLength * cache_rate)));
+ int last = firstRowInViewPort + (int) (cache_rate * pageLength)
+ + pageLength - 1;
+ if (last >= totalRows) {
+ last = totalRows - 1;
+ }
+ setReqRows(last - getReqFirstRow() + 1);
+ updatedReqRows = true;
+ schedule(250);
} else {
int firstRendered = scrollBody.getFirstRendered();
int lastRendered = scrollBody.getLastRendered();
+
if (lastRendered > totalRows) {
lastRendered = totalRows - 1;
}
@@ -6267,6 +6291,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
public Widget getWidgetForPaintable() {
return this;
}
+
}
protected class VScrollTableGeneratedRow extends VScrollTableRow {
@@ -6998,8 +7023,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
return;
}
- if (firstRowInViewPort - pageLength * cache_rate > lastRendered
- || firstRowInViewPort + pageLength + pageLength * cache_rate < firstRendered) {
+ if (allRenderedRowsAreNew()) {
// need a totally new set of rows
rowRequestHandler
.setReqFirstRow((firstRowInViewPort - (int) (pageLength * cache_rate)));
@@ -7010,6 +7034,7 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
rowRequestHandler.setReqRows(last
- rowRequestHandler.getReqFirstRow() + 1);
+ updatedReqRows = false;
rowRequestHandler.deferRowFetch();
return;
}
@@ -7032,6 +7057,14 @@ public class VScrollTable extends FlowPanel implements HasWidgets,
}
}
+ private boolean allRenderedRowsAreNew() {
+ int firstRowInViewPort = calcFirstRowInViewPort();
+ int firstRendered = scrollBody.getFirstRendered();
+ int lastRendered = scrollBody.getLastRendered();
+ return (firstRowInViewPort - pageLength * cache_rate > lastRendered || firstRowInViewPort
+ + pageLength + pageLength * cache_rate < firstRendered);
+ }
+
protected int calcFirstRowInViewPort() {
return (int) Math.ceil(scrollTop / scrollBody.getRowHeight());
}
diff --git a/uitest/src/com/vaadin/tests/components/table/SetPageFirstItemLoadsNeededRowsOnly.java b/uitest/src/com/vaadin/tests/components/table/SetPageFirstItemLoadsNeededRowsOnly.java
new file mode 100644
index 0000000000..e643ef5fa0
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/table/SetPageFirstItemLoadsNeededRowsOnly.java
@@ -0,0 +1,109 @@
+/*
+ * 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.Serializable;
+import java.util.List;
+
+import com.vaadin.data.util.BeanContainer;
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Table;
+import com.vaadin.ui.VerticalLayout;
+
+/**
+ *
+ * @author Vaadin Ltd
+ */
+
+@SuppressWarnings("serial")
+public class SetPageFirstItemLoadsNeededRowsOnly extends AbstractTestUI {
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.tests.components.AbstractTestUI#setup(com.vaadin.server.
+ * VaadinRequest)
+ */
+ @Override
+ protected void setup(VaadinRequest request) {
+ final VerticalLayout layout = new VerticalLayout();
+ addComponent(layout);
+
+ final Label label = new Label("");
+ addComponent(label);
+
+ BeanContainer beans = new BeanContainer(
+ Bean.class) {
+ @Override
+ public List getItemIds(int startIndex, int numberOfIds) {
+ label.setValue("rows requested: " + numberOfIds);
+ return super.getItemIds(startIndex, numberOfIds);
+ }
+ };
+
+ beans.setBeanIdProperty("i");
+ for (int i = 0; i < 2000; i++) {
+ beans.addBean(new Bean(i));
+ }
+
+ final Table table = new Table("Beans", beans);
+ table.setVisibleColumns(new Object[] { "i" });
+ layout.addComponent(table);
+
+ table.setCurrentPageFirstItemIndex(table.size() - 1);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.tests.components.AbstractTestUI#getTestDescription()
+ */
+ @Override
+ protected String getTestDescription() {
+ return "Only cached rows and rows in viewport should be rendered after "
+ + "calling table.setCurrentPageFirstItemIndex(n) - as opposed to all rows "
+ + "between the previous position and new position";
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.tests.components.AbstractTestUI#getTicketNumber()
+ */
+ @Override
+ protected Integer getTicketNumber() {
+ return 14135;
+ }
+
+ public class Bean implements Serializable {
+
+ private Integer i;
+
+ public Bean(Integer i) {
+ this.i = i;
+ }
+
+ public Integer getI() {
+ return i;
+ }
+
+ public void setI(Integer i) {
+ this.i = i;
+ }
+ }
+}
diff --git a/uitest/src/com/vaadin/tests/components/table/SetPageFirstItemLoadsNeededRowsOnlyTest.java b/uitest/src/com/vaadin/tests/components/table/SetPageFirstItemLoadsNeededRowsOnlyTest.java
new file mode 100644
index 0000000000..ebf53e9a6d
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/table/SetPageFirstItemLoadsNeededRowsOnlyTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+import com.vaadin.testbench.elements.LabelElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+/**
+ *
+ * @author Vaadin Ltd
+ */
+public class SetPageFirstItemLoadsNeededRowsOnlyTest extends MultiBrowserTest {
+
+ /*
+ * expectedRowsRequested is related to VScrollTable's cache_rate and
+ * pageLength. See for instance VScrollTable.ensureCacheFilled().
+ *
+ * This also takes into account if the visible rows are at the very start or
+ * end of the table, if the user scrolled or the
+ * Table.setCurrentPageFirstItemIndex(int) method was used.
+ *
+ * This value should not change if cache_rate and pageLength are not changed
+ * as well, and if this test remains constant: the table is scrolled to the
+ * very end (done in the actual UI: SetPageFirstItemLoadsNeededRowsOnly).
+ */
+ private int expectedRowsRequested = 45;
+
+ @Test
+ public void verifyLoadedRows() throws InterruptedException {
+
+ openTestURL();
+
+ // wait for events to be processed in UI after loading page
+ sleep(2000);
+
+ String labelValue = $(LabelElement.class).get(1).getText();
+ String expectedLabelValue = "rows requested: " + expectedRowsRequested;
+ String errorMessage = "Too many rows were requested";
+ assertEquals(errorMessage, expectedLabelValue, labelValue);
+ }
+}
--
cgit v1.2.3
From f45932b91bff06c33bfde64d6f86ebe888ea29fe Mon Sep 17 00:00:00 2001
From: Mika Murtojarvi
Date: Wed, 6 Aug 2014 19:22:30 +0300
Subject: Fix the closing of a popup DateField (#14086, #14375).
The popup is made non-modal.
Change-Id: Ia396ff1e2e88639b97c9f556d7d3866f76755436
---
.../src/com/vaadin/client/ui/VPopupCalendar.java | 2 +-
.../tests/components/datefield/DateFieldClose.java | 43 ++++++++++++++
.../components/datefield/DateFieldCloseTest.java | 66 ++++++++++++++++++++++
3 files changed, 110 insertions(+), 1 deletion(-)
create mode 100644 uitest/src/com/vaadin/tests/components/datefield/DateFieldClose.java
create mode 100644 uitest/src/com/vaadin/tests/components/datefield/DateFieldCloseTest.java
(limited to 'client')
diff --git a/client/src/com/vaadin/client/ui/VPopupCalendar.java b/client/src/com/vaadin/client/ui/VPopupCalendar.java
index 7dea959bb4..1474ad3b71 100644
--- a/client/src/com/vaadin/client/ui/VPopupCalendar.java
+++ b/client/src/com/vaadin/client/ui/VPopupCalendar.java
@@ -145,7 +145,7 @@ public class VPopupCalendar extends VTextualDate implements Field,
}
});
- popup = new VOverlay(true, true, true);
+ popup = new VOverlay(true, false, true);
popup.setOwner(this);
FlowPanel wrapper = new FlowPanel();
diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldClose.java b/uitest/src/com/vaadin/tests/components/datefield/DateFieldClose.java
new file mode 100644
index 0000000000..9ce190a293
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldClose.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.datefield;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.DateField;
+
+public class DateFieldClose extends AbstractTestUI {
+
+ static final String DATEFIELD_ID = "datefield";
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ final DateField df = new DateField();
+ df.setId(DATEFIELD_ID);
+ addComponent(df);
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "A click on the button should open a calendar and a second click should close it.";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 14086;
+ }
+
+}
diff --git a/uitest/src/com/vaadin/tests/components/datefield/DateFieldCloseTest.java b/uitest/src/com/vaadin/tests/components/datefield/DateFieldCloseTest.java
new file mode 100644
index 0000000000..e6f7520813
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/datefield/DateFieldCloseTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.datefield;
+
+import static com.vaadin.tests.components.datefield.DateFieldClose.DATEFIELD_ID;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.interactions.Actions;
+
+import com.vaadin.testbench.By;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+public class DateFieldCloseTest extends MultiBrowserTest {
+ private WebElement dateField;
+
+ @Test
+ public void closeByClickingCalendarButton() throws Exception {
+ openTestURL();
+ dateField = driver.findElement(By.id(DATEFIELD_ID));
+ clickButton();
+ checkForCalendarHeader(true);
+ closePopup();
+ checkForCalendarHeader(false);
+ }
+
+ private void checkForCalendarHeader(boolean headerShouldExist) {
+ boolean headerExists = isElementPresent(By
+ .className("v-datefield-calendarpanel-header"));
+ if (headerShouldExist) {
+ assertTrue("The calendar should be visible", headerExists);
+ } else {
+ assertFalse("The calendar should not be visible", headerExists);
+ }
+ }
+
+ private void clickButton() {
+ WebElement dateFieldButton = dateField.findElement(By
+ .className("v-datefield-button"));
+ testBenchElement(dateFieldButton).click(5, 5);
+ }
+
+ private void closePopup() {
+ WebElement dateFieldButton = dateField.findElement(By
+ .className("v-datefield-button"));
+ // To work reliably with IE, need to click and hold instead of just
+ // clicking the button.
+ Actions actions = new Actions(driver);
+ actions.clickAndHold(dateFieldButton).perform();
+ }
+}
--
cgit v1.2.3
From 409a41ce44f577170f4c84211515dbb5815f5642 Mon Sep 17 00:00:00 2001
From: Guillermo Alvarez
Date: Tue, 5 Aug 2014 18:45:14 +0300
Subject: Correctly display an item which is too long for the textfield.
(#13477) As setSelectionRange is not working correctly in IE the current
approach sets the direction before setting the text and resets it to the
original immediately after that. Change-Id:
I33f40f9ae436122092d995fa17c35a9cbe38aedb
---
client/src/com/vaadin/client/ui/VFilterSelect.java | 23 ++++--
.../components/ui/ComboboxSelectedItemText.java | 43 +++++++++++
.../ui/ComboboxSelectedItemTextTest.java | 90 ++++++++++++++++++++++
3 files changed, 150 insertions(+), 6 deletions(-)
create mode 100644 uitest/src/com/vaadin/tests/components/ui/ComboboxSelectedItemText.java
create mode 100644 uitest/src/com/vaadin/tests/components/ui/ComboboxSelectedItemTextTest.java
(limited to 'client')
diff --git a/client/src/com/vaadin/client/ui/VFilterSelect.java b/client/src/com/vaadin/client/ui/VFilterSelect.java
index 46f90c07fa..6ba0785acc 100644
--- a/client/src/com/vaadin/client/ui/VFilterSelect.java
+++ b/client/src/com/vaadin/client/ui/VFilterSelect.java
@@ -46,6 +46,7 @@ import com.google.gwt.event.dom.client.LoadEvent;
import com.google.gwt.event.dom.client.LoadHandler;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
+import com.google.gwt.i18n.client.HasDirection.Direction;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
@@ -452,9 +453,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
setSelectedItemIcon(suggestion.getIconUri());
// Set the text.
- tb.setText(text);
- tb.setSelectionRange(lastFilter.length(), text.length()
- - lastFilter.length());
+ setText(text);
menu.updateKeyboardSelectedItem();
}
@@ -916,11 +915,11 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
&& !currentSuggestion.key.equals("")) {
// An item (not null) selected
String text = currentSuggestion.getReplacementString();
- tb.setText(text);
+ setText(text);
selectedOptionKey = currentSuggestion.key;
} else {
// Null selected
- tb.setText("");
+ setText("");
selectedOptionKey = null;
}
}
@@ -1060,7 +1059,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
if (textInputEnabled) {
super.setSelectionRange(pos, length);
} else {
- super.setSelectionRange(getValue().length(), 0);
+ super.setSelectionRange(0, getValue().length());
}
}
}
@@ -1452,7 +1451,19 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler,
if (enableDebug) {
debug("VFS: setTextboxText(" + text + ")");
}
+ setText(text);
+ }
+
+ private void setText(final String text) {
+ /**
+ * To leave caret in the beginning of the line.
+ * SetSelectionRange wouldn't work on IE
+ * (see #13477)
+ */
+ Direction previousDirection = tb.getDirection();
+ tb.setDirection(Direction.RTL);
tb.setText(text);
+ tb.setDirection(previousDirection);
}
/**
diff --git a/uitest/src/com/vaadin/tests/components/ui/ComboboxSelectedItemText.java b/uitest/src/com/vaadin/tests/components/ui/ComboboxSelectedItemText.java
new file mode 100644
index 0000000000..d4599fc1a3
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/ui/ComboboxSelectedItemText.java
@@ -0,0 +1,43 @@
+package com.vaadin.tests.components.ui;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.Label;
+
+public class ComboboxSelectedItemText extends AbstractTestUIWithLog {
+ @Override
+ protected void setup(VaadinRequest request) {
+ getLayout()
+ .addComponent(
+ new Label(
+ "Select first ANTIGUA AND BARBUDA from the first combobox. Then select ANTIGUA AND BARBUDA from the second combobox. Finally, click the popup button on the first combobox. Before fix you would see UA AND BAR in the field."));
+
+ ComboBox combobox = new ComboBox("Text input enabled:");
+ combobox.setWidth("100px");
+
+ combobox.addItem("AMERICAN SAMOA");
+ combobox.addItem("ANTIGUA AND BARBUDA");
+
+ ComboBox combobox2 = new ComboBox("Text input disabled:");
+ combobox2.setWidth("100px");
+ combobox2.setTextInputAllowed(false);
+
+ combobox2.addItem("AMERICAN SAMOA");
+ combobox2.addItem("ANTIGUA AND BARBUDA");
+
+ getLayout().addComponent(combobox);
+ getLayout().addComponent(combobox2);
+ }
+
+ @Override
+ protected String getTestDescription() {
+ return "Tests selected item is displayed from the beginning";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ return 13477;
+ }
+
+}
\ No newline at end of file
diff --git a/uitest/src/com/vaadin/tests/components/ui/ComboboxSelectedItemTextTest.java b/uitest/src/com/vaadin/tests/components/ui/ComboboxSelectedItemTextTest.java
new file mode 100644
index 0000000000..f826654022
--- /dev/null
+++ b/uitest/src/com/vaadin/tests/components/ui/ComboboxSelectedItemTextTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2000-2013 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.ui;
+
+import java.io.IOException;
+
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+/**
+ * Test class for issue #13477, where selecting a combobox item that is too long
+ * would render the ending of an item instead of the beginning, which was
+ * considered less than informative.
+ *
+ * @author Vaadin Ltd
+ */
+
+public class ComboboxSelectedItemTextTest extends MultiBrowserTest {
+
+ public final String SCREENSHOT_NAME_EDITABLE = "LongComboboxItemSelectedEditable";
+ public final String SCREENSHOT_NAME_NON_EDITABLE = "LongComboboxItemSelectedNonEditable";
+ public final int INDEX_EDITABLE_COMBOBOX = 1;
+ public final int INDEX_NON_EDITABLE_COMBOBOX = 2;
+
+ @Test
+ public void testCombobox() throws IOException {
+ testCombobox(INDEX_EDITABLE_COMBOBOX, INDEX_NON_EDITABLE_COMBOBOX,
+ SCREENSHOT_NAME_EDITABLE);
+ }
+
+ @Test
+ public void testComboboxNonEditable() throws IOException {
+ testCombobox(INDEX_NON_EDITABLE_COMBOBOX, INDEX_EDITABLE_COMBOBOX,
+ SCREENSHOT_NAME_NON_EDITABLE);
+ }
+
+ private void testCombobox(int indexToTest, int indexToFocus,
+ String screenshotIdentifier) throws IOException {
+ openTestURL();
+
+ WebElement comboBox = vaadinElement("/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot["
+ + indexToTest + "]/VFilterSelect[0]");
+ WebElement comboBoxFocus = vaadinElement("/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot["
+ + indexToFocus + "]/VFilterSelect[0]");
+
+ // Select an element from the first (editable) combobox.
+
+ comboBox.findElement(By.className("v-filterselect-button")).click();
+ WebElement comboBoxPopup = vaadinElement("/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot["
+ + indexToTest + "]/VFilterSelect[0]#popup");
+ comboBoxPopup.findElements(By.tagName("td")).get(2).click();
+
+ // Select an element from the second (non-editable combobox) to remove
+ // focus from the first combobox
+
+ comboBoxFocus.findElement(By.className("v-filterselect-button"))
+ .click();
+ comboBoxPopup = vaadinElement("/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot["
+ + indexToFocus + "]/VFilterSelect[0]#popup");
+ comboBoxPopup.findElements(By.tagName("td")).get(2).click();
+
+ // click the popup on the first combobox. This would reveal the unwanted
+ // behaviour.
+
+ comboBox.findElement(By.className("v-filterselect-button")).click();
+
+ // sadly, screenshot comparison is the only reasonable way to test a
+ // rendering issue.
+
+ compareScreen(screenshotIdentifier);
+
+ }
+
+}
\ No newline at end of file
--
cgit v1.2.3