diff options
14 files changed, 809 insertions, 102 deletions
diff --git a/src/com/vaadin/terminal/gwt/client/ui/TabsheetConnector.java b/src/com/vaadin/terminal/gwt/client/ui/TabsheetConnector.java index 297bb06400..afb9b69e6e 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/TabsheetConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/TabsheetConnector.java @@ -31,10 +31,6 @@ public class TabsheetConnector extends TabsheetBaseConnector implements // tabs; push or not if (!isUndefinedWidth()) { - // FIXME: This makes tab sheet tabs go to 1px width on every update - // and then back to original width - // update width later, in updateTabScroller(); - DOM.setStyleAttribute(getWidget().tabs, "width", "1px"); DOM.setStyleAttribute(getWidget().tabs, "overflow", "hidden"); } else { getWidget().showAllTabs(); diff --git a/src/com/vaadin/terminal/gwt/client/ui/TreeConnector.java b/src/com/vaadin/terminal/gwt/client/ui/TreeConnector.java index e1aef7f9e2..78a0a8453b 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/TreeConnector.java +++ b/src/com/vaadin/terminal/gwt/client/ui/TreeConnector.java @@ -9,6 +9,7 @@ import com.google.gwt.core.client.GWT; import com.google.gwt.user.client.ui.Widget; import com.vaadin.terminal.gwt.client.AbstractFieldState; import com.vaadin.terminal.gwt.client.ApplicationConnection; +import com.vaadin.terminal.gwt.client.BrowserInfo; import com.vaadin.terminal.gwt.client.Paintable; import com.vaadin.terminal.gwt.client.TooltipInfo; import com.vaadin.terminal.gwt.client.UIDL; @@ -88,8 +89,14 @@ public class TreeConnector extends AbstractComponentConnector implements getWidget().isMultiselect = "multi".equals(selectMode); if (getWidget().isMultiselect) { - getWidget().multiSelectMode = uidl - .getIntAttribute("multiselectmode"); + if (BrowserInfo.get().isTouchDevice()) { + // Always use the simple mode for touch devices that do not have + // shift/ctrl keys (#8595) + getWidget().multiSelectMode = VTree.MULTISELECT_MODE_SIMPLE; + } else { + getWidget().multiSelectMode = uidl + .getIntAttribute("multiselectmode"); + } } getWidget().selectedIds = uidl.getStringArrayVariableAsSet("selected"); diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java index 027f7975d3..2cdc041955 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java @@ -395,6 +395,10 @@ public class VTabsheet extends VTabsheetBase implements Focusable, public void onClick(ClickEvent event) { Widget caption = (Widget) event.getSource(); int index = getWidgetIndex(caption.getParent()); + // IE needs explicit focus() + if (BrowserInfo.get().isIE()) { + getTabsheet().focus(); + } getTabsheet().onTabSelected(index); } @@ -562,18 +566,20 @@ public class VTabsheet extends VTabsheetBase implements Focusable, * @return Whether the tab could be selected or not. */ private boolean onTabSelected(final int tabIndex) { - if (disabled || waitingForResponse) { + Tab tab = tb.getTab(tabIndex); + if (client == null || disabled || waitingForResponse) { return false; } - final Object tabKey = tabKeys.get(tabIndex); - if (disabledTabKeys.contains(tabKey)) { + if (!tab.isEnabledOnServer() || tab.isHiddenOnServer()) { return false; } - if (client != null && activeTabIndex != tabIndex) { + if (activeTabIndex != tabIndex) { tb.selectTab(tabIndex); + // If this TabSheet already has focus, set the new selected tab + // as focused. if (focusedTab != null) { - focusedTab = tb.getTab(tabIndex); + focusedTab = tab; } addStyleDependentName("loading"); @@ -586,10 +592,10 @@ public class VTabsheet extends VTabsheetBase implements Focusable, client.updateVariable(id, "selected", tabKeys.get(tabIndex) .toString(), true); waitingForResponse = true; - - return true; } - return false; + // Note that we return true when tabIndex == activeTabIndex; the active + // tab could be selected, it's just a no-op. + return true; } public ApplicationConnection getApplicationConnection() { @@ -1044,6 +1050,11 @@ public class VTabsheet extends VTabsheetBase implements Focusable, - (isScrolledTabs() ? scroller.getOffsetWidth() : 0); } + private boolean isClipped(Tab tab) { + return tab.getAbsoluteLeft() + tab.getOffsetWidth() > getAbsoluteLeft() + + getOffsetWidth() - scroller.getOffsetWidth(); + } + @Override protected void clearPaintables() { @@ -1126,60 +1137,83 @@ public class VTabsheet extends VTabsheetBase implements Focusable, int keycode = event.getNativeEvent().getKeyCode(); if (keycode == getPreviousTabKey()) { - int newTabIndex = activeTabIndex; - // Find the previous non-disabled tab with wraparound. - do { - newTabIndex = (newTabIndex != 0) ? newTabIndex - 1 : tb - .getTabCount() - 1; - } while (newTabIndex != activeTabIndex - && !onTabSelected(newTabIndex)); - activeTabIndex = newTabIndex; - - // Tab scrolling - if (isScrolledTabs()) { - int newFirstIndex = tb.scrollLeft(scrollerIndex); - if (newFirstIndex != -1) { - scrollerIndex = newFirstIndex; - updateTabScroller(); - } - } - + selectPreviousTab(); } else if (keycode == getNextTabKey()) { - int newTabIndex = activeTabIndex; - // Find the next non-disabled tab with wraparound. - do { - newTabIndex = (newTabIndex + 1) % tb.getTabCount(); - } while (newTabIndex != activeTabIndex - && !onTabSelected(newTabIndex)); - activeTabIndex = newTabIndex; - - if (isClippedTabs()) { - int newFirstIndex = tb.scrollRight(scrollerIndex); - if (newFirstIndex != -1) { - scrollerIndex = newFirstIndex; - updateTabScroller(); - } - } - + selectNextTab(); } else if (keycode == getCloseTabKey()) { Tab tab = tb.getTab(activeTabIndex); if (tab.isClosable()) { tab.onClose(); - removeTab(activeTabIndex); } } } } + /** + * @return The key code of the keyboard shortcut that selects the previous + * tab in a focused tabsheet. + */ protected int getPreviousTabKey() { return KeyCodes.KEY_LEFT; } + /** + * @return The key code of the keyboard shortcut that selects the next tab + * in a focused tabsheet. + */ protected int getNextTabKey() { return KeyCodes.KEY_RIGHT; } + /** + * @return The key code of the keyboard shortcut that closes the currently + * selected tab in a focused tabsheet. + */ protected int getCloseTabKey() { return KeyCodes.KEY_DELETE; } + + private void selectPreviousTab() { + int newTabIndex = activeTabIndex; + // Find the previous visible and enabled tab if any. + do { + newTabIndex--; + } while (newTabIndex >= 0 && !onTabSelected(newTabIndex)); + + if (newTabIndex >= 0) { + activeTabIndex = newTabIndex; + if (isScrolledTabs()) { + // Scroll until the new active tab is visible + int newScrollerIndex = scrollerIndex; + while (tb.getTab(activeTabIndex).getAbsoluteLeft() < getAbsoluteLeft() + && newScrollerIndex != -1) { + newScrollerIndex = tb.scrollLeft(newScrollerIndex); + } + scrollerIndex = newScrollerIndex; + updateTabScroller(); + } + } + } + + private void selectNextTab() { + int newTabIndex = activeTabIndex; + // Find the next visible and enabled tab if any. + do { + newTabIndex++; + } while (newTabIndex < getTabCount() && !onTabSelected(newTabIndex)); + + if (newTabIndex < getTabCount()) { + activeTabIndex = newTabIndex; + if (isClippedTabs()) { + // Scroll until the new active tab is completely visible + int newScrollerIndex = scrollerIndex; + while (isClipped(tb.getTab(activeTabIndex)) + && newScrollerIndex != -1) { + newScrollerIndex = tb.scrollRight(newScrollerIndex); + } + scrollerIndex = newScrollerIndex; + updateTabScroller(); + } + } + } } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTree.java b/src/com/vaadin/terminal/gwt/client/ui/VTree.java index e105bcafb1..49c6a2a582 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTree.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTree.java @@ -67,7 +67,14 @@ public class VTree extends FocusElementPanel implements VHasDropHandler, public static final String ITEM_CLICK_EVENT_ID = "itemClick"; + /** + * Click selects the current node, ctrl/shift toggles multi selection + */ public static final int MULTISELECT_MODE_DEFAULT = 0; + + /** + * Click/touch on node toggles its selected status + */ public static final int MULTISELECT_MODE_SIMPLE = 1; private static final int CHARCODE_SPACE = 32; @@ -1197,7 +1204,7 @@ public class VTree extends FocusElementPanel implements VHasDropHandler, selectedIds.add(child.key); } return false; - } else if (child.isLeaf()) { + } else { child.setSelected(true); selectedIds.add(child.key); } diff --git a/src/com/vaadin/terminal/gwt/client/ui/VWindow.java b/src/com/vaadin/terminal/gwt/client/ui/VWindow.java index d3529987fa..860b3d1f9e 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VWindow.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VWindow.java @@ -366,6 +366,9 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, @Override public void show() { if (!windowOrder.contains(this)) { + // This is needed if the window is hidden and then shown again. + // Otherwise this VWindow is added to windowOrder in the + // constructor. windowOrder.add(this); } @@ -382,6 +385,8 @@ public class VWindow extends VOverlay implements ShortcutActionHandlerOwner, } super.hide(); + // Remove window from windowOrder to avoid references being left + // hanging. windowOrder.remove(this); } diff --git a/src/com/vaadin/ui/AbstractField.java b/src/com/vaadin/ui/AbstractField.java index 361e65fa34..3b9d035a9a 100644 --- a/src/com/vaadin/ui/AbstractField.java +++ b/src/com/vaadin/ui/AbstractField.java @@ -29,8 +29,6 @@ import com.vaadin.event.ShortcutListener; import com.vaadin.terminal.AbstractErrorMessage; import com.vaadin.terminal.CompositeErrorMessage; import com.vaadin.terminal.ErrorMessage; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; import com.vaadin.terminal.gwt.client.AbstractFieldState; /** @@ -138,6 +136,11 @@ public abstract class AbstractField<T> extends AbstractComponent implements private boolean valueWasModifiedByDataSourceDuringCommit; + /** + * Whether this field currently listens to Property events. + */ + private boolean isListening = false; + /* Component basics */ /* @@ -673,18 +676,8 @@ public abstract class AbstractField<T> extends AbstractComponent implements // Saves the old value final Object oldValue = getInternalValue(); - // Stops listening the old data source changes - if (dataSource != null - && Property.ValueChangeNotifier.class - .isAssignableFrom(dataSource.getClass())) { - ((Property.ValueChangeNotifier) dataSource).removeListener(this); - } - if (dataSource != null - && Property.ReadOnlyStatusChangeNotifier.class - .isAssignableFrom(dataSource.getClass())) { - ((Property.ReadOnlyStatusChangeNotifier) dataSource) - .removeListener(this); - } + // Stop listening to the old data source + removePropertyListeners(); // Sets the new data source dataSource = newDataSource; @@ -719,14 +712,8 @@ public abstract class AbstractField<T> extends AbstractComponent implements setModified(true); } - // Listens the new data source if possible - if (dataSource instanceof Property.ValueChangeNotifier) { - ((Property.ValueChangeNotifier) dataSource).addListener(this); - } - if (dataSource instanceof Property.ReadOnlyStatusChangeNotifier) { - ((Property.ReadOnlyStatusChangeNotifier) dataSource) - .addListener(this); - } + // Listen to new data source if possible + addPropertyListeners(); // Copy the validators from the data source if (dataSource instanceof Validatable) { @@ -938,6 +925,16 @@ public abstract class AbstractField<T> extends AbstractComponent implements } /** + * Removes all validators from the field. + */ + public void removeAllValidators() { + if (validators != null) { + validators.clear(); + } + requestRepaint(); + } + + /** * Tests the current value against registered validators if the field is not * empty. If the field is empty it is considered valid if it is not required * and invalid otherwise. Validators are never checked for empty fields. @@ -1356,6 +1353,26 @@ public abstract class AbstractField<T> extends AbstractComponent implements } /** + * Notifies the component that it is connected to an application. + * + * @see com.vaadin.ui.Component#attach() + */ + @Override + public void attach() { + super.attach(); + // No-op if listeners already registered + addPropertyListeners(); + } + + @Override + public void detach() { + super.detach(); + // Stop listening to data source events on detach to avoid a potential + // memory leak. See #6155. + removePropertyListeners(); + } + + /** * Is this field required. Required fields must filled by the user. * * If the field is required, it is visually indicated in the user interface. @@ -1592,4 +1609,30 @@ public abstract class AbstractField<T> extends AbstractComponent implements getState().setHideErrors(shouldHideErrors()); } + private void addPropertyListeners() { + if (!isListening) { + if (dataSource instanceof Property.ValueChangeNotifier) { + ((Property.ValueChangeNotifier) dataSource).addListener(this); + } + if (dataSource instanceof Property.ReadOnlyStatusChangeNotifier) { + ((Property.ReadOnlyStatusChangeNotifier) dataSource) + .addListener(this); + } + isListening = true; + } + } + + private void removePropertyListeners() { + if (isListening) { + if (dataSource instanceof Property.ValueChangeNotifier) { + ((Property.ValueChangeNotifier) dataSource) + .removeListener(this); + } + if (dataSource instanceof Property.ReadOnlyStatusChangeNotifier) { + ((Property.ReadOnlyStatusChangeNotifier) dataSource) + .removeListener(this); + } + isListening = false; + } + } } diff --git a/src/com/vaadin/ui/TabSheet.java b/src/com/vaadin/ui/TabSheet.java index 82a2930dd8..c4c524210f 100644 --- a/src/com/vaadin/ui/TabSheet.java +++ b/src/com/vaadin/ui/TabSheet.java @@ -561,7 +561,7 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, /** * Sets the selected tab. The tab is identified by the tab content - * component. + * component. Does nothing if the tabsheet doesn't contain the component. * * @param c */ @@ -596,6 +596,27 @@ public class TabSheet extends AbstractComponentContainer implements Focusable, } /** + * Sets the selected tab. The tab is identified by the corresponding + * {@link Tab Tab} instance. Does nothing if the tabsheet doesn't contain + * the given tab. + * + * @param tab + */ + public void setSelectedTab(Tab tab) { + setSelectedTab(tab.getComponent()); + } + + /** + * Sets the selected tab, identified by its position. Does nothing if + * <code>index < 0 || index > {@link #getComponentCount()}</code>. + * + * @param index + */ + public void setSelectedTab(int index) { + setSelectedTab(getTab(index)); + } + + /** * Checks if the current selection is valid, and updates the selection if * the previously selected component is not visible and enabled. The first * visible and enabled tab is selected if the current selection is empty or diff --git a/tests/integration_tests.xml b/tests/integration_tests.xml index 7bb179056a..7f72758a37 100644 --- a/tests/integration_tests.xml +++ b/tests/integration_tests.xml @@ -243,6 +243,14 @@ <param name="target-server" value="weblogic9" /> </antcall> </target> + + <target name="integration-test-websphere8"> + <antcall target="run-generic-integration-test"> + <param name="startDelay" value="600" /> + <param name="target-port" value="9080" /> + <param name="target-server" value="websphere8" /> + </antcall> + </target> <target name="integration-test-weblogic10"> <antcall target="run-generic-integration-test"> @@ -323,6 +331,7 @@ <antcall target="integration-test-tomcat5" /> <antcall target="integration-test-tomcat6" /> <antcall target="integration-test-tomcat7" /> + <antcall target="integration-test-websphere8" /> </parallel> diff --git a/tests/server-side/com/vaadin/data/util/sqlcontainer/ColumnPropertyTest.java b/tests/server-side/com/vaadin/data/util/sqlcontainer/ColumnPropertyTest.java index fac9fc98db..b9621d518a 100644 --- a/tests/server-side/com/vaadin/data/util/sqlcontainer/ColumnPropertyTest.java +++ b/tests/server-side/com/vaadin/data/util/sqlcontainer/ColumnPropertyTest.java @@ -1,14 +1,19 @@ package com.vaadin.data.util.sqlcontainer; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; import java.util.Arrays; +import com.vaadin.data.Property.ReadOnlyException; +import com.vaadin.data.util.sqlcontainer.ColumnProperty.NotNullableException; +import com.vaadin.data.util.sqlcontainer.query.QueryDelegate; + import org.easymock.EasyMock; import org.junit.Assert; import org.junit.Test; -import com.vaadin.data.Property.ReadOnlyException; -import com.vaadin.data.util.sqlcontainer.ColumnProperty.NotNullableException; - public class ColumnPropertyTest { @Test @@ -175,4 +180,53 @@ public class ColumnPropertyTest { cp.setValue(null); Assert.assertNull(cp.getValue()); } + + @Test + public void setValue_sendsItemChangeNotification() throws SQLException { + + class TestContainer extends SQLContainer { + Object value = null; + boolean modified = false; + + public TestContainer(QueryDelegate delegate) throws SQLException { + super(delegate); + } + + @Override + public void itemChangeNotification(RowItem changedItem) { + ColumnProperty cp = (ColumnProperty) changedItem + .getItemProperty("NAME"); + value = cp.getValue(); + modified = cp.isModified(); + } + } + + ColumnProperty property = new ColumnProperty("NAME", false, true, true, + "Ville", String.class); + + Statement statement = EasyMock.createNiceMock(Statement.class); + EasyMock.replay(statement); + + ResultSetMetaData metadata = EasyMock + .createNiceMock(ResultSetMetaData.class); + EasyMock.replay(metadata); + + ResultSet resultSet = EasyMock.createNiceMock(ResultSet.class); + EasyMock.expect(resultSet.getStatement()).andReturn(statement); + EasyMock.expect(resultSet.getMetaData()).andReturn(metadata); + EasyMock.replay(resultSet); + + QueryDelegate delegate = EasyMock.createNiceMock(QueryDelegate.class); + EasyMock.expect(delegate.getResults(0, 1)).andReturn(resultSet); + EasyMock.replay(delegate); + + TestContainer container = new TestContainer(delegate); + + new RowItem(container, new RowId(new Object[] { 1 }), + Arrays.asList(property)); + + property.setValue("Kalle"); + Assert.assertEquals("Kalle", container.value); + Assert.assertTrue(container.modified); + } } diff --git a/tests/server-side/com/vaadin/tests/server/component/abstractfield/RemoveListenersOnDetach.java b/tests/server-side/com/vaadin/tests/server/component/abstractfield/RemoveListenersOnDetach.java new file mode 100644 index 0000000000..9aeccdb56f --- /dev/null +++ b/tests/server-side/com/vaadin/tests/server/component/abstractfield/RemoveListenersOnDetach.java @@ -0,0 +1,73 @@ +package com.vaadin.tests.server.component.abstractfield; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import com.vaadin.data.Property; +import com.vaadin.data.util.AbstractProperty; +import com.vaadin.data.util.converter.Converter.ConversionException; +import com.vaadin.ui.AbstractField; + +public class RemoveListenersOnDetach { + + int numValueChanges = 0; + int numReadOnlyChanges = 0; + + AbstractField field = new AbstractField() { + @Override + public Class<?> getType() { + return null; + } + + @Override + public void valueChange(Property.ValueChangeEvent event) { + super.valueChange(event); + numValueChanges++; + } + + @Override + public void readOnlyStatusChange( + Property.ReadOnlyStatusChangeEvent event) { + super.readOnlyStatusChange(event); + numReadOnlyChanges++; + } + }; + + Property property = new AbstractProperty() { + public Object getValue() { + return null; + } + + public void setValue(Object newValue) throws ReadOnlyException, + ConversionException { + fireValueChange(); + } + + public Class<?> getType() { + return null; + } + }; + + @Test + public void testAttachDetach() { + field.setPropertyDataSource(property); + + property.setValue(null); + property.setReadOnly(true); + assertEquals(1, numValueChanges); + assertEquals(1, numReadOnlyChanges); + + field.attach(); + property.setValue(null); + property.setReadOnly(false); + assertEquals(2, numValueChanges); + assertEquals(2, numReadOnlyChanges); + + field.detach(); + property.setValue(null); + property.setReadOnly(true); + assertEquals(2, numValueChanges); + assertEquals(2, numReadOnlyChanges); + } +} diff --git a/tests/testbench/com/vaadin/tests/components/tabsheet/TabKeyboardNavigation.html b/tests/testbench/com/vaadin/tests/components/tabsheet/TabKeyboardNavigation.html index d7876ba646..129061e69c 100644 --- a/tests/testbench/com/vaadin/tests/components/tabsheet/TabKeyboardNavigation.html +++ b/tests/testbench/com/vaadin/tests/components/tabsheet/TabKeyboardNavigation.html @@ -27,9 +27,9 @@ <td>right</td> </tr> <tr> - <td>assertTextPresent</td> + <td>assertText</td> + <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[1]/ChildComponentContainer[0]/VLabel[0]</td> <td>Tab 2</td> - <td></td> </tr> <tr> <td>screenCapture</td> @@ -47,9 +47,9 @@ <td>right</td> </tr> <tr> - <td>assertTextPresent</td> + <td>assertText</td> + <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[3]/ChildComponentContainer[0]/VLabel[0]</td> <td>Tab 5</td> - <td></td> </tr> <tr> <td>screenCapture</td> @@ -57,14 +57,44 @@ <td>skip-disabled-to-tab5</td> </tr> <tr> + <td>click</td> + <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> <td>pressSpecialKey</td> - <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[4]</td> + <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> <td>right</td> </tr> <tr> - <td>assertTextPresent</td> - <td>Tab 1</td> - <td>wraparound-to-tab1</td> + <td>assertText</td> + <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[4]/ChildComponentContainer[0]/VLabel[0]</td> + <td>Tab 6</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> </tr> <tr> <td>click</td> @@ -73,23 +103,63 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> - <td>14,9</td> + <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[8]/domChild[0]/domChild[0]/domChild[0]</td> + <td>18,10</td> </tr> <tr> <td>pressSpecialKey</td> - <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> - <td>left</td> + <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[8]</td> + <td>right</td> </tr> <tr> - <td>assertTextPresent</td> - <td>Tab 6</td> + <td>pressSpecialKey</td> + <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[9]</td> + <td>right</td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[10]</td> + <td>right</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[8]/ChildComponentContainer[0]/VLabel[0]</td> + <td>Tab 12</td> +</tr> +<tr> + <td>screenCapture</td> <td></td> + <td>scrolled-right-to-tab-12</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[4]/domChild[0]/domChild[0]/domChild[0]</td> + <td>11,2</td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[4]</td> + <td>left</td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[2]</td> + <td>left</td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[1]</td> + <td>left</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0]</td> + <td>Tab 1</td> </tr> <tr> <td>screenCapture</td> <td></td> - <td>moved-left-to-tab6</td> + <td>scrolled-left-to-tab-1</td> </tr> </tbody></table> diff --git a/tests/testbench/com/vaadin/tests/components/tabsheet/TabKeyboardNavigation.java b/tests/testbench/com/vaadin/tests/components/tabsheet/TabKeyboardNavigation.java index cc82704d16..a3886853ff 100644 --- a/tests/testbench/com/vaadin/tests/components/tabsheet/TabKeyboardNavigation.java +++ b/tests/testbench/com/vaadin/tests/components/tabsheet/TabKeyboardNavigation.java @@ -15,8 +15,6 @@ import com.vaadin.ui.Component; import com.vaadin.ui.Label; import com.vaadin.ui.Layout; import com.vaadin.ui.TabSheet; -import com.vaadin.ui.TabSheet.SelectedTabChangeEvent; -import com.vaadin.ui.TabSheet.SelectedTabChangeListener; import com.vaadin.ui.TabSheet.Tab; import com.vaadin.ui.TextField; import com.vaadin.ui.VerticalLayout; @@ -32,7 +30,6 @@ public class TabKeyboardNavigation extends TestBase { protected void setup() { ts.setWidth("500px"); ts.setHeight("500px"); - // ts.setTabIndex(0); ts.addListener(new FocusListener() { public void focus(FocusEvent event) { @@ -46,14 +43,6 @@ public class TabKeyboardNavigation extends TestBase { } }); - ts.addListener(new SelectedTabChangeListener() { - - public void selectedTabChange(SelectedTabChangeEvent event) { - // ts.setSelectedTab(tabs.get(Math.max(0, - // tabs.indexOf(ts.getSelectedTab()) - 1))); - } - }); - for (int i = 0; i < 5; ++i) { addTab(); } diff --git a/tests/testbench/com/vaadin/tests/components/tree/TreeShiftMultiSelectNodes.html b/tests/testbench/com/vaadin/tests/components/tree/TreeShiftMultiSelectNodes.html new file mode 100644 index 0000000000..75ad4b5ff5 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/tree/TreeShiftMultiSelectNodes.html @@ -0,0 +1,114 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="http://localhost:8888/" /> +<title>Trees</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">Trees</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.tree.Trees/?restartApplication</td> + <td></td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentstreeTrees::PID_StestComponent#n[1]/expand</td> + <td>9,10</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentstreeTrees::PID_StestComponent#n[1]/n[2]/expand</td> + <td>9,10</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentstreeTrees::PID_StestComponent#n[1]/n[0]</td> + <td>23,8</td> +</tr> +<tr> + <td>shiftKeyDown</td> + <td></td> + <td></td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentstreeTrees::PID_StestComponent#n[1]/n[2]/n[1]</td> + <td>28,8</td> +</tr> +<tr> + <td>shiftKeyUp</td> + <td></td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>all-items-inside-selection-are-selected</td> +</tr> + +</tbody></table> +</body> +</html> +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> +<head profile="http://selenium-ide.openqa.org/profiles/test-case"> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> +<link rel="selenium.base" href="http://localhost:8888/" /> +<title>Trees</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">Trees</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.tree.Trees/?restartApplication</td> + <td></td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentstreeTrees::PID_StestComponent#n[1]/expand</td> + <td>9,10</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentstreeTrees::PID_StestComponent#n[1]/n[2]/expand</td> + <td>9,10</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentstreeTrees::PID_StestComponent#n[1]/n[0]</td> + <td>23,8</td> +</tr> +<tr> + <td>shiftKeyDown</td> + <td></td> + <td></td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentstreeTrees::PID_StestComponent#n[1]/n[2]/n[1]</td> + <td>28,8</td> +</tr> +<tr> + <td>shiftKeyUp</td> + <td></td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>all-items-inside-selection-are-selected</td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/layouts/LayoutPerformanceTests.java b/tests/testbench/com/vaadin/tests/layouts/LayoutPerformanceTests.java new file mode 100644 index 0000000000..23cf868085 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/layouts/LayoutPerformanceTests.java @@ -0,0 +1,285 @@ +package com.vaadin.tests.layouts; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.Iterator; + +import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.AbstractOrderedLayout; +import com.vaadin.ui.Alignment; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.CheckBox; +import com.vaadin.ui.Component; +import com.vaadin.ui.ComponentContainer; +import com.vaadin.ui.HorizontalLayout; +import com.vaadin.ui.Label; +import com.vaadin.ui.NativeSelect; +import com.vaadin.ui.Panel; +import com.vaadin.ui.TextField; +import com.vaadin.ui.VerticalLayout; + +public class LayoutPerformanceTests extends TestBase { + private static final String[] widths = { null, "100%", "200px" }; + + private enum ContainerType { + SIMPLE_WRAPS { + @Override + public ComponentContainer buildLayout(int depth, int leafs, + SampleType leafType, boolean fullHeight) { + if (depth == 0) { + return buildInnerLayout(leafs, leafType, fullHeight); + } + + AbstractOrderedLayout layout = createOrderedLayout(depth, + fullHeight); + layout.addComponent(buildLayout(depth - 1, leafs, leafType, + fullHeight)); + return layout; + } + }, + BORDER_LAYOUT { + @Override + public ComponentContainer buildLayout(int depth, int leafs, + SampleType leafType, boolean fullHeight) { + if (depth == 0) { + return buildInnerLayout(leafs, leafType, fullHeight); + } + + AbstractOrderedLayout layout = createOrderedLayout(depth, + fullHeight); + Component content = leafType.createContent(); + content.setSizeUndefined(); + layout.addComponent(content); + layout.addComponent(buildLayout(depth - 1, leafs, leafType, + fullHeight)); + layout.setExpandRatio(layout.getComponent(1), 1); + return layout; + } + }, + FRACTAL { + @Override + public ComponentContainer buildLayout(int depth, int leafs, + SampleType leafType, boolean fullHeight) { + if (depth == 0) { + return buildInnerLayout(leafs, leafType, fullHeight); + } + + AbstractOrderedLayout layout = createOrderedLayout(depth, + fullHeight); + layout.addComponent(buildLayout(depth - 1, leafs, leafType, + fullHeight)); + layout.addComponent(buildLayout(depth - 1, leafs, leafType, + fullHeight)); + layout.setExpandRatio(layout.getComponent(0), 1); + layout.setExpandRatio(layout.getComponent(1), 2); + return layout; + } + }; + public abstract ComponentContainer buildLayout(int depth, int leafs, + SampleType leafType, boolean fullHeight); + + protected AbstractOrderedLayout createOrderedLayout(int depth, + boolean fullHeight) { + AbstractOrderedLayout layout = (depth % 2) == 0 ? new VerticalLayout() + : new HorizontalLayout(); + layout.setWidth("100%"); + if (fullHeight) { + layout.setHeight("100%"); + } else { + layout.setHeight(null); + } + + return layout; + } + + public ComponentContainer buildInnerLayout(int leafs, + SampleType leafType, boolean fullHeight) { + VerticalLayout layout = new VerticalLayout(); + if (fullHeight) { + layout.setHeight("100%"); + layout.setWidth("100%"); + } + for (int i = 0; i < leafs; i++) { + Component leaf = leafType.createContent(); + if (leaf.getWidth() <= 0) { + leaf.setWidth(widths[i % 3]); + } + layout.addComponent(leaf); + } + return layout; + } + } + + private enum SampleType { + SHORT_LABEL { + @Override + public Component createContent() { + return new Label("Short label"); + } + }, + LONG_LABEL { + @Override + public Component createContent() { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < 100; i++) { + builder.append("A rather long text. "); + } + return new Label(builder.toString()); + } + }, + BUTTON { + @Override + public Component createContent() { + return new Button("Text"); + } + }, + TEXT_FIELD { + @Override + public Component createContent() { + return new TextField("Field label"); + } + }, + HORIZONTAL_LAYOUT { + @Override + public Component createContent() { + HorizontalLayout layout = new HorizontalLayout(); + layout.addComponent(new Label("Left")); + layout.addComponent(new Label("Right")); + layout.setComponentAlignment(layout.getComponent(1), + Alignment.BOTTOM_RIGHT); + + return layout; + } + }, + WRAPPED_PANEL { + @Override + public Component createContent() { + HorizontalLayout horizontal = new HorizontalLayout(); + horizontal.setWidth("100%"); + horizontal.setHeight(null); + horizontal.setMargin(true); + + VerticalLayout left = new VerticalLayout(); + left.setWidth("100%"); + left.addComponent(new Label("Text 1")); + left.addComponent(new Label("Text 2")); + left.addComponent(new Label("Text 3")); + horizontal.addComponent(left); + + VerticalLayout right = new VerticalLayout(); + right.setWidth("100%"); + right.addComponent(new Label("Text 1")); + right.addComponent(new Label("Text 2")); + right.addComponent(new Label("Text 3")); + horizontal.addComponent(right); + + Panel panel = new Panel(horizontal); + panel.setCaption("Panel caption"); + panel.setWidth("100%"); + panel.setHeight(null); + + return panel; + } + }; + public abstract Component createContent(); + } + + private Component testLayout = new Label(""); + + private final CheckBox wrapInPanel = new CheckBox("Wrap in Panel"); + private final NativeSelect containerSelector = new NativeSelect( + "Wrapping structure", EnumSet.allOf(ContainerType.class)); + @SuppressWarnings("boxing") + private final NativeSelect levels = new NativeSelect("Wrapping depth", + Arrays.asList(0, 1, 2, 3, 4, 5, 10, 15, 20, 25)); + private final NativeSelect leafSelector = new NativeSelect("Leaf type", + EnumSet.allOf(SampleType.class)); + @SuppressWarnings("boxing") + private final NativeSelect childAmount = new NativeSelect("Leaf count", + Arrays.asList(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, + 4096, 8192, 16384)); + + @Override + protected void setup() { + HorizontalLayout controls = new HorizontalLayout(); + controls.setSpacing(true); + + controls.addComponent(wrapInPanel); + controls.addComponent(containerSelector); + controls.addComponent(levels); + controls.addComponent(leafSelector); + controls.addComponent(childAmount); + + controls.addComponent(new Button("Clear", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + setTestLayout(new Label("")); + } + })); + + controls.addComponent(new Button("Apply", new Button.ClickListener() { + public void buttonClick(ClickEvent event) { + SampleType leafType = (SampleType) leafSelector.getValue(); + if (leafType == null) { + return; + } + + ContainerType containerType = (ContainerType) containerSelector + .getValue(); + if (containerType == null) { + return; + } + + boolean wrapped = wrapInPanel.booleanValue(); + ComponentContainer container = containerType.buildLayout( + ((Number) levels.getValue()).intValue(), + ((Number) childAmount.getValue()).intValue(), leafType, + !wrapped); + if (wrapped) { + Panel panel = new Panel(container); + panel.setSizeFull(); + container = panel; + } + setTestLayout(container); + } + })); + + for (Iterator<Component> i = controls.getComponentIterator(); i + .hasNext();) { + Component component = i.next(); + if (component instanceof NativeSelect) { + NativeSelect nativeSelect = (NativeSelect) component; + nativeSelect.setNullSelectionAllowed(false); + nativeSelect.setValue(new ArrayList<Object>(nativeSelect + .getItemIds()).get(0)); + } + controls.setComponentAlignment(component, Alignment.BOTTOM_LEFT); + } + + VerticalLayout layout = getLayout(); + layout.addComponent(controls); + layout.addComponent(testLayout); + layout.setExpandRatio(testLayout, 1); + layout.setSizeFull(); + } + + public void setTestLayout(Component testLayout) { + getLayout().replaceComponent(this.testLayout, testLayout); + getLayout().setExpandRatio(testLayout, 1); + this.testLayout = testLayout; + } + + @Override + protected String getDescription() { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Integer getTicketNumber() { + // TODO Auto-generated method stub + return null; + } + +} |