From 1001c45a97e8091cdc20f76cd9fcc7c996b003a3 Mon Sep 17 00:00:00 2001 From: Automerge Date: Mon, 2 Apr 2012 10:19:29 +0000 Subject: [merge from 6.7] #8597 Do not leave VWindow references in the static windowOrder list svn changeset:23377/svn branch:6.8 --- src/com/vaadin/terminal/gwt/client/ui/VWindow.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/com/vaadin/terminal/gwt/client/ui/VWindow.java b/src/com/vaadin/terminal/gwt/client/ui/VWindow.java index de01061641..103979927a 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VWindow.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VWindow.java @@ -580,7 +580,7 @@ public class VWindow extends VOverlay implements Container, } private void setCursorProperties() { - if (!this.draggable) { + if (!draggable) { header.getStyle().setProperty("cursor", "default"); footer.getStyle().setProperty("cursor", "default"); } else { @@ -686,6 +686,13 @@ public class VWindow extends VOverlay implements Container, @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); + } + if (vaadinModality) { showModalityCurtain(); } @@ -734,6 +741,10 @@ public class VWindow extends VOverlay implements Container, hideModalityCurtain(); } super.hide(); + + // Remove window from windowOrder to avoid references being left + // hanging. + windowOrder.remove(this); } private void setVaadinModality(boolean modality) { -- cgit v1.2.3 From 74bc9fe48afe4b65c160cb7c6c9e840692304fba Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Mon, 2 Apr 2012 10:54:44 +0000 Subject: Cleaned up #5100 test svn changeset:23378/svn branch:6.8 --- .../tests/components/tabsheet/TabKeyboardNavigation.java | 11 ----------- 1 file changed, 11 deletions(-) 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(); } -- cgit v1.2.3 From 170812b3d14db259268506cf8a4c0db8a2e493c1 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Mon, 2 Apr 2012 13:04:10 +0000 Subject: Fixed IE focus; fixed tab scrolling; minor refactoring svn changeset:23380/svn branch:6.8 --- .../vaadin/terminal/gwt/client/ui/VTabsheet.java | 120 +++++++++++++-------- 1 file changed, 77 insertions(+), 43 deletions(-) diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java index b77203532f..918ab19173 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java @@ -414,6 +414,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); } @@ -594,18 +598,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"); @@ -622,10 +628,10 @@ public class VTabsheet extends VTabsheetBase implements Focusable, } }); 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() { @@ -1196,6 +1202,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() { @@ -1334,60 +1345,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(); + } + } + } } -- cgit v1.2.3 From 7747ca748e809c2a218e1875bdabf3797ac50e69 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Mon, 2 Apr 2012 13:30:06 +0000 Subject: Don't test wrap-around in #5100 test as it's not currently supported svn changeset:23382/svn branch:6.8 --- .../components/tabsheet/TabKeyboardNavigation.html | 34 +++++----------------- 1 file changed, 7 insertions(+), 27 deletions(-) diff --git a/tests/testbench/com/vaadin/tests/components/tabsheet/TabKeyboardNavigation.html b/tests/testbench/com/vaadin/tests/components/tabsheet/TabKeyboardNavigation.html index d7876ba646..551083c1fc 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 @@ right - assertTextPresent + assertText + vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[1]/ChildComponentContainer[0]/VLabel[0] Tab 2 - screenCapture @@ -47,49 +47,29 @@ right - assertTextPresent + assertText + vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[3]/ChildComponentContainer[0]/VLabel[0] Tab 5 - screenCapture skip-disabled-to-tab5 - - pressSpecialKey - vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[4] - right - - - assertTextPresent - Tab 1 - wraparound-to-tab1 - click vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0] - - mouseClick - 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] - 14,9 - pressSpecialKey vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0] - left + right - assertTextPresent + assertText + vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[4]/ChildComponentContainer[0]/VLabel[0] Tab 6 - - - - screenCapture - - moved-left-to-tab6 -- cgit v1.2.3 From b39f10aee376c5b859a505fbe4b530be9790f927 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Mon, 2 Apr 2012 13:35:44 +0000 Subject: Reverted accidental commit svn changeset:23384/svn branch:6.8 --- .../vaadin/terminal/gwt/client/ui/VTabsheet.java | 120 ++++++++------------- 1 file changed, 43 insertions(+), 77 deletions(-) diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java index 918ab19173..b77203532f 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java @@ -414,10 +414,6 @@ 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); } @@ -598,20 +594,18 @@ public class VTabsheet extends VTabsheetBase implements Focusable, * @return Whether the tab could be selected or not. */ private boolean onTabSelected(final int tabIndex) { - Tab tab = tb.getTab(tabIndex); - if (client == null || disabled || waitingForResponse) { + if (disabled || waitingForResponse) { return false; } - if (!tab.isEnabledOnServer() || tab.isHiddenOnServer()) { + final Object tabKey = tabKeys.get(tabIndex); + if (disabledTabKeys.contains(tabKey)) { return false; } - if (activeTabIndex != tabIndex) { + if (client != null && activeTabIndex != tabIndex) { tb.selectTab(tabIndex); - // If this TabSheet already has focus, set the new selected tab - // as focused. if (focusedTab != null) { - focusedTab = tab; + focusedTab = tb.getTab(tabIndex); } addStyleDependentName("loading"); @@ -628,10 +622,10 @@ public class VTabsheet extends VTabsheetBase implements Focusable, } }); waitingForResponse = true; + + return true; } - // Note that we return true when tabIndex == activeTabIndex; the active - // tab could be selected, it's just a no-op. - return true; + return false; } public ApplicationConnection getApplicationConnection() { @@ -1202,11 +1196,6 @@ 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() { @@ -1345,83 +1334,60 @@ public class VTabsheet extends VTabsheetBase implements Focusable, int keycode = event.getNativeEvent().getKeyCode(); if (keycode == getPreviousTabKey()) { - selectPreviousTab(); + 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(); + } + } + } else if (keycode == getNextTabKey()) { - selectNextTab(); + 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(); + } + } + } 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(); - } - } - } } -- cgit v1.2.3 From b7947ce94ba1f8606e84199b67738bcbc6ad4f6f Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Mon, 2 Apr 2012 13:36:17 +0000 Subject: #5100 Fixed IE focus; fixed tab scrolling; minor refactoring svn changeset:23385/svn branch:6.8 --- .../vaadin/terminal/gwt/client/ui/VTabsheet.java | 120 +++++++++++++-------- 1 file changed, 77 insertions(+), 43 deletions(-) diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java index b77203532f..918ab19173 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java @@ -414,6 +414,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); } @@ -594,18 +598,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"); @@ -622,10 +628,10 @@ public class VTabsheet extends VTabsheetBase implements Focusable, } }); 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() { @@ -1196,6 +1202,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() { @@ -1334,60 +1345,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(); + } + } + } } -- cgit v1.2.3 From c75dfefae0180078b8fd99dd10ce60b8102f151d Mon Sep 17 00:00:00 2001 From: Automerge Date: Tue, 3 Apr 2012 10:12:26 +0000 Subject: [merge from 6.7] Basic app for testing various aspects of layout performance svn changeset:23393/svn branch:6.8 --- .../tests/layouts/LayoutPerformanceTests.java | 285 +++++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 tests/testbench/com/vaadin/tests/layouts/LayoutPerformanceTests.java 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 i = controls.getComponentIterator(); i + .hasNext();) { + Component component = i.next(); + if (component instanceof NativeSelect) { + NativeSelect nativeSelect = (NativeSelect) component; + nativeSelect.setNullSelectionAllowed(false); + nativeSelect.setValue(new ArrayList(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; + } + +} -- cgit v1.2.3 From 8b2662409cc4d77a08fcb6d5b72a72e8a542ae7f Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Wed, 4 Apr 2012 10:45:40 +0000 Subject: #5100 Removed obsolete code to fix a Firefox tab scrolling bug svn changeset:23399/svn branch:6.8 --- src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java index 918ab19173..7b9b900289 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTabsheet.java @@ -760,10 +760,6 @@ public class VTabsheet extends VTabsheetBase implements Focusable, // tabs; push or not if (!isDynamicWidth()) { - // 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(tabs, "width", "1px"); DOM.setStyleAttribute(tabs, "overflow", "hidden"); } else { showAllTabs(); -- cgit v1.2.3 From 04c54114279ca3375c16d37de31569e9f1eb429e Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Wed, 4 Apr 2012 10:46:16 +0000 Subject: Test tab scrolling in #5100 test svn changeset:23400/svn branch:6.8 --- .../components/tabsheet/TabKeyboardNavigation.html | 90 ++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/tests/testbench/com/vaadin/tests/components/tabsheet/TabKeyboardNavigation.html b/tests/testbench/com/vaadin/tests/components/tabsheet/TabKeyboardNavigation.html index 551083c1fc..129061e69c 100644 --- a/tests/testbench/com/vaadin/tests/components/tabsheet/TabKeyboardNavigation.html +++ b/tests/testbench/com/vaadin/tests/components/tabsheet/TabKeyboardNavigation.html @@ -71,6 +71,96 @@ vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[4]/ChildComponentContainer[0]/VLabel[0] Tab 6 + + click + vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0] + + + + click + vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0] + + + + click + vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0] + + + + click + vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0] + + + + click + vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0] + + + + click + vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VButton[0]/domChild[0]/domChild[0] + + + + mouseClick + 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] + 18,10 + + + pressSpecialKey + vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[8] + right + + + pressSpecialKey + vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[9] + right + + + pressSpecialKey + vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[10] + right + + + assertText + vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[8]/ChildComponentContainer[0]/VLabel[0] + Tab 12 + + + screenCapture + + scrolled-right-to-tab-12 + + + mouseClick + 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] + 11,2 + + + pressSpecialKey + vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[4] + left + + + pressSpecialKey + vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[2] + left + + + pressSpecialKey + vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]/domChild[1] + left + + + assertText + vaadin=runTabKeyboardNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[4]/VTabsheet[0]/VTabsheetPanel[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VLabel[0] + Tab 1 + + + screenCapture + + scrolled-left-to-tab-1 + -- cgit v1.2.3 From 149855812fc206a58d9e027106f4e88b8e2b5682 Mon Sep 17 00:00:00 2001 From: Leif Åstrand Date: Wed, 4 Apr 2012 11:47:02 +0000 Subject: Create integration test for WebSphere Application Server 8 (#3789) svn changeset:23401/svn branch:6.8 --- tests/integration_tests.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/integration_tests.xml b/tests/integration_tests.xml index ef4f40a60a..1270807630 100644 --- a/tests/integration_tests.xml +++ b/tests/integration_tests.xml @@ -260,6 +260,14 @@ + + + + + + + + @@ -344,6 +352,7 @@ + -- cgit v1.2.3 From c48774888da8fc7b073d715c97a0ee08aa52cf8c Mon Sep 17 00:00:00 2001 From: Automerge Date: Wed, 4 Apr 2012 13:07:03 +0000 Subject: [merge from 6.7] Test for #8328 svn changeset:23402/svn branch:6.8 --- .../data/util/sqlcontainer/ColumnPropertyTest.java | 60 ++++++++++++++++++++-- 1 file changed, 57 insertions(+), 3 deletions(-) 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); + } } -- cgit v1.2.3 From 2a88c95e39bdca3e779ff4e9eb44208dfbe3e8d3 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Thu, 5 Apr 2012 10:38:28 +0000 Subject: Fixed #6155: stop listening to Property value change and read only status change events on detach to avoid a potential memory leak, resume listening on attach svn changeset:23406/svn branch:6.8 --- src/com/vaadin/ui/AbstractField.java | 61 ++++++++++++------ .../abstractfield/RemoveListenersOnDetach.java | 72 ++++++++++++++++++++++ 2 files changed, 113 insertions(+), 20 deletions(-) create mode 100644 tests/server-side/com/vaadin/tests/server/component/abstractfield/RemoveListenersOnDetach.java diff --git a/src/com/vaadin/ui/AbstractField.java b/src/com/vaadin/ui/AbstractField.java index 9ea9bbba2e..ac3e14b2b6 100644 --- a/src/com/vaadin/ui/AbstractField.java +++ b/src/com/vaadin/ui/AbstractField.java @@ -139,6 +139,11 @@ public abstract class AbstractField extends AbstractComponent implements Field, private boolean valueWasModifiedByDataSourceDuringCommit; + /** + * Whether this field currently listens to Property events. + */ + private boolean isListening = false; + /* Component basics */ /* @@ -593,18 +598,8 @@ public abstract class AbstractField extends AbstractComponent implements Field, // Saves the old value final Object oldValue = value; - // 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; @@ -622,14 +617,8 @@ public abstract class AbstractField extends AbstractComponent implements Field, modified = 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) { @@ -1121,6 +1110,8 @@ public abstract class AbstractField extends AbstractComponent implements Field, if (actionManager != null) { actionManager.setViewer(getWindow()); } + // No-op if listeners already registered + addPropertyListeners(); } @Override @@ -1129,6 +1120,9 @@ public abstract class AbstractField extends AbstractComponent implements Field, if (actionManager != null) { actionManager.setViewer((Window) null); } + // Stop listening to data source events on detach to avoid a potential + // memory leak. See #6155. + removePropertyListeners(); } /** @@ -1329,4 +1323,31 @@ public abstract class AbstractField extends AbstractComponent implements Field, focusable.focus(); } } + + 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; + } + } } \ No newline at end of file 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..32b80e0bcd --- /dev/null +++ b/tests/server-side/com/vaadin/tests/server/component/abstractfield/RemoveListenersOnDetach.java @@ -0,0 +1,72 @@ +package com.vaadin.tests.server.component.abstractfield; + +import static org.junit.Assert.assertEquals; + +import com.vaadin.data.Property; +import com.vaadin.data.util.AbstractProperty; +import com.vaadin.ui.AbstractField; + +import org.junit.Test; + +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); + } +} -- cgit v1.2.3 From f7feb7b15aae9abb360c799dc7bf873a0d5a68ef Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Thu, 5 Apr 2012 10:50:00 +0000 Subject: Implemented #8307: Added AbstractField#removeAllValidators() svn changeset:23407/svn branch:6.8 --- src/com/vaadin/ui/AbstractField.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/com/vaadin/ui/AbstractField.java b/src/com/vaadin/ui/AbstractField.java index ac3e14b2b6..f3939de6e1 100644 --- a/src/com/vaadin/ui/AbstractField.java +++ b/src/com/vaadin/ui/AbstractField.java @@ -682,6 +682,16 @@ public abstract class AbstractField extends AbstractComponent implements Field, requestRepaint(); } + /** + * 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 -- cgit v1.2.3 From 35a223e3a3da7e1094cec585421898c8150e23c1 Mon Sep 17 00:00:00 2001 From: Johannes Dahlström Date: Thu, 5 Apr 2012 12:08:08 +0000 Subject: #8203 Added TabSheet#setSelectedTab(int) and TabSheet#setSelectedTab(TabSheet.Tab) svn changeset:23408/svn branch:6.8 --- src/com/vaadin/ui/TabSheet.java | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/com/vaadin/ui/TabSheet.java b/src/com/vaadin/ui/TabSheet.java index 70fa95ba97..cb89c5e0c8 100644 --- a/src/com/vaadin/ui/TabSheet.java +++ b/src/com/vaadin/ui/TabSheet.java @@ -581,7 +581,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 */ @@ -594,6 +594,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 + * index < 0 || index > {@link #getComponentCount()}. + * + * @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 -- cgit v1.2.3 From 97c58999b1450e1e55bfe505e5e15a0dd774ab54 Mon Sep 17 00:00:00 2001 From: Automerge Date: Thu, 5 Apr 2012 13:08:18 +0000 Subject: [merge from 6.7] Fixed #8604: Tree multiselect worked incorrectly in some cases svn changeset:23412/svn branch:6.8 --- src/com/vaadin/terminal/gwt/client/ui/VTree.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTree.java b/src/com/vaadin/terminal/gwt/client/ui/VTree.java index 4344cec5f5..2be01df8cc 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTree.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTree.java @@ -1442,7 +1442,7 @@ public class VTree extends FocusElementPanel implements Paintable, selectedIds.add(child.key); } return false; - } else if (child.isLeaf()) { + } else { child.setSelected(true); selectedIds.add(child.key); } -- cgit v1.2.3 From 6dee9c8fb0799af3bca1376d79449260279c4d67 Mon Sep 17 00:00:00 2001 From: Automerge Date: Thu, 5 Apr 2012 13:08:25 +0000 Subject: [merge from 6.7] TestBench test for #8604 svn changeset:23413/svn branch:6.8 --- .../components/tree/TreeShiftMultiSelectNodes.html | 114 +++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 tests/testbench/com/vaadin/tests/components/tree/TreeShiftMultiSelectNodes.html 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 @@ + + + + + + +Trees + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Trees
open/run/com.vaadin.tests.components.tree.Trees/?restartApplication
mouseClickvaadin=runcomvaadintestscomponentstreeTrees::PID_StestComponent#n[1]/expand9,10
mouseClickvaadin=runcomvaadintestscomponentstreeTrees::PID_StestComponent#n[1]/n[2]/expand9,10
mouseClickvaadin=runcomvaadintestscomponentstreeTrees::PID_StestComponent#n[1]/n[0]23,8
shiftKeyDown
mouseClickvaadin=runcomvaadintestscomponentstreeTrees::PID_StestComponent#n[1]/n[2]/n[1]28,8
shiftKeyUp
screenCaptureall-items-inside-selection-are-selected
+ + + + + + + + +Trees + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Trees
open/run/com.vaadin.tests.components.tree.Trees/?restartApplication
mouseClickvaadin=runcomvaadintestscomponentstreeTrees::PID_StestComponent#n[1]/expand9,10
mouseClickvaadin=runcomvaadintestscomponentstreeTrees::PID_StestComponent#n[1]/n[2]/expand9,10
mouseClickvaadin=runcomvaadintestscomponentstreeTrees::PID_StestComponent#n[1]/n[0]23,8
shiftKeyDown
mouseClickvaadin=runcomvaadintestscomponentstreeTrees::PID_StestComponent#n[1]/n[2]/n[1]28,8
shiftKeyUp
screenCaptureall-items-inside-selection-are-selected
+ + -- cgit v1.2.3 From 18dd267cfe3757adee20aaae556b64746c677683 Mon Sep 17 00:00:00 2001 From: Automerge Date: Thu, 5 Apr 2012 13:08:30 +0000 Subject: [merge from 6.7] Fix #8595: Always use MULTISELECT_MODE_SIMPLE for touch devices svn changeset:23414/svn branch:6.8 --- src/com/vaadin/terminal/gwt/client/ui/VTree.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTree.java b/src/com/vaadin/terminal/gwt/client/ui/VTree.java index 2be01df8cc..1d5ec206aa 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VTree.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VTree.java @@ -66,7 +66,14 @@ public class VTree extends FocusElementPanel implements Paintable, 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; @@ -299,7 +306,13 @@ public class VTree extends FocusElementPanel implements Paintable, isMultiselect = "multi".equals(selectMode); if (isMultiselect) { - multiSelectMode = uidl.getIntAttribute("multiselectmode"); + if (BrowserInfo.get().isTouchDevice()) { + // Always use the simple mode for touch devices that do not have + // shift/ctrl keys (#8595) + multiSelectMode = MULTISELECT_MODE_SIMPLE; + } else { + multiSelectMode = uidl.getIntAttribute("multiselectmode"); + } } selectedIds = uidl.getStringArrayVariableAsSet("selected"); -- cgit v1.2.3