]> source.dussan.org Git - vaadin-framework.git/commitdiff
Merged Select with ComboBox (#2869)
authorArtur Signell <artur@vaadin.com>
Thu, 30 Aug 2012 13:25:57 +0000 (16:25 +0300)
committerArtur Signell <artur@vaadin.com>
Thu, 30 Aug 2012 13:25:57 +0000 (16:25 +0300)
Select now extends ComboBox instead of vice versa
Select is now deprecated in favor of ComboBox

client/src/com/vaadin/client/ui/combobox/ComboBoxConnector.java
server/src/com/vaadin/ui/ComboBox.java
server/src/com/vaadin/ui/Select.java
tests/testbench/com/vaadin/tests/components/combobox/ComboBoxes2.java
tests/testbench/com/vaadin/tests/components/combobox/Comboboxes.java
tests/testbench/com/vaadin/tests/components/combobox/GridLayoutComboBoxZoomOut.java
tests/testbench/com/vaadin/tests/components/select/SelectTest.java

index e942f803e9781a2829449ae303632a1dfe8a250c..fc060f3deb4cb5c31b9110027faf40d05cf1c50b 100644 (file)
@@ -27,9 +27,9 @@ import com.vaadin.client.ui.combobox.VFilterSelect.FilterSelectSuggestion;
 import com.vaadin.client.ui.menubar.MenuItem;
 import com.vaadin.shared.ui.Connect;
 import com.vaadin.shared.ui.combobox.ComboBoxConstants;
-import com.vaadin.ui.Select;
+import com.vaadin.ui.ComboBox;
 
-@Connect(Select.class)
+@Connect(ComboBox.class)
 public class ComboBoxConnector extends AbstractFieldConnector implements
         Paintable, SimpleManagedLayout {
 
index 9cc4caa7c32e9eea98b5363e35b8f2a6840b69a4..f4b55d964a9290139ab30cd2c36fcf0dd564b547 100644 (file)
 
 package com.vaadin.ui;
 
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 
 import com.vaadin.data.Container;
+import com.vaadin.data.util.filter.SimpleStringFilter;
+import com.vaadin.event.FieldEvents;
+import com.vaadin.event.FieldEvents.BlurEvent;
+import com.vaadin.event.FieldEvents.BlurListener;
+import com.vaadin.event.FieldEvents.FocusEvent;
+import com.vaadin.event.FieldEvents.FocusListener;
 import com.vaadin.server.PaintException;
 import com.vaadin.server.PaintTarget;
+import com.vaadin.server.Resource;
 import com.vaadin.shared.ui.combobox.ComboBoxConstants;
 
 /**
@@ -32,10 +46,58 @@ import com.vaadin.shared.ui.combobox.ComboBoxConstants;
  * 
  */
 @SuppressWarnings("serial")
-public class ComboBox extends Select {
+public class ComboBox extends AbstractSelect implements
+        AbstractSelect.Filtering, FieldEvents.BlurNotifier,
+        FieldEvents.FocusNotifier {
 
     private String inputPrompt = null;
 
+    /**
+     * Holds value of property pageLength. 0 disables paging.
+     */
+    protected int pageLength = 10;
+
+    private int columns = 0;
+
+    // Current page when the user is 'paging' trough options
+    private int currentPage = -1;
+
+    private int filteringMode = Filtering.FILTERINGMODE_STARTSWITH;
+
+    private String filterstring;
+    private String prevfilterstring;
+
+    /**
+     * Number of options that pass the filter, excluding the null item if any.
+     */
+    private int filteredSize;
+
+    /**
+     * Cache of filtered options, used only by the in-memory filtering system.
+     */
+    private List<Object> filteredOptions;
+
+    /**
+     * Flag to indicate that request repaint is called by filter request only
+     */
+    private boolean optionRequest;
+
+    /**
+     * True if the container is being filtered temporarily and item set change
+     * notifications should be suppressed.
+     */
+    private boolean filteringContainer;
+
+    /**
+     * Flag to indicate whether to scroll the selected item visible (select the
+     * page on which it is) when opening the popup or not. Only applies to
+     * single select mode.
+     * 
+     * This requires finding the index of the item, which can be expensive in
+     * many large lazy loading containers.
+     */
+    private boolean scrollToSelectedItem = true;
+
     /**
      * If text input is not allowed, the ComboBox behaves like a pretty
      * NativeSelect - the user can not enter any text and clicking the text
@@ -89,11 +151,154 @@ public class ComboBox extends Select {
         if (inputPrompt != null) {
             target.addAttribute(ComboBoxConstants.ATTR_INPUTPROMPT, inputPrompt);
         }
-        super.paintContent(target);
 
         if (!textInputAllowed) {
             target.addAttribute(ComboBoxConstants.ATTR_NO_TEXT_INPUT, true);
         }
+
+        if (isMultiSelect()) {
+            // background compatibility hack. This object shouldn't be used for
+            // multiselect lists anymore (ListSelect instead). This fallbacks to
+            // a simpler paint method in super class.
+            super.paintContent(target);
+            // Fix for #4553
+            target.addAttribute("type", "legacy-multi");
+            return;
+        }
+
+        // clear caption change listeners
+        getCaptionChangeListener().clear();
+
+        // The tab ordering number
+        if (getTabIndex() != 0) {
+            target.addAttribute("tabindex", getTabIndex());
+        }
+
+        // If the field is modified, but not committed, set modified attribute
+        if (isModified()) {
+            target.addAttribute("modified", true);
+        }
+
+        if (isNewItemsAllowed()) {
+            target.addAttribute("allownewitem", true);
+        }
+
+        boolean needNullSelectOption = false;
+        if (isNullSelectionAllowed()) {
+            target.addAttribute("nullselect", true);
+            needNullSelectOption = (getNullSelectionItemId() == null);
+            if (!needNullSelectOption) {
+                target.addAttribute("nullselectitem", true);
+            }
+        }
+
+        // Constructs selected keys array
+        String[] selectedKeys;
+        if (isMultiSelect()) {
+            selectedKeys = new String[((Set<?>) getValue()).size()];
+        } else {
+            selectedKeys = new String[(getValue() == null
+                    && getNullSelectionItemId() == null ? 0 : 1)];
+        }
+
+        target.addAttribute("pagelength", pageLength);
+
+        target.addAttribute("filteringmode", getFilteringMode());
+
+        // Paints the options and create array of selected id keys
+        int keyIndex = 0;
+
+        target.startTag("options");
+
+        if (currentPage < 0) {
+            optionRequest = false;
+            currentPage = 0;
+            filterstring = "";
+        }
+
+        boolean nullFilteredOut = filterstring != null
+                && !"".equals(filterstring)
+                && filteringMode != Filtering.FILTERINGMODE_OFF;
+        // null option is needed and not filtered out, even if not on current
+        // page
+        boolean nullOptionVisible = needNullSelectOption && !nullFilteredOut;
+
+        // first try if using container filters is possible
+        List<?> options = getOptionsWithFilter(nullOptionVisible);
+        if (null == options) {
+            // not able to use container filters, perform explicit in-memory
+            // filtering
+            options = getFilteredOptions();
+            filteredSize = options.size();
+            options = sanitetizeList(options, nullOptionVisible);
+        }
+
+        final boolean paintNullSelection = needNullSelectOption
+                && currentPage == 0 && !nullFilteredOut;
+
+        if (paintNullSelection) {
+            target.startTag("so");
+            target.addAttribute("caption", "");
+            target.addAttribute("key", "");
+            target.endTag("so");
+        }
+
+        final Iterator<?> i = options.iterator();
+        // Paints the available selection options from data source
+
+        while (i.hasNext()) {
+
+            final Object id = i.next();
+
+            if (!isNullSelectionAllowed() && id != null
+                    && id.equals(getNullSelectionItemId()) && !isSelected(id)) {
+                continue;
+            }
+
+            // Gets the option attribute values
+            final String key = itemIdMapper.key(id);
+            final String caption = getItemCaption(id);
+            final Resource icon = getItemIcon(id);
+            getCaptionChangeListener().addNotifierForItem(id);
+
+            // Paints the option
+            target.startTag("so");
+            if (icon != null) {
+                target.addAttribute("icon", icon);
+            }
+            target.addAttribute("caption", caption);
+            if (id != null && id.equals(getNullSelectionItemId())) {
+                target.addAttribute("nullselection", true);
+            }
+            target.addAttribute("key", key);
+            if (isSelected(id) && keyIndex < selectedKeys.length) {
+                target.addAttribute("selected", true);
+                selectedKeys[keyIndex++] = key;
+            }
+            target.endTag("so");
+        }
+        target.endTag("options");
+
+        target.addAttribute("totalitems", size()
+                + (needNullSelectOption ? 1 : 0));
+        if (filteredSize > 0 || nullOptionVisible) {
+            target.addAttribute("totalMatches", filteredSize
+                    + (nullOptionVisible ? 1 : 0));
+        }
+
+        // Paint variables
+        target.addVariable(this, "selected", selectedKeys);
+        if (isNewItemsAllowed()) {
+            target.addVariable(this, "newitem", "");
+        }
+
+        target.addVariable(this, "filter", filterstring);
+        target.addVariable(this, "page", currentPage);
+
+        currentPage = -1; // current page is always set by client
+
+        optionRequest = true;
+
     }
 
     /**
@@ -125,4 +330,531 @@ public class ComboBox extends Select {
         return textInputAllowed;
     }
 
+    /**
+     * Returns the filtered options for the current page using a container
+     * filter.
+     * 
+     * As a size effect, {@link #filteredSize} is set to the total number of
+     * items passing the filter.
+     * 
+     * The current container must be {@link Filterable} and {@link Indexed}, and
+     * the filtering mode must be suitable for container filtering (tested with
+     * {@link #canUseContainerFilter()}).
+     * 
+     * Use {@link #getFilteredOptions()} and
+     * {@link #sanitetizeList(List, boolean)} if this is not the case.
+     * 
+     * @param needNullSelectOption
+     * @return filtered list of options (may be empty) or null if cannot use
+     *         container filters
+     */
+    protected List<?> getOptionsWithFilter(boolean needNullSelectOption) {
+        Container container = getContainerDataSource();
+
+        if (pageLength == 0) {
+            // no paging: return all items
+            filteredSize = container.size();
+            return new ArrayList<Object>(container.getItemIds());
+        }
+
+        if (!(container instanceof Filterable)
+                || !(container instanceof Indexed)
+                || getItemCaptionMode() != ITEM_CAPTION_MODE_PROPERTY) {
+            return null;
+        }
+
+        Filterable filterable = (Filterable) container;
+
+        Filter filter = buildFilter(filterstring, filteringMode);
+
+        // adding and removing filters leads to extraneous item set
+        // change events from the underlying container, but the ComboBox does
+        // not process or propagate them based on the flag filteringContainer
+        if (filter != null) {
+            filteringContainer = true;
+            filterable.addContainerFilter(filter);
+        }
+
+        Indexed indexed = (Indexed) container;
+
+        int indexToEnsureInView = -1;
+
+        // if not an option request (item list when user changes page), go
+        // to page with the selected item after filtering if accepted by
+        // filter
+        Object selection = getValue();
+        if (isScrollToSelectedItem() && !optionRequest && !isMultiSelect()
+                && selection != null) {
+            // ensure proper page
+            indexToEnsureInView = indexed.indexOfId(selection);
+        }
+
+        filteredSize = container.size();
+        currentPage = adjustCurrentPage(currentPage, needNullSelectOption,
+                indexToEnsureInView, filteredSize);
+        int first = getFirstItemIndexOnCurrentPage(needNullSelectOption,
+                filteredSize);
+        int last = getLastItemIndexOnCurrentPage(needNullSelectOption,
+                filteredSize, first);
+
+        List<Object> options = new ArrayList<Object>();
+        for (int i = first; i <= last && i < filteredSize; ++i) {
+            options.add(indexed.getIdByIndex(i));
+        }
+
+        // to the outside, filtering should not be visible
+        if (filter != null) {
+            filterable.removeContainerFilter(filter);
+            filteringContainer = false;
+        }
+
+        return options;
+    }
+
+    /**
+     * Constructs a filter instance to use when using a Filterable container in
+     * the <code>ITEM_CAPTION_MODE_PROPERTY</code> mode.
+     * 
+     * Note that the client side implementation expects the filter string to
+     * apply to the item caption string it sees, so changing the behavior of
+     * this method can cause problems.
+     * 
+     * @param filterString
+     * @param filteringMode
+     * @return
+     */
+    protected Filter buildFilter(String filterString, int filteringMode) {
+        Filter filter = null;
+
+        if (null != filterString && !"".equals(filterString)) {
+            switch (filteringMode) {
+            case Filtering.FILTERINGMODE_OFF:
+                break;
+            case Filtering.FILTERINGMODE_STARTSWITH:
+                filter = new SimpleStringFilter(getItemCaptionPropertyId(),
+                        filterString, true, true);
+                break;
+            case Filtering.FILTERINGMODE_CONTAINS:
+                filter = new SimpleStringFilter(getItemCaptionPropertyId(),
+                        filterString, true, false);
+                break;
+            }
+        }
+        return filter;
+    }
+
+    @Override
+    public void containerItemSetChange(Container.ItemSetChangeEvent event) {
+        if (!filteringContainer) {
+            super.containerItemSetChange(event);
+        }
+    }
+
+    /**
+     * Makes correct sublist of given list of options.
+     * 
+     * If paint is not an option request (affected by page or filter change),
+     * page will be the one where possible selection exists.
+     * 
+     * Detects proper first and last item in list to return right page of
+     * options. Also, if the current page is beyond the end of the list, it will
+     * be adjusted.
+     * 
+     * @param options
+     * @param needNullSelectOption
+     *            flag to indicate if nullselect option needs to be taken into
+     *            consideration
+     */
+    private List<?> sanitetizeList(List<?> options, boolean needNullSelectOption) {
+
+        if (pageLength != 0 && options.size() > pageLength) {
+
+            int indexToEnsureInView = -1;
+
+            // if not an option request (item list when user changes page), go
+            // to page with the selected item after filtering if accepted by
+            // filter
+            Object selection = getValue();
+            if (isScrollToSelectedItem() && !optionRequest && !isMultiSelect()
+                    && selection != null) {
+                // ensure proper page
+                indexToEnsureInView = options.indexOf(selection);
+            }
+
+            int size = options.size();
+            currentPage = adjustCurrentPage(currentPage, needNullSelectOption,
+                    indexToEnsureInView, size);
+            int first = getFirstItemIndexOnCurrentPage(needNullSelectOption,
+                    size);
+            int last = getLastItemIndexOnCurrentPage(needNullSelectOption,
+                    size, first);
+            return options.subList(first, last + 1);
+        } else {
+            return options;
+        }
+    }
+
+    /**
+     * Returns the index of the first item on the current page. The index is to
+     * the underlying (possibly filtered) contents. The null item, if any, does
+     * not have an index but takes up a slot on the first page.
+     * 
+     * @param needNullSelectOption
+     *            true if a null option should be shown before any other options
+     *            (takes up the first slot on the first page, not counted in
+     *            index)
+     * @param size
+     *            number of items after filtering (not including the null item,
+     *            if any)
+     * @return first item to show on the UI (index to the filtered list of
+     *         options, not taking the null item into consideration if any)
+     */
+    private int getFirstItemIndexOnCurrentPage(boolean needNullSelectOption,
+            int size) {
+        // Not all options are visible, find out which ones are on the
+        // current "page".
+        int first = currentPage * pageLength;
+        if (needNullSelectOption && currentPage > 0) {
+            first--;
+        }
+        return first;
+    }
+
+    /**
+     * Returns the index of the last item on the current page. The index is to
+     * the underlying (possibly filtered) contents. If needNullSelectOption is
+     * true, the null item takes up the first slot on the first page,
+     * effectively reducing the first page size by one.
+     * 
+     * @param needNullSelectOption
+     *            true if a null option should be shown before any other options
+     *            (takes up the first slot on the first page, not counted in
+     *            index)
+     * @param size
+     *            number of items after filtering (not including the null item,
+     *            if any)
+     * @param first
+     *            index in the filtered view of the first item of the page
+     * @return index in the filtered view of the last item on the page
+     */
+    private int getLastItemIndexOnCurrentPage(boolean needNullSelectOption,
+            int size, int first) {
+        // page length usable for non-null items
+        int effectivePageLength = pageLength
+                - (needNullSelectOption && (currentPage == 0) ? 1 : 0);
+        return Math.min(size - 1, first + effectivePageLength - 1);
+    }
+
+    /**
+     * Adjusts the index of the current page if necessary: make sure the current
+     * page is not after the end of the contents, and optionally go to the page
+     * containg a specific item. There are no side effects but the adjusted page
+     * index is returned.
+     * 
+     * @param page
+     *            page number to use as the starting point
+     * @param needNullSelectOption
+     *            true if a null option should be shown before any other options
+     *            (takes up the first slot on the first page, not counted in
+     *            index)
+     * @param indexToEnsureInView
+     *            index of an item that should be included on the page (in the
+     *            data set, not counting the null item if any), -1 for none
+     * @param size
+     *            number of items after filtering (not including the null item,
+     *            if any)
+     */
+    private int adjustCurrentPage(int page, boolean needNullSelectOption,
+            int indexToEnsureInView, int size) {
+        if (indexToEnsureInView != -1) {
+            int newPage = (indexToEnsureInView + (needNullSelectOption ? 1 : 0))
+                    / pageLength;
+            page = newPage;
+        }
+        // adjust the current page if beyond the end of the list
+        if (page * pageLength > size) {
+            page = (size + (needNullSelectOption ? 1 : 0)) / pageLength;
+        }
+        return page;
+    }
+
+    /**
+     * Filters the options in memory and returns the full filtered list.
+     * 
+     * This can be less efficient than using container filters, so use
+     * {@link #getOptionsWithFilter(boolean)} if possible (filterable container
+     * and suitable item caption mode etc.).
+     * 
+     * @return
+     */
+    protected List<?> getFilteredOptions() {
+        if (null == filterstring || "".equals(filterstring)
+                || Filtering.FILTERINGMODE_OFF == filteringMode) {
+            prevfilterstring = null;
+            filteredOptions = new LinkedList<Object>(getItemIds());
+            return filteredOptions;
+        }
+
+        if (filterstring.equals(prevfilterstring)) {
+            return filteredOptions;
+        }
+
+        Collection<?> items;
+        if (prevfilterstring != null
+                && filterstring.startsWith(prevfilterstring)) {
+            items = filteredOptions;
+        } else {
+            items = getItemIds();
+        }
+        prevfilterstring = filterstring;
+
+        filteredOptions = new LinkedList<Object>();
+        for (final Iterator<?> it = items.iterator(); it.hasNext();) {
+            final Object itemId = it.next();
+            String caption = getItemCaption(itemId);
+            if (caption == null || caption.equals("")) {
+                continue;
+            } else {
+                caption = caption.toLowerCase();
+            }
+            switch (filteringMode) {
+            case Filtering.FILTERINGMODE_CONTAINS:
+                if (caption.indexOf(filterstring) > -1) {
+                    filteredOptions.add(itemId);
+                }
+                break;
+            case Filtering.FILTERINGMODE_STARTSWITH:
+            default:
+                if (caption.startsWith(filterstring)) {
+                    filteredOptions.add(itemId);
+                }
+                break;
+            }
+        }
+
+        return filteredOptions;
+    }
+
+    /**
+     * Invoked when the value of a variable has changed.
+     * 
+     * @see com.vaadin.ui.AbstractComponent#changeVariables(java.lang.Object,
+     *      java.util.Map)
+     */
+    @Override
+    public void changeVariables(Object source, Map<String, Object> variables) {
+        // Not calling super.changeVariables due the history of select
+        // component hierarchy
+
+        // Selection change
+        if (variables.containsKey("selected")) {
+            final String[] ka = (String[]) variables.get("selected");
+
+            if (isMultiSelect()) {
+                // Multiselect mode
+
+                // TODO Optimize by adding repaintNotNeeded whan applicaple
+
+                // Converts the key-array to id-set
+                final LinkedList<Object> s = new LinkedList<Object>();
+                for (int i = 0; i < ka.length; i++) {
+                    final Object id = itemIdMapper.get(ka[i]);
+                    if (id != null && containsId(id)) {
+                        s.add(id);
+                    }
+                }
+
+                // Limits the deselection to the set of visible items
+                // (non-visible items can not be deselected)
+                final Collection<?> visible = getVisibleItemIds();
+                if (visible != null) {
+                    @SuppressWarnings("unchecked")
+                    Set<Object> newsel = (Set<Object>) getValue();
+                    if (newsel == null) {
+                        newsel = new HashSet<Object>();
+                    } else {
+                        newsel = new HashSet<Object>(newsel);
+                    }
+                    newsel.removeAll(visible);
+                    newsel.addAll(s);
+                    setValue(newsel, true);
+                }
+            } else {
+                // Single select mode
+                if (ka.length == 0) {
+
+                    // Allows deselection only if the deselected item is visible
+                    final Object current = getValue();
+                    final Collection<?> visible = getVisibleItemIds();
+                    if (visible != null && visible.contains(current)) {
+                        setValue(null, true);
+                    }
+                } else {
+                    final Object id = itemIdMapper.get(ka[0]);
+                    if (id != null && id.equals(getNullSelectionItemId())) {
+                        setValue(null, true);
+                    } else {
+                        setValue(id, true);
+                    }
+                }
+            }
+        }
+
+        String newFilter;
+        if ((newFilter = (String) variables.get("filter")) != null) {
+            // this is a filter request
+            currentPage = ((Integer) variables.get("page")).intValue();
+            filterstring = newFilter;
+            if (filterstring != null) {
+                filterstring = filterstring.toLowerCase();
+            }
+            requestRepaint();
+        } else if (isNewItemsAllowed()) {
+            // New option entered (and it is allowed)
+            final String newitem = (String) variables.get("newitem");
+            if (newitem != null && newitem.length() > 0) {
+                getNewItemHandler().addNewItem(newitem);
+                // rebuild list
+                filterstring = null;
+                prevfilterstring = null;
+            }
+        }
+
+        if (variables.containsKey(FocusEvent.EVENT_ID)) {
+            fireEvent(new FocusEvent(this));
+        }
+        if (variables.containsKey(BlurEvent.EVENT_ID)) {
+            fireEvent(new BlurEvent(this));
+        }
+
+    }
+
+    @Override
+    @Deprecated
+    public void requestRepaint() {
+        markAsDirty();
+    }
+
+    @Override
+    public void setFilteringMode(int filteringMode) {
+        this.filteringMode = filteringMode;
+    }
+
+    @Override
+    public int getFilteringMode() {
+        return filteringMode;
+    }
+
+    public void addBlurListener(BlurListener listener) {
+        addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener,
+                BlurListener.blurMethod);
+    }
+
+    /**
+     * @deprecated Since 7.0, replaced by {@link #addBlurListener(BlurListener)}
+     **/
+    @Deprecated
+    public void addListener(BlurListener listener) {
+        addBlurListener(listener);
+    }
+
+    @Override
+    public void removeBlurListener(BlurListener listener) {
+        removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener);
+    }
+
+    /**
+     * @deprecated Since 7.0, replaced by
+     *             {@link #removeBlurListener(BlurListener)}
+     **/
+    @Deprecated
+    public void removeListener(BlurListener listener) {
+        removeBlurListener(listener);
+    }
+
+    @Override
+    public void addFocusListener(FocusListener listener) {
+        addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener,
+                FocusListener.focusMethod);
+    }
+
+    /**
+     * @deprecated Since 7.0, replaced by
+     *             {@link #addFocusListener(FocusListener)}
+     **/
+    @Deprecated
+    public void addListener(FocusListener listener) {
+        addFocusListener(listener);
+    }
+
+    @Override
+    public void removeFocusListener(FocusListener listener) {
+        removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener);
+    }
+
+    /**
+     * @deprecated Since 7.0, replaced by
+     *             {@link #removeFocusListener(FocusListener)}
+     **/
+    @Deprecated
+    public void removeListener(FocusListener listener) {
+        removeFocusListener(listener);
+    }
+
+    /**
+     * @deprecated use {@link ListSelect}, {@link OptionGroup} or
+     *             {@link TwinColSelect} instead
+     * @see com.vaadin.ui.AbstractSelect#setMultiSelect(boolean)
+     * @throws UnsupportedOperationException
+     *             if trying to activate multiselect mode
+     */
+    @Deprecated
+    @Override
+    public void setMultiSelect(boolean multiSelect) {
+        if (multiSelect) {
+            throw new UnsupportedOperationException("Multiselect not supported");
+        }
+    }
+
+    /**
+     * @deprecated use {@link ListSelect}, {@link OptionGroup} or
+     *             {@link TwinColSelect} instead
+     * 
+     * @see com.vaadin.ui.AbstractSelect#isMultiSelect()
+     */
+    @Deprecated
+    @Override
+    public boolean isMultiSelect() {
+        return super.isMultiSelect();
+    }
+
+    /**
+     * Sets whether to scroll the selected item visible (directly open the page
+     * on which it is) when opening the combo box popup or not. Only applies to
+     * single select mode.
+     * 
+     * This requires finding the index of the item, which can be expensive in
+     * many large lazy loading containers.
+     * 
+     * @param scrollToSelectedItem
+     *            true to find the page with the selected item when opening the
+     *            selection popup
+     */
+    public void setScrollToSelectedItem(boolean scrollToSelectedItem) {
+        this.scrollToSelectedItem = scrollToSelectedItem;
+    }
+
+    /**
+     * Returns true if the select should find the page with the selected item
+     * when opening the popup (single select combo box only).
+     * 
+     * @see #setScrollToSelectedItem(boolean)
+     * 
+     * @return true if the page with the selected item will be shown when
+     *         opening the popup
+     */
+    public boolean isScrollToSelectedItem() {
+        return scrollToSelectedItem;
+    }
+
 }
