]> source.dussan.org Git - vaadin-framework.git/commitdiff
Merged fixes from 6.7
authorArtur Signell <artur.signell@itmill.com>
Thu, 17 Nov 2011 13:37:04 +0000 (13:37 +0000)
committerArtur Signell <artur.signell@itmill.com>
Thu, 17 Nov 2011 13:37:04 +0000 (13:37 +0000)
svn changeset:22048/svn branch:6.8

12 files changed:
WebContent/release-notes.html
src/com/vaadin/terminal/gwt/client/ui/VFilterSelect.java
src/com/vaadin/ui/Select.java
tests/testbench/com/vaadin/tests/components/combobox/ComboBoxFiltering.html [new file with mode: 0644]
tests/testbench/com/vaadin/tests/components/combobox/ComboBoxIdenticalItems.html [new file with mode: 0644]
tests/testbench/com/vaadin/tests/components/combobox/ComboBoxIdenticalItems.java [new file with mode: 0644]
tests/testbench/com/vaadin/tests/components/combobox/ComboBoxInPopup.htm [new file with mode: 0644]
tests/testbench/com/vaadin/tests/components/combobox/ComboBoxInPopup.java [new file with mode: 0644]
tests/testbench/com/vaadin/tests/components/combobox/ComboBoxNullItem.html [new file with mode: 0644]
tests/testbench/com/vaadin/tests/components/combobox/ComboBoxSlow.java [new file with mode: 0644]
tests/testbench/com/vaadin/tests/components/combobox/Comboboxes.html
tests/testbench/com/vaadin/tests/components/datefield/DateFieldTimezone.html

index b05a5e1548ab94ad31542a85684f6ae6e8e9bdb4..574c3792effaaf2523aa20b5885e5922ffc8f0b4 100644 (file)
                </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>
index 7c3d3066ceb4643302d11b30776b7f9a2dc378a6..66200cbe8c5cc2380aac6c0d117bdb01257389ac 100644 (file)
@@ -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 = "&nbsp;";
+            } 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()
index 7b6fc07e5bb6928766c77c001feb5b63cd8cb141..439efdb864bc82d1bc166bfd7e2c27980d9674fb 100644 (file)
@@ -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 (file)
index 0000000..3de2218
--- /dev/null
@@ -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 (file)
index 0000000..6d18c60
--- /dev/null
@@ -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 (file)
index 0000000..dcd4af5
--- /dev/null
@@ -0,0 +1,54 @@
+package com.vaadin.tests.components.combobox;\r
+\r
+import com.vaadin.data.Item;\r
+import com.vaadin.data.Property;\r
+import com.vaadin.data.Property.ValueChangeEvent;\r
+import com.vaadin.tests.components.TestBase;\r
+import com.vaadin.tests.util.Log;\r
+import com.vaadin.ui.ComboBox;\r
+\r
+public class ComboBoxIdenticalItems extends TestBase {\r
+\r
+    private Log log = new Log(5);\r
+\r
+    @Override\r
+    public void setup() {\r
+        final ComboBox select = new ComboBox("ComboBox");\r
+        select.addContainerProperty("caption", String.class, null);\r
+        Item item = select.addItem("one-1");\r
+        item.getItemProperty("caption").setValue("One");\r
+        item = select.addItem("one-2");\r
+        item.getItemProperty("caption").setValue("One");\r
+        item = select.addItem("two");\r
+        item.getItemProperty("caption").setValue("Two");\r
+        select.setItemCaptionPropertyId("caption");\r
+        select.setNullSelectionAllowed(false);\r
+        select.setImmediate(true);\r
+        select.addListener(new Property.ValueChangeListener() {\r
+            private static final long serialVersionUID = -7932700771673919620L;\r
+\r
+            public void valueChange(ValueChangeEvent event) {\r
+                log.log("Item " + select.getValue() + " selected");\r
+\r
+            }\r
+        });\r
+\r
+        addComponent(log);\r
+        addComponent(select);\r
+    }\r
+\r
+    @Override\r
+    protected String getDescription() {\r
+        return "Keyboard selecting of a value is broken in combobox if two "\r
+                + "items have the same caption. The first item's id is \"One-1\" "\r
+                + "while the second one is \"One-2\". Selecting with mouse works "\r
+                + "as expected but selecting with keyboard always returns the "\r
+                + "object \"One-1\".";\r
+    }\r
+\r
+    @Override\r
+    protected Integer getTicketNumber() {\r
+        // TODO Auto-generated method stub\r
+        return null;\r
+    }\r
+}\r
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 (file)
index 0000000..f943f91
--- /dev/null
@@ -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 (file)
index 0000000..8160fb5
--- /dev/null
@@ -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 (file)
index 0000000..3dc31f4
--- /dev/null
@@ -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&amp;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&amp;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&amp;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 (file)
index 0000000..15742cc
--- /dev/null
@@ -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);
+    }
+}
index 1affc9a8a98445d5e14069c23d4d7e41dc965610..4aa84a945327c0054f16b593f2c0438aadfae523 100644 (file)
 </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>
index ca354dd2406b3c2eefae1b8696beaaa1bab22de3..2a67b161701a9cb9969f7e71c1b70aeb538f5aaf 100644 (file)
@@ -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>