diff options
author | Leif Åstrand <leif@vaadin.com> | 2013-05-17 15:10:48 +0300 |
---|---|---|
committer | Leif Åstrand <leif@vaadin.com> | 2013-05-17 15:10:48 +0300 |
commit | 9b6b735752e2f30bcdf6a521e031a8de22343bb0 (patch) | |
tree | cb40f3a2bb238057a3875aa4d2581ecda83667a7 | |
parent | 2f6d5e0d8c7cf4912bb82207c0dbe26101d168cb (diff) | |
parent | 42545ac81ae49cb9a3af2a8b3b06ba9525886b22 (diff) | |
download | vaadin-framework-9b6b735752e2f30bcdf6a521e031a8de22343bb0.tar.gz vaadin-framework-9b6b735752e2f30bcdf6a521e031a8de22343bb0.zip |
Merge changes from origin/7.0
55ea6dc More specific workaround for no rows in TreeTable with pagelenght = 0 (#9203)
dca728c Warn if using old widgetset (#11836)
936439d Verify that tests are run with the expected JRE version (#11835)
29eeda5 Merge "Clean up Table popup menu close handler to prevent a memory leak" from 6.8 (#11840)
6d7f5e4 Eliminate unnecessary conversions of option keys
b8c6a15 Clear items in ComboBox only if changed (#10924)
42545ac Fix NPE if there's no query in the URI (#11836)
Change-Id: I2e50ba59b45720a879c6e476333369523a730b9c
11 files changed, 543 insertions, 77 deletions
diff --git a/client/src/com/vaadin/client/ui/VFilterSelect.java b/client/src/com/vaadin/client/ui/VFilterSelect.java index 05535686d5..e08fbf8ab6 100644 --- a/client/src/com/vaadin/client/ui/VFilterSelect.java +++ b/client/src/com/vaadin/client/ui/VFilterSelect.java @@ -153,8 +153,8 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, * * @return The key of the item */ - public int getOptionKey() { - return Integer.parseInt(key); + public String getOptionKey() { + return key; } /** @@ -174,6 +174,27 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, public void execute() { onSuggestionSelected(this); } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof FilterSelectSuggestion)) { + return false; + } + FilterSelectSuggestion other = (FilterSelectSuggestion) obj; + if ((key == null && other.key != null) + || (key != null && !key.equals(other.key))) { + return false; + } + if ((caption == null && other.caption != null) + || (caption != null && !caption.equals(other.caption))) { + return false; + } + if ((iconUri == null && other.iconUri != null) + || (iconUri != null && !iconUri.equals(other.iconUri))) { + return false; + } + return true; + } } /** @@ -1299,7 +1320,7 @@ public class VFilterSelect extends Composite implements Field, KeyDownHandler, newKey = ""; } else { // normal selection - newKey = String.valueOf(suggestion.getOptionKey()); + newKey = suggestion.getOptionKey(); } String text = suggestion.getReplacementString(); diff --git a/client/src/com/vaadin/client/ui/VScrollTable.java b/client/src/com/vaadin/client/ui/VScrollTable.java index d9dd542b15..8705a826cc 100644 --- a/client/src/com/vaadin/client/ui/VScrollTable.java +++ b/client/src/com/vaadin/client/ui/VScrollTable.java @@ -60,6 +60,7 @@ import com.google.gwt.event.dom.client.ScrollEvent; import com.google.gwt.event.dom.client.ScrollHandler; import com.google.gwt.event.logical.shared.CloseEvent; import com.google.gwt.event.logical.shared.CloseHandler; +import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; @@ -556,15 +557,24 @@ public class VScrollTable extends FlowPanel implements HasWidgets, * <p> * For internal use only. May be removed or replaced in the future. */ - public class ContextMenuDetails { + public class ContextMenuDetails implements CloseHandler<PopupPanel> { public String rowKey; public int left; public int top; + HandlerRegistration closeRegistration; - public ContextMenuDetails(String rowKey, int left, int top) { + public ContextMenuDetails(VContextMenu menu, String rowKey, int left, + int top) { this.rowKey = rowKey; this.left = left; this.top = top; + this.closeRegistration = menu.addCloseHandler(this); + } + + @Override + public void onClose(CloseEvent<PopupPanel> event) { + contextMenu = null; + closeRegistration.removeHandler(); } } @@ -2104,6 +2114,15 @@ public class VScrollTable extends FlowPanel implements HasWidgets, * might have been (incorrectly) calculated earlier */ + /* + * TreeTable updates stuff in a funky order, so we must set the + * height as zero here before doing the real update to make it + * realize that there is no content, + */ + if (pageLength == totalRows && pageLength == 0) { + scrollBody.setHeight("0px"); + } + int bodyHeight; if (pageLength == totalRows) { /* @@ -4796,8 +4815,20 @@ public class VScrollTable extends FlowPanel implements HasWidgets, prepx = 0; } preSpacer.getStyle().setPropertyPx("height", prepx); - int postpx = measureRowHeightOffset(totalRows - 1) - - measureRowHeightOffset(lastRendered); + int postpx; + if (pageLength == 0 && totalRows == pageLength) { + /* + * TreeTable depends on having lastRendered out of sync in some + * situations, which makes this method miss the special + * situation in which one row worth of post spacer to be added + * if there are no rows in the table. #9203 + */ + postpx = measureRowHeightOffset(1); + } else { + postpx = measureRowHeightOffset(totalRows - 1) + - measureRowHeightOffset(lastRendered); + } + if (postpx < 0) { postpx = 0; } @@ -6000,15 +6031,20 @@ public class VScrollTable extends FlowPanel implements HasWidgets, public void showContextMenu(Event event) { if (enabled && actionKeys != null) { // Show context menu if there are registered action handlers - int left = Util.getTouchOrMouseClientX(event); - int top = Util.getTouchOrMouseClientY(event); - top += Window.getScrollTop(); - left += Window.getScrollLeft(); - contextMenu = new ContextMenuDetails(getKey(), left, top); - client.getContextMenu().showAt(this, left, top); + int left = Util.getTouchOrMouseClientX(event) + + Window.getScrollLeft(); + int top = Util.getTouchOrMouseClientY(event) + + Window.getScrollTop(); + showContextMenu(left, top); } } + public void showContextMenu(int left, int top) { + VContextMenu menu = client.getContextMenu(); + contextMenu = new ContextMenuDetails(menu, getKey(), left, top); + menu.showAt(this, left, top); + } + /** * Has the row been selected? * diff --git a/client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java b/client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java index e96d27032b..345bdc0cbb 100644 --- a/client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java +++ b/client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java @@ -15,7 +15,9 @@ */ package com.vaadin.client.ui.combobox; +import java.util.ArrayList; import java.util.Iterator; +import java.util.List; import com.vaadin.client.ApplicationConnection; import com.vaadin.client.Paintable; @@ -98,24 +100,6 @@ public class ComboBoxConnector extends AbstractFieldConnector implements getWidget().allowNewItem = uidl.hasAttribute("allownewitem"); getWidget().lastNewItemString = null; - getWidget().currentSuggestions.clear(); - if (!getWidget().waitingForFilteringResponse) { - /* - * Clear the current suggestions as the server response always - * includes the new ones. Exception is when filtering, then we need - * to retain the value if the user does not select any of the - * options matching the filter. - */ - getWidget().currentSuggestion = null; - /* - * Also ensure no old items in menu. Unless cleared the old values - * may cause odd effects on blur events. Suggestions in menu might - * not necessary exist in select at all anymore. - */ - getWidget().suggestionPopup.menu.clearItems(); - - } - final UIDL options = uidl.getChildUIDL(0); if (uidl.hasAttribute("totalMatches")) { getWidget().totalMatches = uidl.getIntAttribute("totalMatches"); @@ -123,55 +107,52 @@ public class ComboBoxConnector extends AbstractFieldConnector implements getWidget().totalMatches = 0; } + List<FilterSelectSuggestion> newSuggestions = new ArrayList<FilterSelectSuggestion>(); + for (final Iterator<?> i = options.getChildIterator(); i.hasNext();) { final UIDL optionUidl = (UIDL) i.next(); final FilterSelectSuggestion suggestion = getWidget().new FilterSelectSuggestion( optionUidl); - getWidget().currentSuggestions.add(suggestion); - if (optionUidl.hasAttribute("selected")) { - if (!getWidget().waitingForFilteringResponse - || getWidget().popupOpenerClicked) { - String newSelectedOptionKey = Integer.toString(suggestion - .getOptionKey()); - if (!newSelectedOptionKey - .equals(getWidget().selectedOptionKey) - || suggestion.getReplacementString().equals( - getWidget().tb.getText())) { - // Update text field if we've got a new selection - // Also update if we've got the same text to retain old - // text selection behavior - getWidget().setPromptingOff( - suggestion.getReplacementString()); - getWidget().selectedOptionKey = newSelectedOptionKey; - } - } - getWidget().currentSuggestion = suggestion; - getWidget().setSelectedItemIcon(suggestion.getIconUri()); + newSuggestions.add(suggestion); + } + + // only close the popup if the suggestions list has actually changed + boolean suggestionsChanged = !getWidget().initDone + || !newSuggestions.equals(getWidget().currentSuggestions); + + if (suggestionsChanged) { + getWidget().currentSuggestions.clear(); + + if (!getWidget().waitingForFilteringResponse) { + /* + * Clear the current suggestions as the server response always + * includes the new ones. Exception is when filtering, then we + * need to retain the value if the user does not select any of + * the options matching the filter. + */ + getWidget().currentSuggestion = null; + /* + * Also ensure no old items in menu. Unless cleared the old + * values may cause odd effects on blur events. Suggestions in + * menu might not necessary exist in select at all anymore. + */ + getWidget().suggestionPopup.menu.clearItems(); + + } + + for (FilterSelectSuggestion suggestion : newSuggestions) { + getWidget().currentSuggestions.add(suggestion); } } - if ((!getWidget().waitingForFilteringResponse || getWidget().popupOpenerClicked) - && uidl.hasVariable("selected") - && uidl.getStringArrayVariable("selected").length == 0) { - // select nulled - if (!getWidget().waitingForFilteringResponse - || !getWidget().popupOpenerClicked) { - if (!getWidget().focused) { - /* - * client.updateComponent overwrites all styles so we must - * ALWAYS set the prompting style at this point, even though - * we think it has been set already... - */ - getWidget().prompting = false; - getWidget().setPromptingOn(); - } else { - // we have focus in field, prompting can't be set on, - // instead just clear the input - getWidget().tb.setValue(""); - } + // handle selection (null or a single value) + if (uidl.hasVariable("selected")) { + String[] selectedKeys = uidl.getStringArrayVariable("selected"); + if (selectedKeys.length > 0) { + performSelection(selectedKeys[0]); + } else { + resetSelection(); } - getWidget().setSelectedItemIcon(null); - getWidget().selectedOptionKey = null; } if (getWidget().waitingForFilteringResponse @@ -230,6 +211,55 @@ public class ComboBoxConnector extends AbstractFieldConnector implements getWidget().initDone = true; } + private void performSelection(String selectedKey) { + // some item selected + for (FilterSelectSuggestion suggestion : getWidget().currentSuggestions) { + String suggestionKey = suggestion.getOptionKey(); + if (suggestionKey.equals(selectedKey)) { + if (!getWidget().waitingForFilteringResponse + || getWidget().popupOpenerClicked) { + if (!suggestionKey.equals(getWidget().selectedOptionKey) + || suggestion.getReplacementString().equals( + getWidget().tb.getText())) { + // Update text field if we've got a new + // selection + // Also update if we've got the same text to + // retain old text selection behavior + getWidget().setPromptingOff( + suggestion.getReplacementString()); + getWidget().selectedOptionKey = suggestionKey; + } + } + getWidget().currentSuggestion = suggestion; + getWidget().setSelectedItemIcon(suggestion.getIconUri()); + // only a single item can be selected + break; + } + } + } + + private void resetSelection() { + if (!getWidget().waitingForFilteringResponse + || getWidget().popupOpenerClicked) { + // select nulled + if (!getWidget().focused) { + /* + * client.updateComponent overwrites all styles so we must + * ALWAYS set the prompting style at this point, even though we + * think it has been set already... + */ + getWidget().prompting = false; + getWidget().setPromptingOn(); + } else { + // we have focus in field, prompting can't be set on, instead + // just clear the input + getWidget().tb.setValue(""); + } + getWidget().setSelectedItemIcon(null); + getWidget().selectedOptionKey = null; + } + } + @Override public VFilterSelect getWidget() { return (VFilterSelect) super.getWidget(); diff --git a/client/src/com/vaadin/client/ui/table/TableConnector.java b/client/src/com/vaadin/client/ui/table/TableConnector.java index c8b4af83f2..36587ffe4d 100644 --- a/client/src/com/vaadin/client/ui/table/TableConnector.java +++ b/client/src/com/vaadin/client/ui/table/TableConnector.java @@ -364,9 +364,8 @@ public class TableConnector extends AbstractHasComponentsConnector implements Widget w = iterator.next(); VScrollTableRow row = (VScrollTableRow) w; if (row.getKey().equals(savedContextMenu.rowKey)) { - getWidget().contextMenu = savedContextMenu; - getConnection().getContextMenu().showAt(row, - savedContextMenu.left, savedContextMenu.top); + row.showContextMenu(savedContextMenu.left, + savedContextMenu.top); } } } diff --git a/server/src/com/vaadin/ui/ComboBox.java b/server/src/com/vaadin/ui/ComboBox.java index 0f42749acd..88e895df82 100644 --- a/server/src/com/vaadin/ui/ComboBox.java +++ b/server/src/com/vaadin/ui/ComboBox.java @@ -262,8 +262,8 @@ public class ComboBox extends AbstractSelect implements target.addAttribute("nullselection", true); } target.addAttribute("key", key); - if (isSelected(id) && keyIndex < selectedKeys.length) { - target.addAttribute("selected", true); + if (keyIndex < selectedKeys.length && isSelected(id)) { + // at most one item can be selected at a time selectedKeys[keyIndex++] = key; } target.endTag("so"); diff --git a/tests/testbench/com/vaadin/tests/components/treetable/RowHeightWithoutRows.html b/tests/testbench/com/vaadin/tests/components/treetable/RowHeightWithoutRows.html new file mode 100644 index 0000000000..e8cb0ccfe6 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/treetable/RowHeightWithoutRows.html @@ -0,0 +1,47 @@ +<?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>New Test</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">New Test</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.treetable.RowHeightWithoutRows?restartApplication=</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>two</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentstreetableRowHeightWithoutRows::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[2]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>empty</td> +</tr> +<tr> + <td>click</td> + <td>vaadin=runcomvaadintestscomponentstreetableRowHeightWithoutRows::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[3]/VButton[0]/domChild[0]/domChild[0]</td> + <td></td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>five</td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/components/treetable/RowHeightWithoutRows.java b/tests/testbench/com/vaadin/tests/components/treetable/RowHeightWithoutRows.java new file mode 100644 index 0000000000..5e94fc1270 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/treetable/RowHeightWithoutRows.java @@ -0,0 +1,87 @@ +package com.vaadin.tests.components.treetable; + +import com.vaadin.data.util.BeanItemContainer; +import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.Button.ClickListener; +import com.vaadin.ui.TreeTable; + +public class RowHeightWithoutRows extends TestBase { + + private TreeTable treeTable = new TreeTable(); + + private BeanItemContainer<User> container = new BeanItemContainer<User>( + User.class); + + @Override + public void setup() { + treeTable.setContainerDataSource(container); + treeTable.setPageLength(0); + + addComponent(treeTable); + + Button refresh = new Button("Add two elements"); + addComponent(refresh); + refresh.addListener(new ClickListener() { + public void buttonClick(ClickEvent event) { + addTwoElements(); + } + }); + + Button reset = new Button("Reset"); + addComponent(reset); + reset.addListener(new ClickListener() { + public void buttonClick(ClickEvent event) { + container.removeAllItems(); + } + }); + + Button refresh5 = new Button("Add five elements"); + addComponent(refresh5); + refresh5.addListener(new ClickListener() { + public void buttonClick(ClickEvent event) { + container.addBean(new User("John", "Doe")); + container.addBean(new User("Mark", "Twain")); + container.addBean(new User("M", "T")); + container.addBean(new User("J", "D")); + container.addBean(new User("J", "T")); + } + }); + addTwoElements(); + } + + private void addTwoElements() { + container.addBean(new User("John", "Doe")); + container.addBean(new User("Mark", "Twain")); + } + + public static class User { + private String firstName; + + private String lastName; + + public User(String firstName, String lastName) { + this.firstName = firstName; + this.lastName = lastName; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + } + + @Override + protected String getDescription() { + return "Reseting the tree table and then adding five elements should properly update the height of the TreeTable"; + } + + @Override + protected Integer getTicketNumber() { + return Integer.valueOf(9203); + } +}
\ No newline at end of file diff --git a/uitest/src/com/vaadin/tests/VerifyJreVersion.html b/uitest/src/com/vaadin/tests/VerifyJreVersion.html new file mode 100644 index 0000000000..abf53883c1 --- /dev/null +++ b/uitest/src/com/vaadin/tests/VerifyJreVersion.html @@ -0,0 +1,26 @@ +<?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="" /> +<title>New Test</title> +</head> +<body> +<table cellpadding="1" cellspacing="1" border="1"> +<thead> +<tr><td rowspan="1" colspan="3">New Test</td></tr> +</thead><tbody> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.VerifyJreVersion?restartApplication</td> + <td></td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestsVerifyJreVersion::/VVerticalLayout[0]/VVerticalLayout[0]/VLabel[0]</td> + <td>Using Java 1.6.0_32 by Sun Microsystems Inc.</td> +</tr> +</tbody></table> +</body> +</html> diff --git a/uitest/src/com/vaadin/tests/VerifyJreVersion.java b/uitest/src/com/vaadin/tests/VerifyJreVersion.java new file mode 100644 index 0000000000..fe3e4bd870 --- /dev/null +++ b/uitest/src/com/vaadin/tests/VerifyJreVersion.java @@ -0,0 +1,45 @@ +/* + * Copyright 2000-2013 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +/** + * + */ +package com.vaadin.tests; + +import com.vaadin.server.VaadinRequest; +import com.vaadin.tests.components.AbstractTestUI; +import com.vaadin.ui.Label; + +public class VerifyJreVersion extends AbstractTestUI { + + @Override + protected void setup(VaadinRequest request) { + String jreVersion = "Using Java " + System.getProperty("java.version") + + " by " + System.getProperty("java.vendor"); + addComponent(new Label(jreVersion)); + } + + @Override + protected String getTestDescription() { + return "Test used to detect when the JRE used to run these tests have changed."; + } + + @Override + protected Integer getTicketNumber() { + return Integer.valueOf(11835); + } + +} diff --git a/uitest/src/com/vaadin/tests/components/AbstractTestUI.java b/uitest/src/com/vaadin/tests/components/AbstractTestUI.java index a044b52f18..ec6cf0c57d 100644 --- a/uitest/src/com/vaadin/tests/components/AbstractTestUI.java +++ b/uitest/src/com/vaadin/tests/components/AbstractTestUI.java @@ -1,10 +1,16 @@ package com.vaadin.tests.components; +import java.io.File; + +import com.vaadin.annotations.Widgetset; import com.vaadin.server.VaadinRequest; +import com.vaadin.server.VaadinServlet; import com.vaadin.server.WebBrowser; import com.vaadin.shared.ui.label.ContentMode; import com.vaadin.ui.Component; import com.vaadin.ui.Label; +import com.vaadin.ui.Notification; +import com.vaadin.ui.Notification.Type; import com.vaadin.ui.UI; import com.vaadin.ui.VerticalLayout; @@ -27,9 +33,68 @@ public abstract class AbstractTestUI extends UI { rootLayout.addComponent(layout); ((VerticalLayout) getContent()).setExpandRatio(layout, 1); + warnIfWidgetsetMaybeNotCompiled(); + setup(request); } + protected void warnIfWidgetsetMaybeNotCompiled() { + // Ignore if using debug mode + String query = getPage().getLocation().getQuery(); + if (query != null && query.matches(".*[&?]gwt\\.codesvr.*")) { + return; + } + + // Find out the widgetset of this UI based on @Widgetset annotation + Class<?> currentType = getClass(); + String usedWidgetset = VaadinServlet.DEFAULT_WIDGETSET; + while (currentType != Object.class) { + Widgetset annotation = currentType.getAnnotation(Widgetset.class); + if (annotation != null) { + usedWidgetset = annotation.value(); + break; + } else { + currentType = currentType.getSuperclass(); + } + } + + // Assuming the same folder structure as in git repo + // Assuming project root is the working dir of this process + File widgetsetsFolder = new File("WebContent/VAADIN/widgetsets"); + if (!widgetsetsFolder.isDirectory()) { + return; + } + + // Find the most newly compiled widgetset + long newestWidgetsetTimestamp = -1; + String newestWidgetsetName = null; + File[] children = widgetsetsFolder.listFiles(); + for (File child : children) { + if (!child.isDirectory() || child.getName().equals("WEB-INF")) { + continue; + } + long lastModified = child.lastModified(); + if (lastModified > newestWidgetsetTimestamp) { + newestWidgetsetTimestamp = lastModified; + newestWidgetsetName = child.getName(); + } + } + + // Compare to currently used widgetset, with a 30 minute grace period + File currentWidgetsetFolder = new File(widgetsetsFolder, usedWidgetset); + long currentWidgetsetTimestamp = currentWidgetsetFolder.lastModified(); + int halfHour = 30 * 60 * 1000; + if (currentWidgetsetTimestamp + halfHour < newestWidgetsetTimestamp) { + Notification + .show("The currently used widgetset (" + + usedWidgetset + + ") was compiled long before the most recently compiled one (" + + newestWidgetsetName + + "). Are you sure you have compiled the right widgetset?", + Type.WARNING_MESSAGE); + } + } + private VerticalLayout layout; protected VerticalLayout getLayout() { diff --git a/uitest/src/com/vaadin/tests/components/combobox/ComboPushTiming.java b/uitest/src/com/vaadin/tests/components/combobox/ComboPushTiming.java new file mode 100644 index 0000000000..fe2cffdc4c --- /dev/null +++ b/uitest/src/com/vaadin/tests/components/combobox/ComboPushTiming.java @@ -0,0 +1,110 @@ +package com.vaadin.tests.components.combobox; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import com.vaadin.data.util.ObjectProperty; +import com.vaadin.event.FieldEvents; +import com.vaadin.event.FieldEvents.BlurEvent; +import com.vaadin.event.FieldEvents.FocusEvent; +import com.vaadin.server.VaadinSession; +import com.vaadin.shared.ui.label.ContentMode; +import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.ComboBox; +import com.vaadin.ui.Label; +import com.vaadin.ui.ProgressIndicator; +import com.vaadin.ui.TextField; + +public class ComboPushTiming extends TestBase { + + private int counter = 0; + private final MyExecutor executor = new MyExecutor(); + + @Override + protected void setup() { + + List<String> list = new ArrayList<String>(); + for (int i = 0; i < 100; i++) { + list.add("Item " + i); + } + + final ComboBox cb = new ComboBox("Combobox", list); + cb.setImmediate(true); + cb.setInputPrompt("Enter text"); + cb.setDescription("Some Combobox"); + addComponent(cb); + + final ObjectProperty<String> log = new ObjectProperty<String>(""); + + cb.addListener(new FieldEvents.FocusListener() { + @Override + public void focus(FocusEvent event) { + log.setValue(log.getValue().toString() + "<br>" + counter + + ": Focus event!"); + counter++; + changeValue(cb); + } + }); + + cb.addListener(new FieldEvents.BlurListener() { + @Override + public void blur(BlurEvent event) { + log.setValue(log.getValue().toString() + "<br>" + counter + + ": Blur event!"); + counter++; + } + }); + + TextField field = new TextField("Some textfield"); + field.setImmediate(true); + addComponent(field); + + Label output = new Label(log); + output.setCaption("Events:"); + + output.setContentMode(ContentMode.HTML); + addComponent(output); + + ProgressIndicator progressIndicator = new ProgressIndicator(); + addComponent(progressIndicator); + progressIndicator.setPollingInterval(3000); + } + + private void changeValue(final ComboBox cb) { + executor.execute(new Runnable() { + public void run() { + VaadinSession.getCurrent().lock(); + try { + cb.setEnabled(true); + cb.setValue("B"); + cb.setEnabled(true); + + // If this isn't sent by push or poll in the background, the + // problem will go away + } finally { + VaadinSession.getCurrent().unlock(); + } + } + }); + } + + class MyExecutor extends ThreadPoolExecutor { + public MyExecutor() { + super(5, 20, 20, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); + } + } + + @Override + protected String getDescription() { + return "When an update is received while the popup is open, the suggestion popup blurs away"; + } + + @Override + protected Integer getTicketNumber() { + return 10924; + } + +} |