index 853a1efeabf264082893d4aa5bf2212c5eab50bd..ef8ba6d30705b51b3dbdafc400057c5d1bf63404 100644 (file)
 
 package com.vaadin.ui;
 
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
 
 import com.vaadin.data.Container;
-import com.vaadin.data.util.filter.SimpleStringFilter;
-import com.vaadin.event.FieldEvents;
-import com.vaadin.event.FieldEvents.BlurEvent;
-import com.vaadin.event.FieldEvents.BlurListener;
-import com.vaadin.event.FieldEvents.FocusEvent;
-import com.vaadin.event.FieldEvents.FocusListener;
-import com.vaadin.server.PaintException;
-import com.vaadin.server.PaintTarget;
-import com.vaadin.server.Resource;
 
 /**
  * <p>
@@ -51,59 +35,10 @@ import com.vaadin.server.Resource;
  * 
  * @author Vaadin Ltd.
  * @since 3.0
+ * @deprecated as of 7.0. Use {@link ComboBox} instead.
  */
-@SuppressWarnings("serial")
-public class Select extends AbstractSelect implements AbstractSelect.Filtering,
-        FieldEvents.BlurNotifier, FieldEvents.FocusNotifier {
-
-    /**
-     * Holds value of property pageLength. 0 disables paging.
-     */
-    protected int pageLength = 10;
-
-    private int columns = 0;
-
-    // Current page when the user is 'paging' trough options
-    private int currentPage = -1;
-
-    private int filteringMode = FILTERINGMODE_STARTSWITH;
-
-    private String filterstring;
-    private String prevfilterstring;
-
-    /**
-     * Number of options that pass the filter, excluding the null item if any.
-     */
-    private int filteredSize;
-
-    /**
-     * Cache of filtered options, used only by the in-memory filtering system.
-     */
-    private List<Object> filteredOptions;
-
-    /**
-     * Flag to indicate that request repaint is called by filter request only
-     */
-    private boolean optionRequest;
-
-    /**
-     * True if the container is being filtered temporarily and item set change
-     * notifications should be suppressed.
-     */
-    private boolean filteringContainer;
-
-    /**
-     * Flag to indicate whether to scroll the selected item visible (select the
-     * page on which it is) when opening the popup or not. Only applies to
-     * single select mode.
-     * 
-     * This requires finding the index of the item, which can be expensive in
-     * many large lazy loading containers.
-     */
-    private boolean scrollToSelectedItem = true;
-
-    /* Constructors */
-
+@Deprecated
+public class Select extends ComboBox {
     /* Component methods */
 
     public Select() {
@@ -122,686 +57,4 @@ public class Select extends AbstractSelect implements AbstractSelect.Filtering,
         super(caption);
     }
 
-    /**
-     * Paints the content of this component.
-     * 
-     * @param target
-     *            the Paint Event.
-     * @throws PaintException
-     *             if the paint operation failed.
-     */
-    @Override
-    public void paintContent(PaintTarget target) throws PaintException {
-        if (isMultiSelect()) {
-            // background compatibility hack. This object shouldn't be used for
-            // multiselect lists anymore (ListSelect instead). This fallbacks to
-            // a simpler paint method in super class.
-            super.paintContent(target);
-            // Fix for #4553
-            target.addAttribute("type", "legacy-multi");
-            return;
-        }
-
-        // clear caption change listeners
-        getCaptionChangeListener().clear();
-
-        // The tab ordering number
-        if (getTabIndex() != 0) {
-            target.addAttribute("tabindex", getTabIndex());
-        }
-
-        // If the field is modified, but not committed, set modified attribute
-        if (isModified()) {
-            target.addAttribute("modified", true);
-        }
-
-        if (isNewItemsAllowed()) {
-            target.addAttribute("allownewitem", true);
-        }
-
-        boolean needNullSelectOption = false;
-        if (isNullSelectionAllowed()) {
-            target.addAttribute("nullselect", true);
-            needNullSelectOption = (getNullSelectionItemId() == null);
-            if (!needNullSelectOption) {
-                target.addAttribute("nullselectitem", true);
-            }
-        }
-
-        // Constructs selected keys array
-        String[] selectedKeys;
-        if (isMultiSelect()) {
-            selectedKeys = new String[((Set<?>) getValue()).size()];
-        } else {
-            selectedKeys = new String[(getValue() == null
-                    && getNullSelectionItemId() == null ? 0 : 1)];
-        }
-
-        target.addAttribute("pagelength", pageLength);
-
-        target.addAttribute("filteringmode", getFilteringMode());
-
-        // Paints the options and create array of selected id keys
-        int keyIndex = 0;
-
-        target.startTag("options");
-
-        if (currentPage < 0) {
-            optionRequest = false;
-            currentPage = 0;
-            filterstring = "";
-        }
-
-        boolean nullFilteredOut = filterstring != null
-                && !"".equals(filterstring)
-                && filteringMode != FILTERINGMODE_OFF;
-        // null option is needed and not filtered out, even if not on current
-        // page
-        boolean nullOptionVisible = needNullSelectOption && !nullFilteredOut;
-
-        // first try if using container filters is possible
-        List<?> options = getOptionsWithFilter(nullOptionVisible);
-        if (null == options) {
-            // not able to use container filters, perform explicit in-memory
-            // filtering
-            options = getFilteredOptions();
-            filteredSize = options.size();
-            options = sanitetizeList(options, nullOptionVisible);
-        }
-
-        final boolean paintNullSelection = needNullSelectOption
-                && currentPage == 0 && !nullFilteredOut;
-
-        if (paintNullSelection) {
-            target.startTag("so");
-            target.addAttribute("caption", "");
-            target.addAttribute("key", "");
-            target.endTag("so");
-        }
-
-        final Iterator<?> i = options.iterator();
-        // Paints the available selection options from data source
-
-        while (i.hasNext()) {
-
-            final Object id = i.next();
-
-            if (!isNullSelectionAllowed() && id != null
-                    && id.equals(getNullSelectionItemId()) && !isSelected(id)) {
-                continue;
-            }
-
-            // Gets the option attribute values
-            final String key = itemIdMapper.key(id);
-            final String caption = getItemCaption(id);
-            final Resource icon = getItemIcon(id);
-            getCaptionChangeListener().addNotifierForItem(id);
-
-            // Paints the option
-            target.startTag("so");
-            if (icon != null) {
-                target.addAttribute("icon", icon);
-            }
-            target.addAttribute("caption", caption);
-            if (id != null && id.equals(getNullSelectionItemId())) {
-                target.addAttribute("nullselection", true);
-            }
-            target.addAttribute("key", key);
-            if (isSelected(id) && keyIndex < selectedKeys.length) {
-                target.addAttribute("selected", true);
-                selectedKeys[keyIndex++] = key;
-            }
-            target.endTag("so");
-        }
-        target.endTag("options");
-
-        target.addAttribute("totalitems", size()
-                + (needNullSelectOption ? 1 : 0));
-        if (filteredSize > 0 || nullOptionVisible) {
-            target.addAttribute("totalMatches", filteredSize
-                    + (nullOptionVisible ? 1 : 0));
-        }
-
-        // Paint variables
-        target.addVariable(this, "selected", selectedKeys);
-        if (isNewItemsAllowed()) {
-            target.addVariable(this, "newitem", "");
-        }
-
-        target.addVariable(this, "filter", filterstring);
-        target.addVariable(this, "page", currentPage);
-
-        currentPage = -1; // current page is always set by client
-
-        optionRequest = true;
-    }
-
-    /**
-     * Returns the filtered options for the current page using a container
-     * filter.
-     * 
-     * As a size effect, {@link #filteredSize} is set to the total number of
-     * items passing the filter.
-     * 
-     * The current container must be {@link Filterable} and {@link Indexed}, and
-     * the filtering mode must be suitable for container filtering (tested with
-     * {@link #canUseContainerFilter()}).
-     * 
-     * Use {@link #getFilteredOptions()} and
-     * {@link #sanitetizeList(List, boolean)} if this is not the case.
-     * 
-     * @param needNullSelectOption
-     * @return filtered list of options (may be empty) or null if cannot use
-     *         container filters
-     */
-    protected List<?> getOptionsWithFilter(boolean needNullSelectOption) {
-        Container container = getContainerDataSource();
-
-        if (pageLength == 0) {
-            // no paging: return all items
-            filteredSize = container.size();
-            return new ArrayList<Object>(container.getItemIds());
-        }
-
-        if (!(container instanceof Filterable)
-                || !(container instanceof Indexed)
-                || getItemCaptionMode() != ITEM_CAPTION_MODE_PROPERTY) {
-            return null;
-        }
-
-        Filterable filterable = (Filterable) container;
-
-        Filter filter = buildFilter(filterstring, filteringMode);
-
-        // adding and removing filters leads to extraneous item set
-        // change events from the underlying container, but the ComboBox does
-        // not process or propagate them based on the flag filteringContainer
-        if (filter != null) {
-            filteringContainer = true;
-            filterable.addContainerFilter(filter);
-        }
-
-        Indexed indexed = (Indexed) container;
-
-        int indexToEnsureInView = -1;
-
-        // if not an option request (item list when user changes page), go
-        // to page with the selected item after filtering if accepted by
-        // filter
-        Object selection = getValue();
-        if (isScrollToSelectedItem() && !optionRequest && !isMultiSelect()
-                && selection != null) {
-            // ensure proper page
-            indexToEnsureInView = indexed.indexOfId(selection);
-        }
-
-        filteredSize = container.size();
-        currentPage = adjustCurrentPage(currentPage, needNullSelectOption,
-                indexToEnsureInView, filteredSize);
-        int first = getFirstItemIndexOnCurrentPage(needNullSelectOption,
-                filteredSize);
-        int last = getLastItemIndexOnCurrentPage(needNullSelectOption,
-                filteredSize, first);
-
-        List<Object> options = new ArrayList<Object>();
-        for (int i = first; i <= last && i < filteredSize; ++i) {
-            options.add(indexed.getIdByIndex(i));
-        }
-
-        // to the outside, filtering should not be visible
-        if (filter != null) {
-            filterable.removeContainerFilter(filter);
-            filteringContainer = false;
-        }
-
-        return options;
-    }
-
-    /**
-     * Constructs a filter instance to use when using a Filterable container in
-     * the <code>ITEM_CAPTION_MODE_PROPERTY</code> mode.
-     * 
-     * Note that the client side implementation expects the filter string to
-     * apply to the item caption string it sees, so changing the behavior of
-     * this method can cause problems.
-     * 
-     * @param filterString
-     * @param filteringMode
-     * @return
-     */
-    protected Filter buildFilter(String filterString, int filteringMode) {
-        Filter filter = null;
-
-        if (null != filterString && !"".equals(filterString)) {
-            switch (filteringMode) {
-            case FILTERINGMODE_OFF:
-                break;
-            case FILTERINGMODE_STARTSWITH:
-                filter = new SimpleStringFilter(getItemCaptionPropertyId(),
-                        filterString, true, true);
-                break;
-            case FILTERINGMODE_CONTAINS:
-                filter = new SimpleStringFilter(getItemCaptionPropertyId(),
-                        filterString, true, false);
-                break;
-            }
-        }
-        return filter;
-    }
-
-    @Override
-    public void containerItemSetChange(Container.ItemSetChangeEvent event) {
-        if (!filteringContainer) {
-            super.containerItemSetChange(event);
-        }
-    }
-
-    /**
-     * Makes correct sublist of given list of options.
-     * 
-     * If paint is not an option request (affected by page or filter change),
-     * page will be the one where possible selection exists.
-     * 
-     * Detects proper first and last item in list to return right page of
-     * options. Also, if the current page is beyond the end of the list, it will
-     * be adjusted.
-     * 
-     * @param options
-     * @param needNullSelectOption
-     *            flag to indicate if nullselect option needs to be taken into
-     *            consideration
-     */
-    private List<?> sanitetizeList(List<?> options, boolean needNullSelectOption) {
-
-        if (pageLength != 0 && options.size() > pageLength) {
-
-            int indexToEnsureInView = -1;
-
-            // if not an option request (item list when user changes page), go
-            // to page with the selected item after filtering if accepted by
-            // filter
-            Object selection = getValue();
-            if (isScrollToSelectedItem() && !optionRequest && !isMultiSelect()
-                    && selection != null) {
-                // ensure proper page
-                indexToEnsureInView = options.indexOf(selection);
-            }
-
-            int size = options.size();
-            currentPage = adjustCurrentPage(currentPage, needNullSelectOption,
-                    indexToEnsureInView, size);
-            int first = getFirstItemIndexOnCurrentPage(needNullSelectOption,
-                    size);
-            int last = getLastItemIndexOnCurrentPage(needNullSelectOption,
-                    size, first);
-            return options.subList(first, last + 1);
-        } else {
-            return options;
-        }
-    }
-
-    /**
-     * Returns the index of the first item on the current page. The index is to
-     * the underlying (possibly filtered) contents. The null item, if any, does
-     * not have an index but takes up a slot on the first page.
-     * 
-     * @param needNullSelectOption
-     *            true if a null option should be shown before any other options
-     *            (takes up the first slot on the first page, not counted in
-     *            index)
-     * @param size
-     *            number of items after filtering (not including the null item,
-     *            if any)
-     * @return first item to show on the UI (index to the filtered list of
-     *         options, not taking the null item into consideration if any)
-     */
-    private int getFirstItemIndexOnCurrentPage(boolean needNullSelectOption,
-            int size) {
-        // Not all options are visible, find out which ones are on the
-        // current "page".
-        int first = currentPage * pageLength;
-        if (needNullSelectOption && currentPage > 0) {
-            first--;
-        }
-        return first;
-    }
-
-    /**
-     * Returns the index of the last item on the current page. The index is to
-     * the underlying (possibly filtered) contents. If needNullSelectOption is
-     * true, the null item takes up the first slot on the first page,
-     * effectively reducing the first page size by one.
-     * 
-     * @param needNullSelectOption
-     *            true if a null option should be shown before any other options
-     *            (takes up the first slot on the first page, not counted in
-     *            index)
-     * @param size
-     *            number of items after filtering (not including the null item,
-     *            if any)
-     * @param first
-     *            index in the filtered view of the first item of the page
-     * @return index in the filtered view of the last item on the page
-     */
-    private int getLastItemIndexOnCurrentPage(boolean needNullSelectOption,
-            int size, int first) {
-        // page length usable for non-null items
-        int effectivePageLength = pageLength
-                - (needNullSelectOption && (currentPage == 0) ? 1 : 0);
-        return Math.min(size - 1, first + effectivePageLength - 1);
-    }
-
-    /**
-     * Adjusts the index of the current page if necessary: make sure the current
-     * page is not after the end of the contents, and optionally go to the page
-     * containg a specific item. There are no side effects but the adjusted page
-     * index is returned.
-     * 
-     * @param page
-     *            page number to use as the starting point
-     * @param needNullSelectOption
-     *            true if a null option should be shown before any other options
-     *            (takes up the first slot on the first page, not counted in
-     *            index)
-     * @param indexToEnsureInView
-     *            index of an item that should be included on the page (in the
-     *            data set, not counting the null item if any), -1 for none
-     * @param size
-     *            number of items after filtering (not including the null item,
-     *            if any)
-     */
-    private int adjustCurrentPage(int page, boolean needNullSelectOption,
-            int indexToEnsureInView, int size) {
-        if (indexToEnsureInView != -1) {
-            int newPage = (indexToEnsureInView + (needNullSelectOption ? 1 : 0))
-                    / pageLength;
-            page = newPage;
-        }
-        // adjust the current page if beyond the end of the list
-        if (page * pageLength > size) {
-            page = (size + (needNullSelectOption ? 1 : 0)) / pageLength;
-        }
-        return page;
-    }
-
-    /**
-     * Filters the options in memory and returns the full filtered list.
-     * 
-     * This can be less efficient than using container filters, so use
-     * {@link #getOptionsWithFilter(boolean)} if possible (filterable container
-     * and suitable item caption mode etc.).
-     * 
-     * @return
-     */
-    protected List<?> getFilteredOptions() {
-        if (null == filterstring || "".equals(filterstring)
-                || FILTERINGMODE_OFF == filteringMode) {
-            prevfilterstring = null;
-            filteredOptions = new LinkedList<Object>(getItemIds());
-            return filteredOptions;
-        }
-
-        if (filterstring.equals(prevfilterstring)) {
-            return filteredOptions;
-        }
-
-        Collection<?> items;
-        if (prevfilterstring != null
-                && filterstring.startsWith(prevfilterstring)) {
-            items = filteredOptions;
-        } else {
-            items = getItemIds();
-        }
-        prevfilterstring = filterstring;
-
-        filteredOptions = new LinkedList<Object>();
-        for (final Iterator<?> it = items.iterator(); it.hasNext();) {
-            final Object itemId = it.next();
-            String caption = getItemCaption(itemId);
-            if (caption == null || caption.equals("")) {
-                continue;
-            } else {
-                caption = caption.toLowerCase();
-            }
-            switch (filteringMode) {
-            case FILTERINGMODE_CONTAINS:
-                if (caption.indexOf(filterstring) > -1) {
-                    filteredOptions.add(itemId);
-                }
-                break;
-            case FILTERINGMODE_STARTSWITH:
-            default:
-                if (caption.startsWith(filterstring)) {
-                    filteredOptions.add(itemId);
-                }
-                break;
-            }
-        }
-
-        return filteredOptions;
-    }
-
-    /**
-     * Invoked when the value of a variable has changed.
-     * 
-     * @see com.vaadin.ui.AbstractComponent#changeVariables(java.lang.Object,
-     *      java.util.Map)
-     */
-    @Override
-    public void changeVariables(Object source, Map<String, Object> variables) {
-        // Not calling super.changeVariables due the history of select
-        // component hierarchy
-
-        // Selection change
-        if (variables.containsKey("selected")) {
-            final String[] ka = (String[]) variables.get("selected");
-
-            if (isMultiSelect()) {
-                // Multiselect mode
-
-                // TODO Optimize by adding repaintNotNeeded whan applicaple
-
-                // Converts the key-array to id-set
-                final LinkedList<Object> s = new LinkedList<Object>();
-                for (int i = 0; i < ka.length; i++) {
-                    final Object id = itemIdMapper.get(ka[i]);
-                    if (id != null && containsId(id)) {
-                        s.add(id);
-                    }
-                }
-
-                // Limits the deselection to the set of visible items
-                // (non-visible items can not be deselected)
-                final Collection<?> visible = getVisibleItemIds();
-                if (visible != null) {
-                    @SuppressWarnings("unchecked")
-                    Set<Object> newsel = (Set<Object>) getValue();
-                    if (newsel == null) {
-                        newsel = new HashSet<Object>();
-                    } else {
-                        newsel = new HashSet<Object>(newsel);
-                    }
-                    newsel.removeAll(visible);
-                    newsel.addAll(s);
-                    setValue(newsel, true);
-                }
-            } else {
-                // Single select mode
-                if (ka.length == 0) {
-
-                    // Allows deselection only if the deselected item is visible
-                    final Object current = getValue();
-                    final Collection<?> visible = getVisibleItemIds();
-                    if (visible != null && visible.contains(current)) {
-                        setValue(null, true);
-                    }
-                } else {
-                    final Object id = itemIdMapper.get(ka[0]);
-                    if (id != null && id.equals(getNullSelectionItemId())) {
-                        setValue(null, true);
-                    } else {
-                        setValue(id, true);
-                    }
-                }
-            }
-        }
-
-        String newFilter;
-        if ((newFilter = (String) variables.get("filter")) != null) {
-            // this is a filter request
-            currentPage = ((Integer) variables.get("page")).intValue();
-            filterstring = newFilter;
-            if (filterstring != null) {
-                filterstring = filterstring.toLowerCase();
-            }
-            requestRepaint();
-        } else if (isNewItemsAllowed()) {
-            // New option entered (and it is allowed)
-            final String newitem = (String) variables.get("newitem");
-            if (newitem != null && newitem.length() > 0) {
-                getNewItemHandler().addNewItem(newitem);
-                // rebuild list
-                filterstring = null;
-                prevfilterstring = null;
-            }
-        }
-
-        if (variables.containsKey(FocusEvent.EVENT_ID)) {
-            fireEvent(new FocusEvent(this));
-        }
-        if (variables.containsKey(BlurEvent.EVENT_ID)) {
-            fireEvent(new BlurEvent(this));
-        }
-
-    }
-
-    @Override
-    @Deprecated
-    public void requestRepaint() {
-        markAsDirty();
-    }
-
-    @Override
-    public void setFilteringMode(int filteringMode) {
-        this.filteringMode = filteringMode;
-    }
-
-    @Override
-    public int getFilteringMode() {
-        return filteringMode;
-    }
-
-    @Override
-    public void addBlurListener(BlurListener listener) {
-        addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener,
-                BlurListener.blurMethod);
-    }
-
-    /**
-     * @deprecated Since 7.0, replaced by {@link #addBlurListener(BlurListener)}
-     **/
-    @Deprecated
-    public void addListener(BlurListener listener) {
-        addBlurListener(listener);
-    }
-
-    @Override
-    public void removeBlurListener(BlurListener listener) {
-        removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener);
-    }
-
-    /**
-     * @deprecated Since 7.0, replaced by
-     *             {@link #removeBlurListener(BlurListener)}
-     **/
-    @Deprecated
-    public void removeListener(BlurListener listener) {
-        removeBlurListener(listener);
-    }
-
-    @Override
-    public void addFocusListener(FocusListener listener) {
-        addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener,
-                FocusListener.focusMethod);
-    }
-
-    /**
-     * @deprecated Since 7.0, replaced by
-     *             {@link #addFocusListener(FocusListener)}
-     **/
-    @Deprecated
-    public void addListener(FocusListener listener) {
-        addFocusListener(listener);
-    }
-
-    @Override
-    public void removeFocusListener(FocusListener listener) {
-        removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener);
-    }
-
-    /**
-     * @deprecated Since 7.0, replaced by
-     *             {@link #removeFocusListener(FocusListener)}
-     **/
-    @Deprecated
-    public void removeListener(FocusListener listener) {
-        removeFocusListener(listener);
-    }
-
-    /**
-     * @deprecated use {@link ListSelect}, {@link OptionGroup} or
-     *             {@link TwinColSelect} instead
-     * @see com.vaadin.ui.AbstractSelect#setMultiSelect(boolean)
-     * @throws UnsupportedOperationException
-     *             if trying to activate multiselect mode
-     */
-    @Deprecated
-    @Override
-    public void setMultiSelect(boolean multiSelect) {
-        if (multiSelect) {
-            throw new UnsupportedOperationException("Multiselect not supported");
-        }
-    }
-
-    /**
-     * @deprecated use {@link ListSelect}, {@link OptionGroup} or
-     *             {@link TwinColSelect} instead
-     * 
-     * @see com.vaadin.ui.AbstractSelect#isMultiSelect()
-     */
-    @Deprecated
-    @Override
-    public boolean isMultiSelect() {
-        return super.isMultiSelect();
-    }
-
-    /**
-     * Sets whether to scroll the selected item visible (directly open the page
-     * on which it is) when opening the combo box popup or not. Only applies to
-     * single select mode.
-     * 
-     * This requires finding the index of the item, which can be expensive in
-     * many large lazy loading containers.
-     * 
-     * @param scrollToSelectedItem
-     *            true to find the page with the selected item when opening the
-     *            selection popup
-     */
-    public void setScrollToSelectedItem(boolean scrollToSelectedItem) {
-        this.scrollToSelectedItem = scrollToSelectedItem;
-    }
-
-    /**
-     * Returns true if the select should find the page with the selected item
-     * when opening the popup (single select combo box only).
-     * 
-     * @see #setScrollToSelectedItem(boolean)
-     * 
-     * @return true if the page with the selected item will be shown when
-     *         opening the popup
-     */
-    public boolean isScrollToSelectedItem() {
-        return scrollToSelectedItem;
-    }
-
 }
