diff options
12 files changed, 664 insertions, 94 deletions
diff --git a/WebContent/release-notes.html b/WebContent/release-notes.html index b05a5e1548..574c3792ef 100644 --- a/WebContent/release-notes.html +++ b/WebContent/release-notes.html @@ -481,11 +481,11 @@ </p> <ul> - <li>Mozilla Firefox 3-6</li> + <li>Mozilla Firefox 3-8</li> <li>Internet Explorer 6-9</li> <li>Safari 4-5</li> <li>Opera 10-11</li> - <li>Google Chrome 13</li> + <li>Google Chrome 13-15</li> </ul> <h2 id="vaadinontheweb">Vaadin on the Web</h2> diff --git a/src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java b/src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java index 7c3d3066ce..66200cbe8c 100644 --- a/src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java +++ b/src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java @@ -7,8 +7,10 @@ package com.vaadin.terminal.gwt.client.ui; import java.util.ArrayList; import java.util.Collection; import java.util.Date; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Set; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; @@ -49,6 +51,7 @@ import com.vaadin.terminal.gwt.client.Focusable; import com.vaadin.terminal.gwt.client.Paintable; import com.vaadin.terminal.gwt.client.UIDL; import com.vaadin.terminal.gwt.client.Util; +import com.vaadin.terminal.gwt.client.VConsole; import com.vaadin.terminal.gwt.client.VTooltip; /** @@ -56,6 +59,7 @@ import com.vaadin.terminal.gwt.client.VTooltip; * * TODO needs major refactoring (to be extensible etc) */ +@SuppressWarnings("deprecation") public class VFilterSelect extends Composite implements Paintable, Field, KeyDownHandler, KeyUpHandler, ClickHandler, FocusHandler, BlurHandler, Focusable { @@ -96,7 +100,15 @@ public class VFilterSelect extends Composite implements Paintable, Field, sb.append(Util.escapeAttribute(iconUri)); sb.append("\" alt=\"\" class=\"v-icon\" />"); } - sb.append("<span>" + Util.escapeHTML(caption) + "</span>"); + String content; + if ("".equals(caption)) { + // Ensure that empty options use the same height as other + // options and are not collapsed (#7506) + content = " "; + } else { + content = Util.escapeHTML(caption); + } + sb.append("<span>" + content + "</span>"); return sb.toString(); } @@ -286,7 +298,7 @@ public class VFilterSelect extends Composite implements Paintable, Field, .getText().length() - lastFilter.length()); } else if (hasNextPage()) { - lastIndex = index - 1; // save for paging + selectPopupItemWhenResponseIsReceived = Select.FIRST; filterOptions(currentPage + 1, lastFilter); } } @@ -305,7 +317,7 @@ public class VFilterSelect extends Composite implements Paintable, Field, .getText().length() - lastFilter.length()); } else if (index == -1) { if (currentPage > 0) { - lastIndex = index + 1; // save for paging + selectPopupItemWhenResponseIsReceived = Select.LAST; filterOptions(currentPage - 1, lastFilter); } } else { @@ -330,7 +342,20 @@ public class VFilterSelect extends Composite implements Paintable, Field, @Override public void run() { if (pagesToScroll != 0) { - filterOptions(currentPage + pagesToScroll, lastFilter); + if (!waitingForFilteringResponse) { + /* + * Avoid scrolling while we are waiting for a response + * because otherwise the waiting flag will be reset in + * the first response and the second response will be + * ignored, causing an empty popup... + * + * As long as the scrolling delay is suitable + * double/triple clicks will work by scrolling two or + * three pages at a time and this should not be a + * problem. + */ + filterOptions(currentPage + pagesToScroll, lastFilter); + } pagesToScroll = 0; } } @@ -339,7 +364,7 @@ public class VFilterSelect extends Composite implements Paintable, Field, if (currentPage + pagesToScroll > 0) { pagesToScroll--; cancel(); - schedule(100); + schedule(200); } } @@ -348,7 +373,7 @@ public class VFilterSelect extends Composite implements Paintable, Field, * pageLength) { pagesToScroll++; cancel(); - schedule(100); + schedule(200); } } } @@ -538,6 +563,13 @@ public class VFilterSelect extends Composite implements Paintable, Field, public class SuggestionMenu extends MenuBar implements SubPartAware, LoadHandler { + /** + * Tracks the item that is currently selected using the keyboard. This + * is need only because mouseover changes the selection and we do not + * want to use that selection when pressing enter to select the item. + */ + private MenuItem keyboardSelectedItem; + private VLazyExecutor delayedImageLoadExecutioner = new VLazyExecutor( 100, new ScheduledCommand() { @@ -584,6 +616,10 @@ public class VFilterSelect extends Composite implements Paintable, Field, */ public void setSuggestions( Collection<FilterSelectSuggestion> suggestions) { + // Reset keyboard selection when contents is updated to avoid + // reusing old, invalid data + setKeyboardSelectedItem(null); + clearItems(); final Iterator<FilterSelectSuggestion> it = suggestions.iterator(); while (it.hasNext()) { @@ -623,8 +659,8 @@ public class VFilterSelect extends Composite implements Paintable, Field, return; } - selecting = filtering; - if (!filtering) { + updateSelectionWhenReponseIsReceived = waitingForFilteringResponse; + if (!waitingForFilteringResponse) { doPostFilterSelectedItemAction(); } } @@ -636,7 +672,7 @@ public class VFilterSelect extends Composite implements Paintable, Field, final MenuItem item = getSelectedItem(); final String enteredItemValue = tb.getText(); - selecting = false; + updateSelectionWhenReponseIsReceived = false; // check for exact match in menu int p = getItems().size(); @@ -737,6 +773,25 @@ public class VFilterSelect extends Composite implements Paintable, Field, delayedImageLoadExecutioner.trigger(); } + + public void selectFirstItem() { + MenuItem firstItem = getItems().get(0); + selectItem(firstItem); + } + + private MenuItem getKeyboardSelectedItem() { + return keyboardSelectedItem; + } + + private void setKeyboardSelectedItem(MenuItem firstItem) { + keyboardSelectedItem = firstItem; + } + + public void selectLastItem() { + List<MenuItem> items = getItems(); + MenuItem lastItem = items.get(items.size() - 1); + selectItem(lastItem); + } } public static final int FILTERINGMODE_OFF = 0; @@ -748,6 +803,8 @@ public class VFilterSelect extends Composite implements Paintable, Field, protected int pageLength = 10; + private boolean enableDebug = false; + private final FlowPanel panel = new FlowPanel(); /** @@ -821,19 +878,24 @@ public class VFilterSelect extends Composite implements Paintable, Field, * A collection of available suggestions (options) as received from the * server. */ - private final Collection<FilterSelectSuggestion> currentSuggestions = new ArrayList<FilterSelectSuggestion>(); + private final List<FilterSelectSuggestion> currentSuggestions = new ArrayList<FilterSelectSuggestion>(); private boolean immediate; private String selectedOptionKey; - private boolean filtering = false; - private boolean selecting = false; - private boolean tabPressed = false; + private boolean waitingForFilteringResponse = false; + private boolean updateSelectionWhenReponseIsReceived = false; + private boolean tabPressedWhenPopupOpen = false; private boolean initDone = false; private String lastFilter = ""; - private int lastIndex = -1; // last selected index when using arrows + + private enum Select { + NONE, FIRST, LAST + }; + + private Select selectPopupItemWhenResponseIsReceived = Select.NONE; /** * The current suggestion selected from the dropdown. This is one of the @@ -968,7 +1030,7 @@ public class VFilterSelect extends Composite implements Paintable, Field, } } - filtering = true; + waitingForFilteringResponse = true; client.updateVariable(paintableId, "filter", filter, false); client.updateVariable(paintableId, "page", page, true); lastFilter = filter; @@ -1032,14 +1094,13 @@ public class VFilterSelect extends Composite implements Paintable, Field, inputPrompt = ""; } - suggestionPopup.setPagingEnabled(true); suggestionPopup.updateStyleNames(uidl); allowNewItem = uidl.hasAttribute("allownewitem"); lastNewItemString = null; currentSuggestions.clear(); - if (!filtering) { + if (!waitingForFilteringResponse) { /* * Clear the current suggestions as the server response always * includes the new ones. Exception is when filtering, then we need @@ -1059,6 +1120,8 @@ public class VFilterSelect extends Composite implements Paintable, Field, final UIDL options = uidl.getChildUIDL(0); if (uidl.hasAttribute("totalMatches")) { totalMatches = uidl.getIntAttribute("totalMatches"); + } else { + totalMatches = 0; } // used only to calculate minimum popup width @@ -1070,7 +1133,7 @@ public class VFilterSelect extends Composite implements Paintable, Field, optionUidl); currentSuggestions.add(suggestion); if (optionUidl.hasAttribute("selected")) { - if (!filtering || popupOpenerClicked) { + if (!waitingForFilteringResponse || popupOpenerClicked) { String newSelectedOptionKey = Integer.toString(suggestion .getOptionKey()); if (!newSelectedOptionKey.equals(selectedOptionKey) @@ -1094,10 +1157,11 @@ public class VFilterSelect extends Composite implements Paintable, Field, captions += Util.escapeHTML(suggestion.getReplacementString()); } - if ((!filtering || popupOpenerClicked) && uidl.hasVariable("selected") + if ((!waitingForFilteringResponse || popupOpenerClicked) + && uidl.hasVariable("selected") && uidl.getStringArrayVariable("selected").length == 0) { // select nulled - if (!filtering || !popupOpenerClicked) { + if (!waitingForFilteringResponse || !popupOpenerClicked) { if (!focused) { /* * client.updateComponent overwrites all styles so we must @@ -1115,41 +1179,35 @@ public class VFilterSelect extends Composite implements Paintable, Field, selectedOptionKey = null; } - if (filtering + if (waitingForFilteringResponse && lastFilter.toLowerCase().equals( uidl.getStringVariable("filter"))) { suggestionPopup.showSuggestions(currentSuggestions, currentPage, totalMatches); - filtering = false; - if (!popupOpenerClicked && lastIndex != -1) { + waitingForFilteringResponse = false; + if (!popupOpenerClicked + && selectPopupItemWhenResponseIsReceived != Select.NONE) { // we're paging w/ arrows - MenuItem activeMenuItem; - if (lastIndex == 0) { - // going up, select last item - int lastItem = pageLength - 1; - List<MenuItem> items = suggestionPopup.menu.getItems(); - /* - * The first page can contain less than 10 items if the null - * selection item is filtered away - */ - if (lastItem >= items.size()) { - lastItem = items.size() - 1; - } - activeMenuItem = items.get(lastItem); - suggestionPopup.menu.selectItem(activeMenuItem); + if (selectPopupItemWhenResponseIsReceived == Select.LAST) { + suggestionPopup.menu.selectLastItem(); } else { - // going down, select first item - activeMenuItem = suggestionPopup.menu.getItems().get(0); - suggestionPopup.menu.selectItem(activeMenuItem); + suggestionPopup.menu.selectFirstItem(); } + // This is used for paging so we update the keyboard selection + // variable as well. + MenuItem activeMenuItem = suggestionPopup.menu + .getSelectedItem(); + suggestionPopup.menu.setKeyboardSelectedItem(activeMenuItem); + + // Update text field to contain the correct text setTextboxText(activeMenuItem.getText()); tb.setSelectionRange(lastFilter.length(), activeMenuItem .getText().length() - lastFilter.length()); - lastIndex = -1; // reset + selectPopupItemWhenResponseIsReceived = Select.NONE; // reset } - if (selecting) { + if (updateSelectionWhenReponseIsReceived) { suggestionPopup.menu.doPostFilterSelectedItemAction(); } } @@ -1261,7 +1319,7 @@ public class VFilterSelect extends Composite implements Paintable, Field, * The suggestion that just got selected. */ public void onSuggestionSelected(FilterSelectSuggestion suggestion) { - selecting = false; + updateSelectionWhenReponseIsReceived = false; currentSuggestion = suggestion; String newKey; @@ -1329,6 +1387,15 @@ public class VFilterSelect extends Composite implements Paintable, Field, marginTop + "px"); } + private static Set<Integer> navigationKeyCodes = new HashSet<Integer>(); + static { + navigationKeyCodes.add(KeyCodes.KEY_DOWN); + navigationKeyCodes.add(KeyCodes.KEY_UP); + navigationKeyCodes.add(KeyCodes.KEY_PAGEDOWN); + navigationKeyCodes.add(KeyCodes.KEY_PAGEUP); + navigationKeyCodes.add(KeyCodes.KEY_ENTER); + } + /* * (non-Javadoc) * @@ -1338,34 +1405,39 @@ public class VFilterSelect extends Composite implements Paintable, Field, */ public void onKeyDown(KeyDownEvent event) { if (enabled && !readonly) { - if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) { - // Same reaction to enter no matter on whether the popup is open - if (suggestionPopup.isAttached()) { - filterOptions(currentPage); - } else if (currentSuggestion != null - && tb.getText().equals( - currentSuggestion.getReplacementString())) { - // Retain behavior from #6686 by returning without stopping - // propagation if there's nothing to do - return; - } - if (currentSuggestions.size() == 1 && !allowNewItem) { - // If there is only one suggestion, select that - suggestionPopup.menu.selectItem(suggestionPopup.menu - .getItems().get(0)); - } - suggestionPopup.menu.doSelectedItemAction(); + int keyCode = event.getNativeKeyCode(); + debug("key down: " + keyCode); + if (waitingForFilteringResponse + && navigationKeyCodes.contains(keyCode)) { + /* + * Keyboard navigation events should not be handled while we are + * waiting for a response. This avoids flickering, disappearing + * items, wrongly interpreted responses and more. + */ + debug("Ignoring " + keyCode + + " because we are waiting for a filtering response"); + DOM.eventPreventDefault(DOM.eventGetCurrentEvent()); event.stopPropagation(); return; - } else if (suggestionPopup.isAttached()) { + } + + if (suggestionPopup.isAttached()) { + debug("Keycode " + keyCode + " target is popup"); popupKeyDown(event); } else { + debug("Keycode " + keyCode + " target is text field"); inputFieldKeyDown(event); } } } + private void debug(String string) { + if (enableDebug) { + VConsole.error(string); + } + } + /** * Triggered when a key is pressed in the text box * @@ -1378,17 +1450,31 @@ public class VFilterSelect extends Composite implements Paintable, Field, case KeyCodes.KEY_UP: case KeyCodes.KEY_PAGEDOWN: case KeyCodes.KEY_PAGEUP: - if (!suggestionPopup.isAttached()) { - // open popup as from gadget - filterOptions(-1, ""); - lastFilter = ""; - tb.selectAll(); - } + // open popup as from gadget + filterOptions(-1, ""); + lastFilter = ""; + tb.selectAll(); break; - case KeyCodes.KEY_TAB: - if (suggestionPopup.isAttached()) { - filterOptions(currentPage, tb.getText()); + case KeyCodes.KEY_ENTER: + /* + * This only handles the case when new items is allowed, a text is + * entered, the popup opener button is clicked to close the popup + * and enter is then pressed (see #7560). + */ + if (!allowNewItem) { + return; } + + if (currentSuggestion != null + && tb.getText().equals( + currentSuggestion.getReplacementString())) { + // Retain behavior from #6686 by returning without stopping + // propagation if there's nothing to do + return; + } + suggestionPopup.menu.doSelectedItemAction(); + + event.stopPropagation(); break; } @@ -1406,11 +1492,15 @@ public class VFilterSelect extends Composite implements Paintable, Field, switch (event.getNativeKeyCode()) { case KeyCodes.KEY_DOWN: suggestionPopup.selectNextItem(); + suggestionPopup.menu.setKeyboardSelectedItem(suggestionPopup.menu + .getSelectedItem()); DOM.eventPreventDefault(DOM.eventGetCurrentEvent()); event.stopPropagation(); break; case KeyCodes.KEY_UP: suggestionPopup.selectPrevItem(); + suggestionPopup.menu.setKeyboardSelectedItem(suggestionPopup.menu + .getSelectedItem()); DOM.eventPreventDefault(DOM.eventGetCurrentEvent()); event.stopPropagation(); break; @@ -1427,12 +1517,43 @@ public class VFilterSelect extends Composite implements Paintable, Field, event.stopPropagation(); break; case KeyCodes.KEY_TAB: - if (suggestionPopup.isAttached()) { - tabPressed = true; - filterOptions(currentPage); - } + tabPressedWhenPopupOpen = true; + filterOptions(currentPage); // onBlur() takes care of the rest break; + case KeyCodes.KEY_ESCAPE: + reset(); + event.stopPropagation(); + break; + case KeyCodes.KEY_ENTER: + if (suggestionPopup.menu.getKeyboardSelectedItem() == null) { + /* + * Nothing selected using up/down. Happens e.g. when entering a + * text (causes popup to open) and then pressing enter. + */ + if (!allowNewItem) { + /* + * New items are not allowed: If there is only one + * suggestion, select that. Otherwise do nothing. + */ + if (currentSuggestions.size() == 1) { + onSuggestionSelected(currentSuggestions.get(0)); + } + } else { + // Handle addition of new items. + suggestionPopup.menu.doSelectedItemAction(); + } + } else { + /* + * Get the suggestion that was navigated to using up/down. + */ + currentSuggestion = ((FilterSelectSuggestion) suggestionPopup.menu + .getKeyboardSelectedItem().getCommand()); + onSuggestionSelected(currentSuggestion); + } + + event.stopPropagation(); + break; } } @@ -1455,10 +1576,8 @@ public class VFilterSelect extends Composite implements Paintable, Field, case KeyCodes.KEY_UP: case KeyCodes.KEY_PAGEDOWN: case KeyCodes.KEY_PAGEUP: - ; // NOP - break; case KeyCodes.KEY_ESCAPE: - reset(); + ; // NOP break; default: if (textInputEnabled) { @@ -1617,8 +1736,8 @@ public class VFilterSelect extends Composite implements Paintable, Field, focused = false; if (!readonly) { // much of the TAB handling takes place here - if (tabPressed) { - tabPressed = false; + if (tabPressedWhenPopupOpen) { + tabPressedWhenPopupOpen = false; suggestionPopup.menu.doSelectedItemAction(); suggestionPopup.hide(); } else if (!suggestionPopup.isAttached() diff --git a/src/com/vaadin/ui/Select.java b/src/com/vaadin/ui/Select.java index 7b6fc07e5b..439efdb864 100644 --- a/src/com/vaadin/ui/Select.java +++ b/src/com/vaadin/ui/Select.java @@ -148,7 +148,7 @@ public class Select extends AbstractSelect implements AbstractSelect.Filtering, } // Adds the required attribute - if (isRequired()) { + if (!isReadOnly() && isRequired()) { target.addAttribute("required", true); } diff --git a/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxFiltering.html b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxFiltering.html new file mode 100644 index 0000000000..3de221871d --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxFiltering.html @@ -0,0 +1,62 @@ +<?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.components.combobox.ComboBoxSlow?restartApplication</td> + <td></td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxSlow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td> + <td>92,19</td> +</tr> +<tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxSlow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td> + <td>1</td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>filter-no-match</td> +</tr> +<tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxSlow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td> + <td>Item 12</td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>filter-11-matches-paging</td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>filter-11-matches-page-2</td> +</tr> +<tr> + <td>enterCharacter</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxSlow::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td> + <td>Item 100</td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>filter-2-matches-no-paging</td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxIdenticalItems.html b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxIdenticalItems.html new file mode 100644 index 0000000000..6d18c60038 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxIdenticalItems.html @@ -0,0 +1,112 @@ +<?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.components.combobox.ComboBoxIdenticalItems?restartApplication</td> + <td></td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxIdenticalItems::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td> + <td>66,8</td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxIdenticalItems::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td> + <td>down</td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxIdenticalItems::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td> + <td>down</td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxIdenticalItems::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td> + <td>enter</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxIdenticalItems::PID_SLog_row_0</td> + <td>1. Item one-1 selected</td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxIdenticalItems::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td> + <td>down</td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxIdenticalItems::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td> + <td>down</td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxIdenticalItems::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td> + <td>enter</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxIdenticalItems::PID_SLog_row_0</td> + <td>2. Item one-2 selected</td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxIdenticalItems::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td> + <td>down</td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxIdenticalItems::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td> + <td>down</td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxIdenticalItems::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td> + <td>enter</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxIdenticalItems::PID_SLog_row_0</td> + <td>3. Item two selected</td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxIdenticalItems::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td> + <td>up</td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxIdenticalItems::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td> + <td>up</td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxIdenticalItems::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td> + <td>up</td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxIdenticalItems::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[1]/VFilterSelect[0]/domChild[0]</td> + <td>enter</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxIdenticalItems::PID_SLog_row_0</td> + <td>4. Item one-1 selected</td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxIdenticalItems.java b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxIdenticalItems.java new file mode 100644 index 0000000000..dcd4af58ad --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxIdenticalItems.java @@ -0,0 +1,54 @@ +package com.vaadin.tests.components.combobox;
+
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.data.Property.ValueChangeEvent;
+import com.vaadin.tests.components.TestBase;
+import com.vaadin.tests.util.Log;
+import com.vaadin.ui.ComboBox;
+
+public class ComboBoxIdenticalItems extends TestBase {
+
+ private Log log = new Log(5);
+
+ @Override
+ public void setup() {
+ final ComboBox select = new ComboBox("ComboBox");
+ select.addContainerProperty("caption", String.class, null);
+ Item item = select.addItem("one-1");
+ item.getItemProperty("caption").setValue("One");
+ item = select.addItem("one-2");
+ item.getItemProperty("caption").setValue("One");
+ item = select.addItem("two");
+ item.getItemProperty("caption").setValue("Two");
+ select.setItemCaptionPropertyId("caption");
+ select.setNullSelectionAllowed(false);
+ select.setImmediate(true);
+ select.addListener(new Property.ValueChangeListener() {
+ private static final long serialVersionUID = -7932700771673919620L;
+
+ public void valueChange(ValueChangeEvent event) {
+ log.log("Item " + select.getValue() + " selected");
+
+ }
+ });
+
+ addComponent(log);
+ addComponent(select);
+ }
+
+ @Override
+ protected String getDescription() {
+ return "Keyboard selecting of a value is broken in combobox if two "
+ + "items have the same caption. The first item's id is \"One-1\" "
+ + "while the second one is \"One-2\". Selecting with mouse works "
+ + "as expected but selecting with keyboard always returns the "
+ + "object \"One-1\".";
+ }
+
+ @Override
+ protected Integer getTicketNumber() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
diff --git a/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxInPopup.htm b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxInPopup.htm new file mode 100644 index 0000000000..f943f912e4 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxInPopup.htm @@ -0,0 +1,48 @@ +<?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.components.combobox.ComboBoxInPopup?restartApplication</td> + <td></td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxInPopup::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/ChildComponentContainer[0]/VFilterSelect[0]/domChild[1]</td> + <td>12,13</td> +</tr> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxInPopup::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item1</td> + <td>Yes</td> +</tr> +<tr> + <td>pressSpecialKey</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxInPopup::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item1</td> + <td>esc</td> +</tr> +<!--ensure the sub window is still open but the popup is not--> +<tr> + <td>assertText</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxInPopup::/VWindow[0]/FocusableScrollPanel[0]/VVerticalLayout[0]/domChild[0]/domChild[0]/domChild[0]/domChild[0]</td> + <td>A combo box</td> +</tr> +<tr> + <td>assertElementNotPresent</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxInPopup::Root/VFilterSelect$SuggestionPopup[0]/VFilterSelect$SuggestionMenu[0]#item1</td> + <td></td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxInPopup.java b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxInPopup.java new file mode 100644 index 0000000000..8160fb576e --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxInPopup.java @@ -0,0 +1,50 @@ +package com.vaadin.tests.components.combobox; + +import com.vaadin.event.ShortcutAction.KeyCode; +import com.vaadin.tests.components.TestBase; +import com.vaadin.ui.Button; +import com.vaadin.ui.Button.ClickEvent; +import com.vaadin.ui.ComboBox; +import com.vaadin.ui.Component; +import com.vaadin.ui.Window; + +public class ComboBoxInPopup extends TestBase { + + @Override + protected void setup() { + final Window w = new Window(); + w.getContent().setSizeUndefined(); + w.addComponent(createComboBox()); + Button close = new Button("Close window", new Button.ClickListener() { + + public void buttonClick(ClickEvent event) { + w.getParent().removeWindow(w); + } + }); + close.setClickShortcut(KeyCode.ESCAPE, null); + w.addComponent(close); + + getLayout().getWindow().addWindow(w); + + } + + private Component createComboBox() { + ComboBox cb = new ComboBox("A combo box"); + + cb.addItem("Yes"); + cb.addItem("No"); + cb.addItem("Maybe"); + return cb; + } + + @Override + protected String getDescription() { + return "Escape is a shortcut for the close button. Pressing escape when the popup is open should cause only the popup to close, not the window."; + } + + @Override + protected Integer getTicketNumber() { + return 6978; + } + +} diff --git a/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxNullItem.html b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxNullItem.html new file mode 100644 index 0000000000..3dc31f4a98 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxNullItem.html @@ -0,0 +1,62 @@ +<?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://arturwin.office.itmill.com: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.combobox.ComboBoxNavigation?restartApplication&theme=chameleon</td> + <td></td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VFilterSelect[0]/domChild[1]</td> + <td>5,9</td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>combobox-with-null-item-chameleon</td> +</tr> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.combobox.ComboBoxNavigation?restartApplication&theme=runo</td> + <td></td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VFilterSelect[0]/domChild[1]</td> + <td>5,9</td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>combobox-with-null-item-runo</td> +</tr> +<tr> + <td>open</td> + <td>/run/com.vaadin.tests.components.combobox.ComboBoxNavigation?restartApplication&theme=reindeer</td> + <td></td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboBoxNavigation::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VFilterSelect[0]/domChild[1]</td> + <td>5,9</td> +</tr> +<tr> + <td>screenCapture</td> + <td></td> + <td>combobox-with-null-item-reindeer</td> +</tr> + +</tbody></table> +</body> +</html> diff --git a/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxSlow.java b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxSlow.java new file mode 100644 index 0000000000..15742cc783 --- /dev/null +++ b/tests/testbench/com/vaadin/tests/components/combobox/ComboBoxSlow.java @@ -0,0 +1,55 @@ +package com.vaadin.tests.components.combobox; + +import java.util.Map; + +import com.vaadin.data.Property.ValueChangeEvent; +import com.vaadin.data.Property.ValueChangeListener; +import com.vaadin.tests.components.TestBase; +import com.vaadin.tests.util.Log; +import com.vaadin.ui.ComboBox; + +public class ComboBoxSlow extends TestBase { + + private Log log = new Log(5); + + @Override + protected Integer getTicketNumber() { + return 7949; + } + + @Override + protected String getDescription() { + return "The ComboBox artificially introduces a server delay to more easily spot problems"; + } + + public class SlowComboBox extends ComboBox { + @Override + public void changeVariables(Object source, Map<String, Object> variables) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + super.changeVariables(source, variables); + } + } + + @Override + protected void setup() { + addComponent(log); + final SlowComboBox cb = new SlowComboBox(); + cb.setImmediate(true); + for (int i = 0; i <= 1000; i++) { + cb.addItem("Item " + i); + } + cb.addListener(new ValueChangeListener() { + + public void valueChange(ValueChangeEvent event) { + log.log("Value changed to " + cb.getValue()); + + } + }); + addComponent(cb); + } +} diff --git a/tests/testbench/com/vaadin/tests/components/combobox/Comboboxes.html b/tests/testbench/com/vaadin/tests/components/combobox/Comboboxes.html index 1affc9a8a9..4aa84a9453 100644 --- a/tests/testbench/com/vaadin/tests/components/combobox/Comboboxes.html +++ b/tests/testbench/com/vaadin/tests/components/combobox/Comboboxes.html @@ -250,30 +250,39 @@ </tr> <tr> <td>mouseClick</td> - <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::PID_Scheckboxaction-Readonly/domChild[0]</td> - <td>26,10</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::PID_Scheckboxaction-Required/domChild[0]</td> + <td>12,-8</td> </tr> <tr> - <td>waitForVaadin</td> - <td></td> - <td></td> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::PID_Scheckboxaction-Error indicators/domChild[0]</td> + <td>7,-8</td> </tr> <tr> <td>screenCapture</td> <td></td> - <td>error</td> + <td>readonly-required</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::PID_Scheckboxaction-Readonly/domChild[0]</td> + <td>26,10</td> +</tr> +<tr> + <td>mouseClick</td> + <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::PID_Scheckboxaction-Required/domChild[0]</td> + <td>3,-7</td> </tr> <tr> <td>mouseClick</td> <td>vaadin=runcomvaadintestscomponentscomboboxComboboxes::PID_Scheckboxaction-Error indicators/domChild[0]</td> - <td>67,8</td> + <td>7,-8</td> </tr> <tr> - <td>waitForVaadin</td> - <td></td> + <td>screenCapture</td> <td></td> + <td>error</td> </tr> - </tbody></table> </body> </html> diff --git a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldTimezone.html b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldTimezone.html index ca354dd240..2a67b16170 100644 --- a/tests/testbench/com/vaadin/tests/components/datefield/DateFieldTimezone.html +++ b/tests/testbench/com/vaadin/tests/components/datefield/DateFieldTimezone.html @@ -22,7 +22,7 @@ <td>6,10</td> </tr> <tr> - <td>type</td> + <td>enterCharacter</td> <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldTimezone::/VVerticalLayout[0]/ChildComponentContainer[1]/VVerticalLayout[0]/ChildComponentContainer[0]/VFilterSelect[0]/domChild[0]</td> <td>Europe/Helsinki (Eastern European Time)</td> </tr> @@ -51,7 +51,6 @@ <td>vaadin=runcomvaadintestscomponentsdatefieldDateFieldTimezone::PID_SLog_row_0</td> <td>2. Date changed to 12/31/09 11:00:00 PM UTC</td> </tr> - </tbody></table> </body> </html> |