index 7b241c9fe1c2bdd3f7f5a0a4f06e61af29cb8cfb..c72fdd71326736e28afd469ee9dec05a16508966 100644 (file)
@@ -3,29 +3,28 @@ package com.vaadin.tests.components.combobox;
 import java.util.LinkedHashMap;
 
 import com.vaadin.server.Resource;
-import com.vaadin.tests.components.select.SelectTest;
+import com.vaadin.tests.components.select.AbstractSelectTestCase;
 import com.vaadin.ui.ComboBox;
-import com.vaadin.ui.Select;
 
-public class ComboBoxes2 extends SelectTest<ComboBox> {
+public class ComboBoxes2<T extends ComboBox> extends AbstractSelectTestCase<T> {
 
-    private Command<ComboBox, String> inputPromptCommand = new Command<ComboBox, String>() {
+    private Command<T, String> inputPromptCommand = new Command<T, String>() {
         @Override
-        public void execute(ComboBox c, String value, Object data) {
+        public void execute(T c, String value, Object data) {
             c.setInputPrompt(value);
         }
     };
-    private Command<ComboBox, Integer> filteringModeCommand = new Command<ComboBox, Integer>() {
+    private Command<T, Integer> filteringModeCommand = new Command<T, Integer>() {
 
         @Override
-        public void execute(ComboBox c, Integer value, Object data) {
+        public void execute(T c, Integer value, Object data) {
             c.setFilteringMode(value);
         }
     };
 
     @Override
-    protected Class<ComboBox> getTestClass() {
-        return ComboBox.class;
+    protected Class<T> getTestClass() {
+        return (Class<T>) ComboBox.class;
     }
 
     @Override
@@ -40,9 +39,9 @@ public class ComboBoxes2 extends SelectTest<ComboBox> {
 
     private void createTextInputAlowedAction(String category) {
         createBooleanAction("Text input allowed", category, true,
-                new Command<ComboBox, Boolean>() {
+                new Command<T, Boolean>() {
                     @Override
-                    public void execute(ComboBox c, Boolean value, Object data) {
+                    public void execute(T c, Boolean value, Object data) {
                         c.setTextInputAllowed(value.booleanValue());
                     }
                 });
@@ -50,9 +49,9 @@ public class ComboBoxes2 extends SelectTest<ComboBox> {
 
     private void createNewItemsAllowedAction(String category) {
         createBooleanAction("New items allowed", category, false,
-                new Command<ComboBox, Boolean>() {
+                new Command<T, Boolean>() {
                     @Override
-                    public void execute(ComboBox c, Boolean value, Object data) {
+                    public void execute(T c, Boolean value, Object data) {
                         c.setNewItemsAllowed(value.booleanValue());
                     }
                 });
@@ -60,9 +59,9 @@ public class ComboBoxes2 extends SelectTest<ComboBox> {
 
     private void createFilteringModeAction(String category) {
         LinkedHashMap<String, Integer> options = new LinkedHashMap<String, Integer>();
-        options.put("Off", Select.FILTERINGMODE_OFF);
-        options.put("Contains", Select.FILTERINGMODE_CONTAINS);
-        options.put("Starts with", Select.FILTERINGMODE_STARTSWITH);
+        options.put("Off", ComboBox.FILTERINGMODE_OFF);
+        options.put("Contains", ComboBox.FILTERINGMODE_CONTAINS);
+        options.put("Starts with", ComboBox.FILTERINGMODE_STARTSWITH);
 
         createSelectAction("Filtering mode", category, options, "Contains",
                 filteringModeCommand);
@@ -82,10 +81,10 @@ public class ComboBoxes2 extends SelectTest<ComboBox> {
     private void createItemIconSelect(String category) {
 
         createSelectAction("Icon", category, createIconOptions(false), "-",
-                new Command<ComboBox, Resource>() {
+                new Command<T, Resource>() {
 
                     @Override
-                    public void execute(ComboBox c, Resource value, Object data) {
+                    public void execute(T c, Resource value, Object data) {
                         for (Object id : c.getItemIds()) {
                             if (value == null) {
                                 c.setItemIcon(id, null);
index 3e409069d017107a28e464303f0ad0625d9d9057..5b2608b389a82a7711aaf91b5f403c2d1a622932 100644 (file)
@@ -8,7 +8,6 @@ import com.vaadin.server.ThemeResource;
 import com.vaadin.tests.components.ComponentTestCase;
 import com.vaadin.ui.ComboBox;
 import com.vaadin.ui.Component;
-import com.vaadin.ui.Select;
 
 public class Comboboxes extends ComponentTestCase<ComboBox> {
 
@@ -83,7 +82,7 @@ public class Comboboxes extends ComponentTestCase<ComboBox> {
         }
     }
 
-    private void populate(Select s, int nr) {
+    private void populate(ComboBox s, int nr) {
         String text = " an item ";
 
         String caption = "";
@@ -99,7 +98,7 @@ public class Comboboxes extends ComponentTestCase<ComboBox> {
 
     }
 
-    private void addItem(Select s, String string) {
+    private void addItem(ComboBox s, String string) {
         Object id = s.addItem();
         s.getItem(id).getItemProperty(CAPTION).setValue(string);
 
index f64fd6f5fa4e3c9f349090c9e750e6ecddd78137..c93da483ab228ed2a081cf84f13450bdc30c7937 100644 (file)
@@ -6,7 +6,6 @@ import com.vaadin.ui.GridLayout;
 import com.vaadin.ui.Label;
 import com.vaadin.ui.Layout;
 import com.vaadin.ui.UI;
-import com.vaadin.ui.Select;
 
 @SuppressWarnings("serial")
 public class GridLayoutComboBoxZoomOut extends AbstractTestCase {
@@ -26,7 +25,7 @@ public class GridLayoutComboBoxZoomOut extends AbstractTestCase {
         // formLayout.setWidth("100%");
         formLayout.setWidth("1000px");
 
-        Select countryField = new ComboBox();
+        ComboBox countryField = new ComboBox();
         countryField.addItem("Finland");
         countryField.addItem("Sweden");
         countryField.addItem("Canada");
@@ -35,7 +34,7 @@ public class GridLayoutComboBoxZoomOut extends AbstractTestCase {
         countryField.setWidth("100%");
         formLayout.addComponent(countryField);
 
-        Select statusField = new ComboBox();
+        ComboBox statusField = new ComboBox();
         statusField.addItem("Available");
         statusField.addItem("On vacation");
         statusField.addItem("Busy");
index efea50868179d83b134d90a989a8b73bebecd4cb..f19e7ecad2586a904556f454d81f4549b4fda32a 100644 (file)
@@ -1,13 +1,14 @@
 package com.vaadin.tests.components.select;
 
+import com.vaadin.tests.components.combobox.ComboBoxes2;
 import com.vaadin.ui.Select;
 
-public class SelectTest<T extends Select> extends AbstractSelectTestCase<T> {
+public class SelectTest extends ComboBoxes2<Select> {
 
     @SuppressWarnings("unchecked")
     @Override
-    protected Class<T> getTestClass() {
-        return (Class<T>) Select.class;
+    protected Class<Select> getTestClass() {
+        return Select.class;
     }
 
 }