This simplifies the client side state machine.
This change does not modify the CSS class name v-filterselect.
Change-Id: I2f4a6e5252045cb7698d582be90693e00961b342
--- /dev/null
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui;
+
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.widgets.Escalator;
+
+/**
+ * A mousewheel handling class to get around the limits of
+ * {@link Event#ONMOUSEWHEEL}.
+ *
+ * For internal use only. May be removed or replaced in the future.
+ *
+ * @see Escalator.JsniWorkaround
+ */
+// FIXME remove the copy in v7 package
+abstract class JsniMousewheelHandler {
+
+ /**
+ * A JavaScript function that handles the mousewheel DOM event, and passes
+ * it on to Java code.
+ *
+ * @see #createMousewheelListenerFunction(Widget)
+ */
+ protected final JavaScriptObject mousewheelListenerFunction;
+
+ protected JsniMousewheelHandler(final Widget widget) {
+ mousewheelListenerFunction = createMousewheelListenerFunction(widget);
+ }
+
+ /**
+ * A method that constructs the JavaScript function that will be stored into
+ * {@link #mousewheelListenerFunction}.
+ *
+ * @param widget
+ * a reference to the current instance of {@link Widget}
+ */
+ protected abstract JavaScriptObject createMousewheelListenerFunction(
+ Widget widget);
+
+ public native void attachMousewheelListener(Element element)
+ /*-{
+ if (element.addEventListener) {
+ // FireFox likes "wheel", while others use "mousewheel"
+ var eventName = 'onmousewheel' in element ? 'mousewheel' : 'wheel';
+ element.addEventListener(eventName, this.@com.vaadin.client.ui.JsniMousewheelHandler::mousewheelListenerFunction);
+ }
+ }-*/;
+
+ public native void detachMousewheelListener(Element element)
+ /*-{
+ if (element.addEventListener) {
+ // FireFox likes "wheel", while others use "mousewheel"
+ var eventName = element.onwheel===undefined?"mousewheel":"wheel";
+ element.removeEventListener(eventName, this.@com.vaadin.client.ui.JsniMousewheelHandler::mousewheelListenerFunction);
+ }
+ }-*/;
+
+}
--- /dev/null
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.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.aria.client.Roles;
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.Scheduler.ScheduledCommand;
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.NativeEvent;
+import com.google.gwt.dom.client.Style;
+import com.google.gwt.dom.client.Style.Display;
+import com.google.gwt.dom.client.Style.Unit;
+import com.google.gwt.dom.client.Style.Visibility;
+import com.google.gwt.event.dom.client.BlurEvent;
+import com.google.gwt.event.dom.client.BlurHandler;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.FocusEvent;
+import com.google.gwt.event.dom.client.FocusHandler;
+import com.google.gwt.event.dom.client.KeyCodes;
+import com.google.gwt.event.dom.client.KeyDownEvent;
+import com.google.gwt.event.dom.client.KeyDownHandler;
+import com.google.gwt.event.dom.client.KeyUpEvent;
+import com.google.gwt.event.dom.client.KeyUpHandler;
+import com.google.gwt.event.dom.client.LoadEvent;
+import com.google.gwt.event.dom.client.LoadHandler;
+import com.google.gwt.event.dom.client.MouseDownEvent;
+import com.google.gwt.event.dom.client.MouseDownHandler;
+import com.google.gwt.event.logical.shared.CloseEvent;
+import com.google.gwt.event.logical.shared.CloseHandler;
+import com.google.gwt.i18n.client.HasDirection.Direction;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.Window;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.PopupPanel;
+import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
+import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
+import com.google.gwt.user.client.ui.TextBox;
+import com.google.gwt.user.client.ui.Widget;
+import com.vaadin.client.ApplicationConnection;
+import com.vaadin.client.BrowserInfo;
+import com.vaadin.client.ComputedStyle;
+import com.vaadin.client.DeferredWorker;
+import com.vaadin.client.Focusable;
+import com.vaadin.client.VConsole;
+import com.vaadin.client.WidgetUtil;
+import com.vaadin.client.ui.aria.AriaHelper;
+import com.vaadin.client.ui.aria.HandlesAriaCaption;
+import com.vaadin.client.ui.aria.HandlesAriaInvalid;
+import com.vaadin.client.ui.aria.HandlesAriaRequired;
+import com.vaadin.client.ui.combobox.ComboBoxConnector;
+import com.vaadin.client.ui.menubar.MenuBar;
+import com.vaadin.client.ui.menubar.MenuItem;
+import com.vaadin.shared.AbstractComponentState;
+import com.vaadin.shared.ui.ComponentStateUtil;
+import com.vaadin.shared.util.SharedUtil;
+
+/**
+ * Client side implementation of the ComboBox component.
+ *
+ * TODO needs major refactoring (to be extensible etc)
+ */
+@SuppressWarnings("deprecation")
+public class VComboBox extends Composite implements Field, KeyDownHandler,
+ KeyUpHandler, ClickHandler, FocusHandler, BlurHandler, Focusable,
+ SubPartAware, HandlesAriaCaption, HandlesAriaInvalid,
+ HandlesAriaRequired, DeferredWorker, MouseDownHandler {
+
+ /**
+ * Represents a suggestion in the suggestion popup box.
+ */
+ public class ComboBoxSuggestion implements Suggestion, Command {
+
+ private final String key;
+ private final String caption;
+ private String untranslatedIconUri;
+ private String style;
+
+ /**
+ * Constructor for a single suggestion.
+ *
+ * @param key
+ * item key, empty string for a special null item not in
+ * container
+ * @param caption
+ * item caption
+ * @param style
+ * item style name, can be empty string
+ * @param untranslatedIconUri
+ * icon URI or null
+ */
+ public ComboBoxSuggestion(String key, String caption, String style,
+ String untranslatedIconUri) {
+ this.key = key;
+ this.caption = caption;
+ this.style = style;
+ this.untranslatedIconUri = untranslatedIconUri;
+ }
+
+ /**
+ * Gets the visible row in the popup as a HTML string. The string
+ * contains an image tag with the rows icon (if an icon has been
+ * specified) and the caption of the item
+ */
+
+ @Override
+ public String getDisplayString() {
+ final StringBuffer sb = new StringBuffer();
+ ApplicationConnection client = connector.getConnection();
+ final Icon icon = client
+ .getIcon(client.translateVaadinUri(untranslatedIconUri));
+ if (icon != null) {
+ sb.append(icon.getElement().getString());
+ }
+ String content;
+ if ("".equals(caption)) {
+ // Ensure that empty options use the same height as other
+ // options and are not collapsed (#7506)
+ content = " ";
+ } else {
+ content = WidgetUtil.escapeHTML(caption);
+ }
+ sb.append("<span>" + content + "</span>");
+ return sb.toString();
+ }
+
+ /**
+ * Get a string that represents this item. This is used in the text box.
+ */
+
+ @Override
+ public String getReplacementString() {
+ return caption;
+ }
+
+ /**
+ * Get the option key which represents the item on the server side.
+ *
+ * @return The key of the item
+ */
+ public String getOptionKey() {
+ return key;
+ }
+
+ /**
+ * Get the URI of the icon. Used when constructing the displayed option.
+ *
+ * @return real (translated) icon URI or null if none
+ */
+ public String getIconUri() {
+ ApplicationConnection client = connector.getConnection();
+ return client.translateVaadinUri(untranslatedIconUri);
+ }
+
+ /**
+ * Gets the style set for this suggestion item. Styles are typically set
+ * by a server-side {@link com.vaadin.ui.ComboBox.ItemStyleProvider}.
+ * The returned style is prefixed by <code>v-filterselect-item-</code>.
+ *
+ * @since 7.5.6
+ * @return the style name to use, or <code>null</code> to not apply any
+ * custom style.
+ */
+ public String getStyle() {
+ return style;
+ }
+
+ /**
+ * Executes a selection of this item.
+ */
+
+ @Override
+ public void execute() {
+ onSuggestionSelected(this);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ComboBoxSuggestion)) {
+ return false;
+ }
+ ComboBoxSuggestion other = (ComboBoxSuggestion) obj;
+ if ((key == null && other.key != null)
+ || (key != null && !key.equals(other.key))) {
+ return false;
+ }
+ if ((caption == null && other.caption != null)
+ || (caption != null && !caption.equals(other.caption))) {
+ return false;
+ }
+ if (!SharedUtil.equals(untranslatedIconUri,
+ other.untranslatedIconUri)) {
+ return false;
+ }
+ if (!SharedUtil.equals(style, other.style)) {
+ return false;
+ }
+ return true;
+ }
+ }
+
+ /** An inner class that handles all logic related to mouse wheel. */
+ private class MouseWheeler extends JsniMousewheelHandler {
+
+ public MouseWheeler() {
+ super(VComboBox.this);
+ }
+
+ @Override
+ protected native JavaScriptObject createMousewheelListenerFunction(
+ Widget widget)
+ /*-{
+ return $entry(function(e) {
+ var deltaX = e.deltaX ? e.deltaX : -0.5*e.wheelDeltaX;
+ var deltaY = e.deltaY ? e.deltaY : -0.5*e.wheelDeltaY;
+
+ // IE8 has only delta y
+ if (isNaN(deltaY)) {
+ deltaY = -0.5*e.wheelDelta;
+ }
+
+ @com.vaadin.client.ui.VComboBox.JsniUtil::moveScrollFromEvent(*)(widget, deltaX, deltaY, e, e.deltaMode);
+ });
+ }-*/;
+
+ }
+
+ /**
+ * A utility class that contains utility methods that are usually called
+ * from JSNI.
+ * <p>
+ * The methods are moved in this class to minimize the amount of JSNI code
+ * as much as feasible.
+ */
+ static class JsniUtil {
+ private static final int DOM_DELTA_PIXEL = 0;
+ private static final int DOM_DELTA_LINE = 1;
+ private static final int DOM_DELTA_PAGE = 2;
+
+ // Rough estimation of item height
+ private static final int SCROLL_UNIT_PX = 25;
+
+ private static double deltaSum = 0;
+
+ public static void moveScrollFromEvent(final Widget widget,
+ final double deltaX, final double deltaY,
+ final NativeEvent event, final int deltaMode) {
+
+ if (!Double.isNaN(deltaY)) {
+ VComboBox filterSelect = (VComboBox) widget;
+
+ switch (deltaMode) {
+ case DOM_DELTA_LINE:
+ if (deltaY >= 0) {
+ filterSelect.suggestionPopup.selectNextItem();
+ } else {
+ filterSelect.suggestionPopup.selectPrevItem();
+ }
+ break;
+ case DOM_DELTA_PAGE:
+ if (deltaY >= 0) {
+ filterSelect.selectNextPage();
+ } else {
+ filterSelect.selectPrevPage();
+ }
+ break;
+ case DOM_DELTA_PIXEL:
+ default:
+ // Accumulate dampened deltas
+ deltaSum += Math.pow(Math.abs(deltaY), 0.7)
+ * Math.signum(deltaY);
+
+ // "Scroll" if change exceeds item height
+ while (Math.abs(deltaSum) >= SCROLL_UNIT_PX) {
+ if (!filterSelect.dataReceivedHandler
+ .isWaitingForFilteringResponse()) {
+ // Move selection if page flip is not in progress
+ if (deltaSum < 0) {
+ filterSelect.suggestionPopup.selectPrevItem();
+ } else {
+ filterSelect.suggestionPopup.selectNextItem();
+ }
+ }
+ deltaSum -= SCROLL_UNIT_PX * Math.signum(deltaSum);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Represents the popup box with the selection options. Wraps a suggestion
+ * menu.
+ */
+ public class SuggestionPopup extends VOverlay
+ implements PositionCallback, CloseHandler<PopupPanel> {
+
+ private static final int Z_INDEX = 30000;
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public final SuggestionMenu menu;
+
+ private final Element up = DOM.createDiv();
+ private final Element down = DOM.createDiv();
+ private final Element status = DOM.createDiv();
+
+ private boolean isPagingEnabled = true;
+
+ private long lastAutoClosed;
+
+ private int popupOuterPadding = -1;
+
+ private int topPosition;
+
+ private final MouseWheeler mouseWheeler = new MouseWheeler();
+
+ /**
+ * Default constructor
+ */
+ SuggestionPopup() {
+ super(true, false);
+ debug("VComboBox.SP: constructor()");
+ setOwner(VComboBox.this);
+ menu = new SuggestionMenu();
+ setWidget(menu);
+
+ getElement().getStyle().setZIndex(Z_INDEX);
+
+ final Element root = getContainerElement();
+
+ up.setInnerHTML("<span>Prev</span>");
+ DOM.sinkEvents(up, Event.ONCLICK);
+
+ down.setInnerHTML("<span>Next</span>");
+ DOM.sinkEvents(down, Event.ONCLICK);
+
+ root.insertFirst(up);
+ root.appendChild(down);
+ root.appendChild(status);
+
+ DOM.sinkEvents(root, Event.ONMOUSEDOWN | Event.ONMOUSEWHEEL);
+ addCloseHandler(this);
+
+ Roles.getListRole().set(getElement());
+
+ setPreviewingAllNativeEvents(true);
+ }
+
+ @Override
+ protected void onLoad() {
+ super.onLoad();
+
+ // Register mousewheel listener on paged select
+ if (pageLength > 0) {
+ mouseWheeler.attachMousewheelListener(getElement());
+ }
+ }
+
+ @Override
+ protected void onUnload() {
+ mouseWheeler.detachMousewheelListener(getElement());
+ super.onUnload();
+ }
+
+ /**
+ * Shows the popup where the user can see the filtered options that have
+ * been set with a call to
+ * {@link SuggestionMenu#setSuggestions(Collection)}.
+ *
+ * @param currentPage
+ * The current page number
+ * @param totalSuggestions
+ * The total amount of suggestions
+ */
+ public void showSuggestions(final int currentPage,
+ final int totalSuggestions) {
+
+ debug("VComboBox.SP: showSuggestions(" + currentPage + ", "
+ + totalSuggestions + ")");
+
+ final SuggestionPopup popup = this;
+ // Add TT anchor point
+ getElement().setId("VAADIN_COMBOBOX_OPTIONLIST");
+
+ final int x = VComboBox.this.getAbsoluteLeft();
+
+ topPosition = tb.getAbsoluteTop();
+ topPosition += tb.getOffsetHeight();
+
+ setPopupPosition(x, topPosition);
+
+ int nullOffset = (nullSelectionAllowed && "".equals(lastFilter) ? 1
+ : 0);
+ boolean firstPage = (currentPage == 0);
+ final int first = currentPage * pageLength + 1
+ - (firstPage ? 0 : nullOffset);
+ final int last = first + currentSuggestions.size() - 1
+ - (firstPage && "".equals(lastFilter) ? nullOffset : 0);
+ final int matches = totalSuggestions - nullOffset;
+ if (last > 0) {
+ // nullsel not counted, as requested by user
+ status.setInnerText((matches == 0 ? 0 : first) + "-" + last
+ + "/" + matches);
+ } else {
+ status.setInnerText("");
+ }
+ // We don't need to show arrows or statusbar if there is
+ // only one page
+ if (totalSuggestions <= pageLength || pageLength == 0) {
+ setPagingEnabled(false);
+ } else {
+ setPagingEnabled(true);
+ }
+ setPrevButtonActive(first > 1);
+ setNextButtonActive(last < matches);
+
+ // clear previously fixed width
+ menu.setWidth("");
+ menu.getElement().getFirstChildElement().getStyle().clearWidth();
+
+ setPopupPositionAndShow(popup);
+ }
+
+ /**
+ * Should the next page button be visible to the user?
+ *
+ * @param active
+ */
+ private void setNextButtonActive(boolean active) {
+ if (enableDebug) {
+ debug("VComboBox.SP: setNextButtonActive(" + active + ")");
+ }
+ if (active) {
+ DOM.sinkEvents(down, Event.ONCLICK);
+ down.setClassName(
+ VComboBox.this.getStylePrimaryName() + "-nextpage");
+ } else {
+ DOM.sinkEvents(down, 0);
+ down.setClassName(
+ VComboBox.this.getStylePrimaryName() + "-nextpage-off");
+ }
+ }
+
+ /**
+ * Should the previous page button be visible to the user
+ *
+ * @param active
+ */
+ private void setPrevButtonActive(boolean active) {
+ if (enableDebug) {
+ debug("VComboBox.SP: setPrevButtonActive(" + active + ")");
+ }
+
+ if (active) {
+ DOM.sinkEvents(up, Event.ONCLICK);
+ up.setClassName(
+ VComboBox.this.getStylePrimaryName() + "-prevpage");
+ } else {
+ DOM.sinkEvents(up, 0);
+ up.setClassName(
+ VComboBox.this.getStylePrimaryName() + "-prevpage-off");
+ }
+
+ }
+
+ /**
+ * Selects the next item in the filtered selections.
+ */
+ public void selectNextItem() {
+ debug("VComboBox.SP: selectNextItem()");
+
+ final int index = menu.getSelectedIndex() + 1;
+ if (menu.getItems().size() > index) {
+ selectItem(menu.getItems().get(index));
+
+ } else {
+ selectNextPage();
+ }
+ }
+
+ /**
+ * Selects the previous item in the filtered selections.
+ */
+ public void selectPrevItem() {
+ debug("VComboBox.SP: selectPrevItem()");
+
+ final int index = menu.getSelectedIndex() - 1;
+ if (index > -1) {
+ selectItem(menu.getItems().get(index));
+
+ } else if (index == -1) {
+ selectPrevPage();
+
+ } else {
+ if (!menu.getItems().isEmpty()) {
+ selectLastItem();
+ }
+ }
+ }
+
+ /**
+ * Select the first item of the suggestions list popup.
+ *
+ * @since 7.2.6
+ */
+ public void selectFirstItem() {
+ debug("VComboBox.SP: selectFirstItem()");
+ selectItem(menu.getFirstItem());
+ }
+
+ /**
+ * Select the last item of the suggestions list popup.
+ *
+ * @since 7.2.6
+ */
+ public void selectLastItem() {
+ debug("VComboBox.SP: selectLastItem()");
+ selectItem(menu.getLastItem());
+ }
+
+ /*
+ * Sets the selected item in the popup menu.
+ */
+ private void selectItem(final MenuItem newSelectedItem) {
+ menu.selectItem(newSelectedItem);
+
+ // Set the icon.
+ ComboBoxSuggestion suggestion = (ComboBoxSuggestion) newSelectedItem
+ .getCommand();
+ setSelectedItemIcon(suggestion.getIconUri());
+
+ // Set the text.
+ setText(suggestion.getReplacementString());
+
+ }
+
+ /*
+ * Using a timer to scroll up or down the pages so when we receive lots
+ * of consecutive mouse wheel events the pages does not flicker.
+ */
+ private LazyPageScroller lazyPageScroller = new LazyPageScroller();
+
+ private class LazyPageScroller extends Timer {
+ private int pagesToScroll = 0;
+
+ @Override
+ public void run() {
+ debug("VComboBox.SP.LPS: run()");
+ if (pagesToScroll != 0) {
+ if (!dataReceivedHandler.isWaitingForFilteringResponse()) {
+ /*
+ * 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.
+ */
+ // this makes sure that we don't close the popup
+ dataReceivedHandler.setNavigationCallback(() -> {
+ });
+ filterOptions(currentPage + pagesToScroll, lastFilter);
+ }
+ pagesToScroll = 0;
+ }
+ }
+
+ public void scrollUp() {
+ debug("VComboBox.SP.LPS: scrollUp()");
+ if (pageLength > 0 && currentPage + pagesToScroll > 0) {
+ pagesToScroll--;
+ cancel();
+ schedule(200);
+ }
+ }
+
+ public void scrollDown() {
+ debug("VComboBox.SP.LPS: scrollDown()");
+ if (pageLength > 0
+ && totalMatches > (currentPage + pagesToScroll + 1)
+ * pageLength) {
+ pagesToScroll++;
+ cancel();
+ schedule(200);
+ }
+ }
+ }
+
+ private void scroll(double deltaY) {
+ boolean scrollActive = menu.isScrollActive();
+
+ debug("VComboBox.SP: scroll() scrollActive: " + scrollActive);
+
+ if (!scrollActive) {
+ if (deltaY > 0d) {
+ lazyPageScroller.scrollDown();
+ } else {
+ lazyPageScroller.scrollUp();
+ }
+ }
+ }
+
+ @Override
+ public void onBrowserEvent(Event event) {
+ debug("VComboBox.SP: onBrowserEvent()");
+
+ if (event.getTypeInt() == Event.ONCLICK) {
+ final Element target = DOM.eventGetTarget(event);
+ if (target == up || target == DOM.getChild(up, 0)) {
+ lazyPageScroller.scrollUp();
+ } else if (target == down || target == DOM.getChild(down, 0)) {
+ lazyPageScroller.scrollDown();
+ }
+
+ }
+
+ /*
+ * Prevent the keyboard focus from leaving the textfield by
+ * preventing the default behaviour of the browser. Fixes #4285.
+ */
+ handleMouseDownEvent(event);
+ }
+
+ /**
+ * Should paging be enabled. If paging is enabled then only a certain
+ * amount of items are visible at a time and a scrollbar or buttons are
+ * visible to change page. If paging is turned of then all options are
+ * rendered into the popup menu.
+ *
+ * @param paging
+ * Should the paging be turned on?
+ */
+ public void setPagingEnabled(boolean paging) {
+ debug("VComboBox.SP: setPagingEnabled(" + paging + ")");
+ if (isPagingEnabled == paging) {
+ return;
+ }
+ if (paging) {
+ down.getStyle().clearDisplay();
+ up.getStyle().clearDisplay();
+ status.getStyle().clearDisplay();
+ } else {
+ down.getStyle().setDisplay(Display.NONE);
+ up.getStyle().setDisplay(Display.NONE);
+ status.getStyle().setDisplay(Display.NONE);
+ }
+ isPagingEnabled = paging;
+ }
+
+ @Override
+ public void setPosition(int offsetWidth, int offsetHeight) {
+ debug("VComboBox.SP: setPosition(" + offsetWidth + ", "
+ + offsetHeight + ")");
+
+ int top = topPosition;
+ int left = getPopupLeft();
+
+ // reset menu size and retrieve its "natural" size
+ menu.setHeight("");
+ if (currentPage > 0 && !hasNextPage()) {
+ // fix height to avoid height change when getting to last page
+ menu.fixHeightTo(pageLength);
+ }
+
+ // ignoring the parameter as in V7
+ offsetHeight = getOffsetHeight();
+ final int desiredHeight = offsetHeight;
+ final int desiredWidth = getMainWidth();
+
+ debug("VComboBox.SP: desired[" + desiredWidth + ", "
+ + desiredHeight + "]");
+
+ Element menuFirstChild = menu.getElement().getFirstChildElement();
+ int naturalMenuWidth;
+ if (BrowserInfo.get().isIE()
+ && BrowserInfo.get().getBrowserMajorVersion() < 10) {
+ // On IE 8 & 9 visibility is set to hidden and measuring
+ // elements while they are hidden yields incorrect results
+ String before = menu.getElement().getParentElement().getStyle()
+ .getVisibility();
+ menu.getElement().getParentElement().getStyle()
+ .setVisibility(Visibility.VISIBLE);
+ naturalMenuWidth = WidgetUtil.getRequiredWidth(menuFirstChild);
+ menu.getElement().getParentElement().getStyle()
+ .setProperty("visibility", before);
+ } else {
+ naturalMenuWidth = WidgetUtil.getRequiredWidth(menuFirstChild);
+ }
+
+ if (popupOuterPadding == -1) {
+ popupOuterPadding = WidgetUtil
+ .measureHorizontalPaddingAndBorder(menu.getElement(), 2)
+ + WidgetUtil.measureHorizontalPaddingAndBorder(
+ suggestionPopup.getElement(), 0);
+ }
+
+ updateMenuWidth(desiredWidth, naturalMenuWidth);
+
+ if (BrowserInfo.get().isIE()
+ && BrowserInfo.get().getBrowserMajorVersion() < 11) {
+ // Must take margin,border,padding manually into account for
+ // menu element as we measure the element child and set width to
+ // the element parent
+
+ double naturalMenuOuterWidth;
+ if (BrowserInfo.get().getBrowserMajorVersion() < 10) {
+ // On IE 8 & 9 visibility is set to hidden and measuring
+ // elements while they are hidden yields incorrect results
+ String before = menu.getElement().getParentElement()
+ .getStyle().getVisibility();
+ menu.getElement().getParentElement().getStyle()
+ .setVisibility(Visibility.VISIBLE);
+ naturalMenuOuterWidth = WidgetUtil
+ .getRequiredWidthDouble(menuFirstChild)
+ + getMarginBorderPaddingWidth(menu.getElement());
+ menu.getElement().getParentElement().getStyle()
+ .setProperty("visibility", before);
+ } else {
+ naturalMenuOuterWidth = WidgetUtil
+ .getRequiredWidthDouble(menuFirstChild)
+ + getMarginBorderPaddingWidth(menu.getElement());
+ }
+
+ /*
+ * IE requires us to specify the width for the container
+ * element. Otherwise it will be 100% wide
+ */
+ double rootWidth = Math.max(desiredWidth - popupOuterPadding,
+ naturalMenuOuterWidth);
+ getContainerElement().getStyle().setWidth(rootWidth, Unit.PX);
+ }
+
+ final int textInputHeight = VComboBox.this.getOffsetHeight();
+ final int textInputTopOnPage = tb.getAbsoluteTop();
+ final int viewportOffset = Document.get().getScrollTop();
+ final int textInputTopInViewport = textInputTopOnPage
+ - viewportOffset;
+ final int textInputBottomInViewport = textInputTopInViewport
+ + textInputHeight;
+
+ final int spaceAboveInViewport = textInputTopInViewport;
+ final int spaceBelowInViewport = Window.getClientHeight()
+ - textInputBottomInViewport;
+
+ if (spaceBelowInViewport < offsetHeight
+ && spaceBelowInViewport < spaceAboveInViewport) {
+ // popup on top of input instead
+ if (offsetHeight > spaceAboveInViewport) {
+ // Shrink popup height to fit above
+ offsetHeight = spaceAboveInViewport;
+ }
+ top = textInputTopOnPage - offsetHeight;
+ } else {
+ // Show below, position calculated in showSuggestions for some
+ // strange reason
+ top = topPosition;
+ offsetHeight = Math.min(offsetHeight, spaceBelowInViewport);
+ }
+
+ // fetch real width (mac FF bugs here due GWT popups overflow:auto )
+ offsetWidth = menuFirstChild.getOffsetWidth();
+
+ if (offsetHeight < desiredHeight) {
+ int menuHeight = offsetHeight;
+ if (isPagingEnabled) {
+ menuHeight -= up.getOffsetHeight() + down.getOffsetHeight()
+ + status.getOffsetHeight();
+ } else {
+ final ComputedStyle s = new ComputedStyle(
+ menu.getElement());
+ menuHeight -= s.getIntProperty("marginBottom")
+ + s.getIntProperty("marginTop");
+ }
+
+ // If the available page height is really tiny then this will be
+ // negative and an exception will be thrown on setHeight.
+ int menuElementHeight = menu.getItemOffsetHeight();
+ if (menuHeight < menuElementHeight) {
+ menuHeight = menuElementHeight;
+ }
+
+ menu.setHeight(menuHeight + "px");
+
+ if (suggestionPopupWidth == null) {
+ final int naturalMenuWidthPlusScrollBar = naturalMenuWidth
+ + WidgetUtil.getNativeScrollbarSize();
+ if (offsetWidth < naturalMenuWidthPlusScrollBar) {
+ menu.setWidth(naturalMenuWidthPlusScrollBar + "px");
+ }
+ }
+ }
+
+ if (offsetWidth + left > Window.getClientWidth()) {
+ left = VComboBox.this.getAbsoluteLeft()
+ + VComboBox.this.getOffsetWidth() - offsetWidth;
+ if (left < 0) {
+ left = 0;
+ menu.setWidth(Window.getClientWidth() + "px");
+
+ }
+ }
+
+ setPopupPosition(left, top);
+ menu.scrollSelectionIntoView();
+ }
+
+ /**
+ * Adds in-line CSS rules to the DOM according to the
+ * suggestionPopupWidth field
+ *
+ * @param desiredWidth
+ * @param naturalMenuWidth
+ */
+ private void updateMenuWidth(final int desiredWidth,
+ int naturalMenuWidth) {
+ /**
+ * Three different width modes for the suggestion pop-up:
+ *
+ * 1. Legacy "null"-mode: width is determined by the longest item
+ * caption for each page while still maintaining minimum width of
+ * (desiredWidth - popupOuterPadding)
+ *
+ * 2. relative to the component itself
+ *
+ * 3. fixed width
+ */
+ String width = "auto";
+ if (suggestionPopupWidth == null) {
+ if (naturalMenuWidth < desiredWidth) {
+ naturalMenuWidth = desiredWidth - popupOuterPadding;
+ width = (desiredWidth - popupOuterPadding) + "px";
+ }
+ } else if (isrelativeUnits(suggestionPopupWidth)) {
+ float mainComponentWidth = desiredWidth - popupOuterPadding;
+ // convert percentage value to fraction
+ int widthInPx = Math.round(
+ mainComponentWidth * asFraction(suggestionPopupWidth));
+ width = widthInPx + "px";
+ } else {
+ // use as fixed width CSS definition
+ width = WidgetUtil.escapeAttribute(suggestionPopupWidth);
+ }
+ menu.setWidth(width);
+ }
+
+ /**
+ * Returns the percentage value as a fraction, e.g. 42% -> 0.42
+ *
+ * @param percentage
+ */
+ private float asFraction(String percentage) {
+ String trimmed = percentage.trim();
+ String withoutPercentSign = trimmed.substring(0,
+ trimmed.length() - 1);
+ float asFraction = Float.parseFloat(withoutPercentSign) / 100;
+ return asFraction;
+ }
+
+ /**
+ * @since 7.7
+ * @param suggestionPopupWidth
+ * @return
+ */
+ private boolean isrelativeUnits(String suggestionPopupWidth) {
+ return suggestionPopupWidth.trim().endsWith("%");
+ }
+
+ /**
+ * Was the popup just closed?
+ *
+ * @return true if popup was just closed
+ */
+ public boolean isJustClosed() {
+ debug("VComboBox.SP: justClosed()");
+ final long now = (new Date()).getTime();
+ return (lastAutoClosed > 0 && (now - lastAutoClosed) < 200);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.logical.shared.CloseHandler#onClose(com.google
+ * .gwt.event.logical.shared.CloseEvent)
+ */
+
+ @Override
+ public void onClose(CloseEvent<PopupPanel> event) {
+ if (enableDebug) {
+ debug("VComboBox.SP: onClose(" + event.isAutoClosed() + ")");
+ }
+ if (event.isAutoClosed()) {
+ lastAutoClosed = (new Date()).getTime();
+ }
+ }
+
+ /**
+ * Updates style names in suggestion popup to help theme building.
+ *
+ * @param componentState
+ * shared state of the combo box
+ */
+ public void updateStyleNames(AbstractComponentState componentState) {
+ debug("VComboBox.SP: updateStyleNames()");
+ setStyleName(
+ VComboBox.this.getStylePrimaryName() + "-suggestpopup");
+ menu.setStyleName(
+ VComboBox.this.getStylePrimaryName() + "-suggestmenu");
+ status.setClassName(
+ VComboBox.this.getStylePrimaryName() + "-status");
+ if (ComponentStateUtil.hasStyles(componentState)) {
+ for (String style : componentState.styles) {
+ if (!"".equals(style)) {
+ addStyleDependentName(style);
+ }
+ }
+ }
+ }
+
+ }
+
+ /**
+ * The menu where the suggestions are rendered
+ */
+ public class SuggestionMenu extends MenuBar
+ implements SubPartAware, LoadHandler {
+
+ private VLazyExecutor delayedImageLoadExecutioner = new VLazyExecutor(
+ 100, new ScheduledCommand() {
+
+ @Override
+ public void execute() {
+ debug("VComboBox.SM: delayedImageLoadExecutioner()");
+ if (suggestionPopup.isVisible()
+ && suggestionPopup.isAttached()) {
+ setWidth("");
+ getElement().getFirstChildElement().getStyle()
+ .clearWidth();
+ suggestionPopup
+ .setPopupPositionAndShow(suggestionPopup);
+ }
+
+ }
+ });
+
+ /**
+ * Default constructor
+ */
+ SuggestionMenu() {
+ super(true);
+ debug("VComboBox.SM: constructor()");
+ addDomHandler(this, LoadEvent.getType());
+
+ setScrollEnabled(true);
+ }
+
+ /**
+ * Fixes menus height to use same space as full page would use. Needed
+ * to avoid height changes when quickly "scrolling" to last page.
+ */
+ public void fixHeightTo(int pageItemsCount) {
+ setHeight(getPreferredHeight(pageItemsCount));
+ }
+
+ /*
+ * Gets the preferred height of the menu including pageItemsCount items.
+ */
+ String getPreferredHeight(int pageItemsCount) {
+ if (currentSuggestions.size() > 0) {
+ final int pixels = (getPreferredHeight()
+ / currentSuggestions.size()) * pageItemsCount;
+ return pixels + "px";
+ } else {
+ return "";
+ }
+ }
+
+ /**
+ * Sets the suggestions rendered in the menu.
+ *
+ * @param suggestions
+ * The suggestions to be rendered in the menu
+ */
+ public void setSuggestions(Collection<ComboBoxSuggestion> suggestions) {
+ if (enableDebug) {
+ debug("VComboBox.SM: setSuggestions(" + suggestions + ")");
+ }
+
+ clearItems();
+ final Iterator<ComboBoxSuggestion> it = suggestions.iterator();
+ boolean isFirstIteration = true;
+ while (it.hasNext()) {
+ final ComboBoxSuggestion s = it.next();
+ final MenuItem mi = new MenuItem(s.getDisplayString(), true, s);
+ String style = s.getStyle();
+ if (style != null) {
+ mi.addStyleName("v-filterselect-item-" + style);
+ }
+ Roles.getListitemRole().set(mi.getElement());
+
+ WidgetUtil.sinkOnloadForImages(mi.getElement());
+
+ this.addItem(mi);
+
+ // By default, first item on the list is always highlighted,
+ // unless adding new items is allowed.
+ if (isFirstIteration && !allowNewItems) {
+ selectItem(mi);
+ }
+
+ if (currentSuggestion != null && s.getOptionKey()
+ .equals(currentSuggestion.getOptionKey())) {
+ // refresh also selected caption and icon in case they have
+ // been updated on the server
+ if (currentSuggestion.getReplacementString()
+ .equals(tb.getText())) {
+ currentSuggestion = s;
+ selectItem(mi);
+ setSelectedCaption(
+ currentSuggestion.getReplacementString());
+ setSelectedItemIcon(currentSuggestion.getIconUri());
+ }
+ }
+
+ isFirstIteration = false;
+ }
+ }
+
+ /**
+ * Create/select a suggestion based on the used entered string. This
+ * method is called after filtering has completed with the given string.
+ *
+ * @param enteredItemValue
+ * user entered string
+ */
+ public void actOnEnteredValueAfterFiltering(String enteredItemValue) {
+ debug("VComboBox.SM: doPostFilterSelectedItemAction()");
+ final MenuItem item = getSelectedItem();
+
+ // check for exact match in menu
+ int p = getItems().size();
+ if (p > 0) {
+ for (int i = 0; i < p; i++) {
+ final MenuItem potentialExactMatch = getItems().get(i);
+ if (potentialExactMatch.getText()
+ .equals(enteredItemValue)) {
+ selectItem(potentialExactMatch);
+ // do not send a value change event if null was and
+ // stays selected
+ if (!"".equals(enteredItemValue)
+ || (selectedOptionKey != null
+ && !"".equals(selectedOptionKey))) {
+ doItemAction(potentialExactMatch, true);
+ }
+ suggestionPopup.hide();
+ return;
+ }
+ }
+ }
+ if ("".equals(enteredItemValue) && nullSelectionAllowed) {
+ onNullSelected();
+ } else if (allowNewItems) {
+ if (!enteredItemValue.equals(lastNewItemString)) {
+ // Store last sent new item string to avoid double sends
+ lastNewItemString = enteredItemValue;
+ connector.sendNewItem(enteredItemValue);
+ // TODO try to select the new value if it matches what was
+ // sent for V7 compatibility
+ }
+ } else if (item != null && !"".equals(lastFilter) && (item.getText()
+ .toLowerCase().contains(lastFilter.toLowerCase()))) {
+ doItemAction(item, true);
+ } else {
+ // currentSuggestion has key="" for nullselection
+ if (currentSuggestion != null
+ && !currentSuggestion.key.equals("")) {
+ // An item (not null) selected
+ String text = currentSuggestion.getReplacementString();
+ setText(text);
+ selectedOptionKey = currentSuggestion.key;
+ } else {
+ onNullSelected();
+ }
+ }
+ suggestionPopup.hide();
+ }
+
+ private static final String SUBPART_PREFIX = "item";
+
+ @Override
+ public com.google.gwt.user.client.Element getSubPartElement(
+ String subPart) {
+ int index = Integer
+ .parseInt(subPart.substring(SUBPART_PREFIX.length()));
+
+ MenuItem item = getItems().get(index);
+
+ return item.getElement();
+ }
+
+ @Override
+ public String getSubPartName(
+ com.google.gwt.user.client.Element subElement) {
+ if (!getElement().isOrHasChild(subElement)) {
+ return null;
+ }
+
+ Element menuItemRoot = subElement;
+ while (menuItemRoot != null
+ && !menuItemRoot.getTagName().equalsIgnoreCase("td")) {
+ menuItemRoot = menuItemRoot.getParentElement().cast();
+ }
+ // "menuItemRoot" is now the root of the menu item
+
+ final int itemCount = getItems().size();
+ for (int i = 0; i < itemCount; i++) {
+ if (getItems().get(i).getElement() == menuItemRoot) {
+ String name = SUBPART_PREFIX + i;
+ return name;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void onLoad(LoadEvent event) {
+ debug("VComboBox.SM: onLoad()");
+ // Handle icon onload events to ensure shadow is resized
+ // correctly
+ delayedImageLoadExecutioner.trigger();
+
+ }
+
+ /**
+ * @deprecated use {@link SuggestionPopup#selectFirstItem()} instead.
+ */
+ @Deprecated
+ public void selectFirstItem() {
+ debug("VComboBox.SM: selectFirstItem()");
+ MenuItem firstItem = getItems().get(0);
+ selectItem(firstItem);
+ }
+
+ /**
+ * @deprecated use {@link SuggestionPopup#selectLastItem()} instead.
+ */
+ @Deprecated
+ public void selectLastItem() {
+ debug("VComboBox.SM: selectLastItem()");
+ List<MenuItem> items = getItems();
+ MenuItem lastItem = items.get(items.size() - 1);
+ selectItem(lastItem);
+ }
+
+ /*
+ * Gets the height of one menu item.
+ */
+ int getItemOffsetHeight() {
+ List<MenuItem> items = getItems();
+ return items != null && items.size() > 0
+ ? items.get(0).getOffsetHeight() : 0;
+ }
+
+ /*
+ * Gets the width of one menu item.
+ */
+ int getItemOffsetWidth() {
+ List<MenuItem> items = getItems();
+ return items != null && items.size() > 0
+ ? items.get(0).getOffsetWidth() : 0;
+ }
+
+ /**
+ * Returns true if the scroll is active on the menu element or if the
+ * menu currently displays the last page with less items then the
+ * maximum visibility (in which case the scroll is not active, but the
+ * scroll is active for any other page in general).
+ *
+ * @since 7.2.6
+ */
+ @Override
+ public boolean isScrollActive() {
+ String height = getElement().getStyle().getHeight();
+ String preferredHeight = getPreferredHeight(pageLength);
+
+ return !(height == null || height.length() == 0
+ || height.equals(preferredHeight));
+ }
+
+ /**
+ * Highlight (select) an item matching the current text box content
+ * without triggering its action.
+ */
+ public void highlightSelectedItem() {
+ int p = getItems().size();
+ // first check if there is a key match to handle items with
+ // identical captions
+ String currentKey = currentSuggestion != null
+ ? currentSuggestion.getOptionKey() : "";
+ for (int i = 0; i < p; i++) {
+ final MenuItem potentialExactMatch = getItems().get(i);
+ if (currentKey.equals(getSuggestionKey(potentialExactMatch))
+ && tb.getText().equals(potentialExactMatch.getText())) {
+ selectItem(potentialExactMatch);
+ tb.setSelectionRange(tb.getText().length(), 0);
+ return;
+ }
+ }
+ // then check for exact string match in menu
+ String text = tb.getText();
+ for (int i = 0; i < p; i++) {
+ final MenuItem potentialExactMatch = getItems().get(i);
+ if (potentialExactMatch.getText().equals(text)) {
+ selectItem(potentialExactMatch);
+ tb.setSelectionRange(tb.getText().length(), 0);
+ return;
+ }
+ }
+ }
+ }
+
+ private String getSuggestionKey(MenuItem item) {
+ if (item != null && item.getCommand() != null) {
+ return ((ComboBoxSuggestion) item.getCommand()).getOptionKey();
+ }
+ return "";
+ }
+
+ /**
+ * TextBox variant used as input element for filter selects, which prevents
+ * selecting text when disabled.
+ *
+ * @since 7.1.5
+ */
+ public class FilterSelectTextBox extends TextBox {
+
+ /**
+ * Creates a new filter select text box.
+ *
+ * @since 7.6.4
+ */
+ public FilterSelectTextBox() {
+ /*-
+ * Stop the browser from showing its own suggestion popup.
+ *
+ * Using an invalid value instead of "off" as suggested by
+ * https://developer.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion
+ *
+ * Leaving the non-standard Safari options autocapitalize and
+ * autocorrect untouched since those do not interfere in the same
+ * way, and they might be useful in a combo box where new items are
+ * allowed.
+ */
+ getElement().setAttribute("autocomplete", "nope");
+ }
+
+ /**
+ * Overridden to avoid selecting text when text input is disabled
+ */
+ @Override
+ public void setSelectionRange(int pos, int length) {
+ if (textInputEnabled) {
+ /*
+ * set selection range with a backwards direction: anchor at the
+ * back, focus at the front. This means that items that are too
+ * long to display will display from the start and not the end
+ * even on Firefox.
+ *
+ * We need the JSNI function to set selection range so that we
+ * can use the optional direction attribute to set the anchor to
+ * the end and the focus to the start. This makes Firefox work
+ * the same way as other browsers (#13477)
+ */
+ WidgetUtil.setSelectionRange(getElement(), pos, length,
+ "backward");
+
+ } else {
+ /*
+ * Setting the selectionrange for an uneditable textbox leads to
+ * unwanted behaviour when the width of the textbox is narrower
+ * than the width of the entry: the end of the entry is shown
+ * instead of the beginning. (see #13477)
+ *
+ * To avoid this, we set the caret to the beginning of the line.
+ */
+
+ super.setSelectionRange(0, 0);
+ }
+ }
+
+ }
+
+ /**
+ * Handler receiving notifications from the connector and updating the
+ * widget state accordingly.
+ *
+ * This class is still subject to change and should not be considered as
+ * public stable API.
+ *
+ * @since
+ */
+ public class DataReceivedHandler {
+
+ private Runnable navigationCallback = null;
+ /**
+ * Set true when popupopened has been clicked. Cleared on each
+ * UIDL-update. This handles the special case where are not filtering
+ * yet and the selected value has changed on the server-side. See #2119
+ * <p>
+ * For internal use only. May be removed or replaced in the future.
+ */
+ private boolean popupOpenerClicked = false;
+ /** For internal use only. May be removed or replaced in the future. */
+ private boolean waitingForFilteringResponse = false;
+ private boolean initialData = true;
+ private String pendingUserInput = null;
+ private boolean showPopup = false;
+
+ /**
+ * Called by the connector when new data for the last requested filter
+ * is received from the server.
+ */
+ public void dataReceived() {
+ if (initialData) {
+ suggestionPopup.menu.setSuggestions(currentSuggestions);
+ performSelection(serverSelectedKey, true, true);
+ updateSuggestionPopupMinWidth();
+ updateRootWidth();
+ initialData = false;
+ return;
+ }
+
+ suggestionPopup.menu.setSuggestions(currentSuggestions);
+ if (!waitingForFilteringResponse && suggestionPopup.isAttached()) {
+ showPopup = true;
+ }
+ if (showPopup) {
+ suggestionPopup.showSuggestions(currentPage, totalMatches);
+ }
+
+ waitingForFilteringResponse = false;
+
+ if (pendingUserInput != null) {
+ suggestionPopup.menu
+ .actOnEnteredValueAfterFiltering(pendingUserInput);
+ pendingUserInput = null;
+ } else if (popupOpenerClicked) {
+ // make sure the current item is selected in the popup
+ suggestionPopup.menu.highlightSelectedItem();
+ } else {
+ navigateItemAfterPageChange();
+ }
+
+ if (!showPopup) {
+ suggestionPopup.hide();
+ }
+
+ popupOpenerClicked = false;
+ showPopup = false;
+ }
+
+ /**
+ * Perform filtering with the user entered string and when the results
+ * are received, perform any action appropriate for the user input
+ * (select an item or create a new one).
+ *
+ * @param value
+ * user input
+ */
+ public void reactOnInputWhenReady(String value) {
+ pendingUserInput = value;
+ showPopup = false;
+ filterOptions(0, value);
+ }
+
+ /*
+ * This method navigates to the proper item in the combobox page. This
+ * should be executed after setSuggestions() method which is called from
+ * VComboBox.showSuggestions(). ShowSuggestions() method builds the page
+ * content. As far as setSuggestions() method is called as deferred,
+ * navigateItemAfterPageChange method should be also be called as
+ * deferred. #11333
+ */
+ private void navigateItemAfterPageChange() {
+ if (navigationCallback != null) {
+ // navigationCallback is not reset here but after any server
+ // request in case you are in between two requests both changing
+ // the page back and forth
+
+ // we're paging w/ arrows
+ navigationCallback.run();
+ navigationCallback = null;
+ }
+ }
+
+ /**
+ * Called by the connector any pending navigation operations should be
+ * cleared.
+ */
+ public void clearPendingNavigation() {
+ navigationCallback = null;
+ }
+
+ /**
+ * Set a callback that is invoked when a page change occurs if there
+ * have not been intervening requests to the server. The callback is
+ * reset when any additional request is made to the server.
+ *
+ * @param callback
+ * method to call after filtering has completed
+ */
+ public void setNavigationCallback(Runnable callback) {
+ showPopup = true;
+ navigationCallback = callback;
+ }
+
+ /**
+ * Record that the popup opener has been clicked and the popup should be
+ * opened on the next request.
+ *
+ * This handles the special case where are not filtering yet and the
+ * selected value has changed on the server-side. See #2119. The flag is
+ * cleared on each server reply.
+ */
+ public void popupOpenerClicked() {
+ popupOpenerClicked = true;
+ showPopup = true;
+ }
+
+ /**
+ * Cancel a pending request to perform post-filtering actions.
+ */
+ private void cancelPendingPostFiltering() {
+ pendingUserInput = null;
+ }
+
+ /**
+ * Called by the connector when it has finished handling any reply from
+ * the server, regardless of what was updated.
+ */
+ public void serverReplyHandled() {
+ popupOpenerClicked = false;
+ lastNewItemString = null;
+
+ // if (!initDone) {
+ // debug("VComboBox: init done, updating widths");
+ // // Calculate minimum textarea width
+ // updateSuggestionPopupMinWidth();
+ // updateRootWidth();
+ // initDone = true;
+ // }
+ }
+
+ /**
+ * For internal use only - this method will be removed in the future.
+ *
+ * @return true if the combo box is waiting for a reply from the server
+ * with a new page of data, false otherwise
+ */
+ public boolean isWaitingForFilteringResponse() {
+ return waitingForFilteringResponse;
+ }
+
+ /**
+ * For internal use only - this method will be removed in the future.
+ *
+ * @return true if the combo box is waiting for initial data from the
+ * server, false otherwise
+ */
+ public boolean isWaitingForInitialData() {
+ return initialData;
+ }
+
+ /**
+ * Set a flag that filtering of options is pending a response from the
+ * server.
+ */
+ private void startWaitingForFilteringResponse() {
+ waitingForFilteringResponse = true;
+ }
+
+ /**
+ * Perform selection (if appropriate) based on a reply from the server.
+ * When this method is called, the suggestions have been reset if new
+ * ones (different from the previous list) were received from the
+ * server.
+ *
+ * @param selectedKey
+ * new selected key or null if none given by the server
+ * @param selectedCaption
+ * new selected item caption if sent by the server or null -
+ * this is used when the selected item is not on the current
+ * page
+ */
+ public void updateSelectionFromServer(String selectedKey,
+ String selectedCaption) {
+ boolean oldSuggestionTextMatchTheOldSelection = currentSuggestion != null
+ && currentSuggestion.getReplacementString()
+ .equals(tb.getText());
+
+ serverSelectedKey = selectedKey;
+
+ performSelection(selectedKey, oldSuggestionTextMatchTheOldSelection,
+ !isWaitingForFilteringResponse() || popupOpenerClicked);
+
+ cancelPendingPostFiltering();
+
+ setSelectedCaption(selectedCaption);
+ if (currentSuggestion != null && serverSelectedKey
+ .equals(currentSuggestion.getOptionKey())) {
+ setSelectedItemIcon(currentSuggestion.getIconUri());
+ }
+ }
+
+ }
+
+ // TODO decide whether this should change - affects themes and v7
+ public static final String CLASSNAME = "v-filterselect";
+ private static final String STYLE_NO_INPUT = "no-input";
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public int pageLength = 10;
+
+ private boolean enableDebug = false;
+
+ private final FlowPanel panel = new FlowPanel();
+
+ /**
+ * The text box where the filter is written
+ * <p>
+ * For internal use only. May be removed or replaced in the future.
+ */
+ public final TextBox tb;
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public final SuggestionPopup suggestionPopup;
+
+ /**
+ * Used when measuring the width of the popup
+ */
+ private final HTML popupOpener = new HTML("");
+
+ private class IconWidget extends Widget {
+ IconWidget(Icon icon) {
+ setElement(icon.getElement());
+ }
+ }
+
+ private IconWidget selectedItemIcon;
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public ComboBoxConnector connector;
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public int currentPage;
+
+ /**
+ * A collection of available suggestions (options) as received from the
+ * server.
+ * <p>
+ * For internal use only. May be removed or replaced in the future.
+ */
+ public final List<ComboBoxSuggestion> currentSuggestions = new ArrayList<ComboBoxSuggestion>();
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public String serverSelectedKey;
+ /** For internal use only. May be removed or replaced in the future. */
+ public String selectedOptionKey;
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public boolean initDone = false;
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public String lastFilter = "";
+
+ /**
+ * The current suggestion selected from the dropdown. This is one of the
+ * values in currentSuggestions except when filtering, in this case
+ * currentSuggestion might not be in currentSuggestions.
+ * <p>
+ * For internal use only. May be removed or replaced in the future.
+ */
+ public ComboBoxSuggestion currentSuggestion;
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public boolean allowNewItems;
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public int totalMatches;
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public boolean nullSelectionAllowed;
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public boolean nullSelectItem;
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public boolean enabled;
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public boolean readonly;
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public String inputPrompt = "";
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public int suggestionPopupMinWidth = 0;
+
+ public String suggestionPopupWidth = null;
+
+ private int popupWidth = -1;
+ /**
+ * Stores the last new item string to avoid double submissions. Cleared on
+ * uidl updates.
+ * <p>
+ * For internal use only. May be removed or replaced in the future.
+ */
+ public String lastNewItemString;
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public boolean focused = false;
+
+ /**
+ * If set to false, the component should not allow entering text to the
+ * field even for filtering.
+ */
+ private boolean textInputEnabled = true;
+
+ private final DataReceivedHandler dataReceivedHandler = new DataReceivedHandler();
+
+ /**
+ * Default constructor.
+ */
+ public VComboBox() {
+ tb = createTextBox();
+ suggestionPopup = createSuggestionPopup();
+
+ popupOpener.addMouseDownHandler(VComboBox.this);
+ Roles.getButtonRole().setAriaHiddenState(popupOpener.getElement(),
+ true);
+ Roles.getButtonRole().set(popupOpener.getElement());
+
+ panel.add(tb);
+ panel.add(popupOpener);
+ initWidget(panel);
+ Roles.getComboboxRole().set(panel.getElement());
+
+ tb.addKeyDownHandler(this);
+ tb.addKeyUpHandler(this);
+
+ tb.addFocusHandler(this);
+ tb.addBlurHandler(this);
+
+ panel.addDomHandler(this, ClickEvent.getType());
+
+ setStyleName(CLASSNAME);
+
+ sinkEvents(Event.ONPASTE);
+ }
+
+ private static double getMarginBorderPaddingWidth(Element element) {
+ final ComputedStyle s = new ComputedStyle(element);
+ return s.getMarginWidth() + s.getBorderWidth() + s.getPaddingWidth();
+
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.user.client.ui.Composite#onBrowserEvent(com.google.gwt
+ * .user.client.Event)
+ */
+ @Override
+ public void onBrowserEvent(Event event) {
+ super.onBrowserEvent(event);
+
+ if (event.getTypeInt() == Event.ONPASTE) {
+ if (textInputEnabled) {
+ filterOptions(currentPage);
+ }
+ }
+ }
+
+ /**
+ * This method will create the TextBox used by the VComboBox instance. It is
+ * invoked during the Constructor and should only be overridden if a custom
+ * TextBox shall be used. The overriding method cannot use any instance
+ * variables.
+ *
+ * @since 7.1.5
+ * @return TextBox instance used by this VComboBox
+ */
+ protected TextBox createTextBox() {
+ return new FilterSelectTextBox();
+ }
+
+ /**
+ * This method will create the SuggestionPopup used by the VComboBox
+ * instance. It is invoked during the Constructor and should only be
+ * overridden if a custom SuggestionPopup shall be used. The overriding
+ * method cannot use any instance variables.
+ *
+ * @since 7.1.5
+ * @return SuggestionPopup instance used by this VComboBox
+ */
+ protected SuggestionPopup createSuggestionPopup() {
+ return new SuggestionPopup();
+ }
+
+ @Override
+ public void setStyleName(String style) {
+ super.setStyleName(style);
+ updateStyleNames();
+ }
+
+ @Override
+ public void setStylePrimaryName(String style) {
+ super.setStylePrimaryName(style);
+ updateStyleNames();
+ }
+
+ protected void updateStyleNames() {
+ tb.setStyleName(getStylePrimaryName() + "-input");
+ popupOpener.setStyleName(getStylePrimaryName() + "-button");
+ suggestionPopup.setStyleName(getStylePrimaryName() + "-suggestpopup");
+ }
+
+ /**
+ * Does the Select have more pages?
+ *
+ * @return true if a next page exists, else false if the current page is the
+ * last page
+ */
+ public boolean hasNextPage() {
+ return (pageLength > 0
+ && totalMatches > (currentPage + 1) * pageLength);
+ }
+
+ /**
+ * Filters the options at a certain page. Uses the text box input as a
+ * filter and ensures the popup is opened when filtering results are
+ * available.
+ *
+ * @param page
+ * The page which items are to be filtered
+ */
+ public void filterOptions(int page) {
+ dataReceivedHandler.popupOpenerClicked();
+ filterOptions(page, tb.getText());
+ }
+
+ /**
+ * Filters the options at certain page using the given filter.
+ *
+ * @param page
+ * The page to filter
+ * @param filter
+ * The filter to apply to the components
+ */
+ public void filterOptions(int page, String filter) {
+ debug("VComboBox: filterOptions(" + page + ", " + filter + ")");
+
+ if (filter.equals(lastFilter) && currentPage == page) {
+ if (!suggestionPopup.isAttached()) {
+ dataReceivedHandler.startWaitingForFilteringResponse();
+ connector.requestPage(currentPage);
+ } else {
+ // already have the page
+ dataReceivedHandler.dataReceived();
+ }
+ return;
+ }
+ if (!filter.equals(lastFilter)) {
+ // when filtering, let the server decide the page unless we've
+ // set the filter to empty and explicitly said that we want to see
+ // the results starting from page 0.
+ if ("".equals(filter) && page != 0) {
+ // let server decide
+ page = -1;
+ } else {
+ page = 0;
+ }
+ }
+
+ dataReceivedHandler.startWaitingForFilteringResponse();
+ connector.setFilter(filter);
+ connector.requestPage(currentPage);
+
+ lastFilter = filter;
+ currentPage = page;
+ }
+
+ /** For internal use only. May be removed or replaced in the future. */
+ public void updateReadOnly() {
+ debug("VComboBox: updateReadOnly()");
+ tb.setReadOnly(readonly || !textInputEnabled);
+ }
+
+ public void setTextInputAllowed(boolean textInputAllowed) {
+ debug("VComboBox: setTextInputAllowed()");
+ // Always update styles as they might have been overwritten
+ if (textInputAllowed) {
+ removeStyleDependentName(STYLE_NO_INPUT);
+ Roles.getTextboxRole().removeAriaReadonlyProperty(tb.getElement());
+ } else {
+ addStyleDependentName(STYLE_NO_INPUT);
+ Roles.getTextboxRole().setAriaReadonlyProperty(tb.getElement(),
+ true);
+ }
+
+ if (textInputEnabled == textInputAllowed) {
+ return;
+ }
+
+ textInputEnabled = textInputAllowed;
+ updateReadOnly();
+ }
+
+ /**
+ * Sets the text in the text box.
+ *
+ * @param text
+ * the text to set in the text box
+ */
+ public void setText(final String text) {
+ /**
+ * To leave caret in the beginning of the line. SetSelectionRange
+ * wouldn't work on IE (see #13477)
+ */
+ Direction previousDirection = tb.getDirection();
+ tb.setDirection(Direction.RTL);
+ tb.setText(text);
+ tb.setDirection(previousDirection);
+ }
+
+ /**
+ * Set or reset the placeholder attribute for the text field.
+ *
+ * @param placeholder
+ * new placeholder string or null for none
+ */
+ public void setPlaceholder(String placeholder) {
+ inputPrompt = placeholder;
+ updatePlaceholder();
+ }
+
+ /**
+ * Update placeholder visibility (hidden when read-only or disabled).
+ */
+ public void updatePlaceholder() {
+ if (inputPrompt != null && enabled && !readonly) {
+ tb.getElement().setAttribute("placeholder", inputPrompt);
+ } else {
+ tb.getElement().removeAttribute("placeholder");
+ }
+ }
+
+ /**
+ * Triggered when a suggestion is selected.
+ *
+ * @param suggestion
+ * The suggestion that just got selected.
+ */
+ public void onSuggestionSelected(ComboBoxSuggestion suggestion) {
+ if (enableDebug) {
+ debug("VComboBox: onSuggestionSelected(" + suggestion.caption + ": "
+ + suggestion.key + ")");
+ }
+ // special handling of null selection
+ if (suggestion.key.equals("")) {
+ onNullSelected();
+ return;
+ }
+
+ dataReceivedHandler.cancelPendingPostFiltering();
+
+ currentSuggestion = suggestion;
+ String newKey = suggestion.getOptionKey();
+
+ String text = suggestion.getReplacementString();
+ setText(text);
+ setSelectedItemIcon(suggestion.getIconUri());
+
+ if (!(newKey.equals(selectedOptionKey))) {
+ selectedOptionKey = newKey;
+ connector.sendSelection(selectedOptionKey);
+ setSelectedCaption(text);
+
+ // currentPage = -1; // forget the page
+ }
+
+ suggestionPopup.hide();
+ }
+
+ /**
+ * Triggered when an empty value is selected and null selection is allowed.
+ */
+ public void onNullSelected() {
+ if (enableDebug) {
+ debug("VComboBox: onNullSelected()");
+ }
+ // TODO do we need this feature?
+ if (nullSelectItem) {
+ reset();
+ return;
+ }
+ dataReceivedHandler.cancelPendingPostFiltering();
+
+ currentSuggestion = null;
+ setText("");
+ setSelectedItemIcon(null);
+
+ if (!"".equals(selectedOptionKey) || (selectedOptionKey != null)) {
+ selectedOptionKey = "";
+ setSelectedCaption("");
+ connector.sendSelection(null);
+ // currentPage = 0;
+ }
+
+ suggestionPopup.hide();
+ }
+
+ /**
+ * Sets the icon URI of the selected item. The icon is shown on the left
+ * side of the item caption text. Set the URI to null to remove the icon.
+ *
+ * @param iconUri
+ * The URI of the icon
+ */
+ public void setSelectedItemIcon(String iconUri) {
+
+ if (selectedItemIcon != null) {
+ panel.remove(selectedItemIcon);
+ }
+ if (iconUri == null || iconUri.length() == 0) {
+ if (selectedItemIcon != null) {
+ selectedItemIcon = null;
+ afterSelectedItemIconChange();
+ }
+ } else {
+ selectedItemIcon = new IconWidget(
+ connector.getConnection().getIcon(iconUri));
+ selectedItemIcon.addDomHandler(VComboBox.this,
+ ClickEvent.getType());
+ selectedItemIcon.addDomHandler(VComboBox.this,
+ MouseDownEvent.getType());
+ iconUpdating = true;
+ selectedItemIcon.addDomHandler(new LoadHandler() {
+ @Override
+ public void onLoad(LoadEvent event) {
+ afterSelectedItemIconChange();
+ iconUpdating = false;
+ }
+ }, LoadEvent.getType());
+ panel.insert(selectedItemIcon, 0);
+ afterSelectedItemIconChange();
+ }
+ }
+
+ private void afterSelectedItemIconChange() {
+ if (BrowserInfo.get().isWebkit()) {
+ // Some browsers need a nudge to reposition the text field
+ forceReflow();
+ }
+ updateRootWidth();
+ if (selectedItemIcon != null) {
+ updateSelectedIconPosition();
+ }
+ }
+
+ /**
+ * Perform selection based on a message from the server.
+ *
+ * The special case where the selected item is not on the current page is
+ * handled separately by the caller.
+ *
+ * @param selectedKey
+ * non-empty selected item key
+ * @param forceUpdateText
+ * true to force the text box value to match the suggestion text
+ * @param updatePromptAndSelectionIfMatchFound
+ */
+ private void performSelection(String selectedKey, boolean forceUpdateText,
+ boolean updatePromptAndSelectionIfMatchFound) {
+ if (selectedKey == null || "".equals(selectedKey)) {
+ currentSuggestion = null; // #13217
+ setSelectedItemIcon(null);
+ selectedOptionKey = null;
+ setText("");
+ }
+ // some item selected
+ for (ComboBoxSuggestion suggestion : currentSuggestions) {
+ String suggestionKey = suggestion.getOptionKey();
+ if (!suggestionKey.equals(selectedKey)) {
+ continue;
+ }
+ // at this point, suggestion key matches the new selection key
+ if (updatePromptAndSelectionIfMatchFound) {
+ if (!suggestionKey.equals(selectedOptionKey) || suggestion
+ .getReplacementString().equals(tb.getText())
+ || forceUpdateText) {
+ // Update text field if we've got a new
+ // selection
+ // Also update if we've got the same text to
+ // retain old text selection behavior
+ // OR if selected item caption is changed.
+ setText(suggestion.getReplacementString());
+ selectedOptionKey = suggestionKey;
+ }
+ }
+ currentSuggestion = suggestion;
+ setSelectedItemIcon(suggestion.getIconUri());
+ // only a single item can be selected
+ break;
+ }
+ }
+
+ private void forceReflow() {
+ WidgetUtil.setStyleTemporarily(tb.getElement(), "zoom", "1");
+ }
+
+ /**
+ * Positions the icon vertically in the middle. Should be called after the
+ * icon has loaded
+ */
+ private void updateSelectedIconPosition() {
+ // Position icon vertically to middle
+ int availableHeight = 0;
+ availableHeight = getOffsetHeight();
+
+ int iconHeight = WidgetUtil.getRequiredHeight(selectedItemIcon);
+ int marginTop = (availableHeight - iconHeight) / 2;
+ selectedItemIcon.getElement().getStyle().setMarginTop(marginTop,
+ Unit.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)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.KeyDownHandler#onKeyDown(com.google.gwt
+ * .event.dom.client.KeyDownEvent)
+ */
+
+ @Override
+ public void onKeyDown(KeyDownEvent event) {
+ if (enabled && !readonly) {
+ int keyCode = event.getNativeKeyCode();
+
+ if (enableDebug) {
+ debug("VComboBox: key down: " + keyCode);
+ }
+ if (dataReceivedHandler.isWaitingForFilteringResponse()
+ && navigationKeyCodes.contains(keyCode)
+ && (!allowNewItems || keyCode != KeyCodes.KEY_ENTER)) {
+ /*
+ * Keyboard navigation events should not be handled while we are
+ * waiting for a response. This avoids flickering, disappearing
+ * items, wrongly interpreted responses and more.
+ */
+ if (enableDebug) {
+ debug("Ignoring " + keyCode
+ + " because we are waiting for a filtering response");
+ }
+ DOM.eventPreventDefault(DOM.eventGetCurrentEvent());
+ event.stopPropagation();
+ return;
+ }
+
+ if (suggestionPopup.isAttached()) {
+ if (enableDebug) {
+ debug("Keycode " + keyCode + " target is popup");
+ }
+ popupKeyDown(event);
+ } else {
+ if (enableDebug) {
+ 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
+ *
+ * @param event
+ * The KeyDownEvent
+ */
+ private void inputFieldKeyDown(KeyDownEvent event) {
+ if (enableDebug) {
+ debug("VComboBox: inputFieldKeyDown(" + event.getNativeKeyCode()
+ + ")");
+ }
+ switch (event.getNativeKeyCode()) {
+ case KeyCodes.KEY_DOWN:
+ case KeyCodes.KEY_UP:
+ case KeyCodes.KEY_PAGEDOWN:
+ case KeyCodes.KEY_PAGEUP:
+ // open popup as from gadget
+ filterOptions(-1, "");
+ tb.selectAll();
+ dataReceivedHandler.popupOpenerClicked();
+ break;
+ 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 (!allowNewItems) {
+ 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;
+ }
+ dataReceivedHandler.reactOnInputWhenReady(tb.getText());
+ suggestionPopup.hide();
+
+ event.stopPropagation();
+ break;
+ }
+
+ }
+
+ /**
+ * Triggered when a key was pressed in the suggestion popup.
+ *
+ * @param event
+ * The KeyDownEvent of the key
+ */
+ private void popupKeyDown(KeyDownEvent event) {
+ if (enableDebug) {
+ debug("VComboBox: popupKeyDown(" + event.getNativeKeyCode() + ")");
+ }
+ // Propagation of handled events is stopped so other handlers such as
+ // shortcut key handlers do not also handle the same events.
+ switch (event.getNativeKeyCode()) {
+ case KeyCodes.KEY_DOWN:
+ suggestionPopup.selectNextItem();
+
+ DOM.eventPreventDefault(DOM.eventGetCurrentEvent());
+ event.stopPropagation();
+ break;
+ case KeyCodes.KEY_UP:
+ suggestionPopup.selectPrevItem();
+
+ DOM.eventPreventDefault(DOM.eventGetCurrentEvent());
+ event.stopPropagation();
+ break;
+ case KeyCodes.KEY_PAGEDOWN:
+ selectNextPage();
+ event.stopPropagation();
+ break;
+ case KeyCodes.KEY_PAGEUP:
+ selectPrevPage();
+ event.stopPropagation();
+ break;
+ case KeyCodes.KEY_ESCAPE:
+ reset();
+ DOM.eventPreventDefault(DOM.eventGetCurrentEvent());
+ event.stopPropagation();
+ break;
+ case KeyCodes.KEY_TAB:
+ case KeyCodes.KEY_ENTER:
+
+ // queue this, may be cancelled by selection
+ int selectedIndex = suggestionPopup.menu.getSelectedIndex();
+ if (!allowNewItems && selectedIndex != -1) {
+ onSuggestionSelected(currentSuggestions.get(selectedIndex));
+ } else {
+ dataReceivedHandler.reactOnInputWhenReady(tb.getText());
+ }
+ suggestionPopup.hide();
+
+ event.stopPropagation();
+ break;
+ }
+
+ }
+
+ /*
+ * Show the prev page.
+ */
+ private void selectPrevPage() {
+ if (currentPage > 0) {
+ dataReceivedHandler.setNavigationCallback(
+ () -> suggestionPopup.selectLastItem());
+ filterOptions(currentPage - 1, lastFilter);
+ }
+ }
+
+ /*
+ * Show the next page.
+ */
+ private void selectNextPage() {
+ if (hasNextPage()) {
+ dataReceivedHandler.setNavigationCallback(
+ () -> suggestionPopup.selectFirstItem());
+ filterOptions(currentPage + 1, lastFilter);
+ }
+ }
+
+ /**
+ * Triggered when a key was depressed.
+ *
+ * @param event
+ * The KeyUpEvent of the key depressed
+ */
+ @Override
+ public void onKeyUp(KeyUpEvent event) {
+ if (enableDebug) {
+ debug("VComboBox: onKeyUp(" + event.getNativeKeyCode() + ")");
+ }
+ if (enabled && !readonly) {
+ switch (event.getNativeKeyCode()) {
+ case KeyCodes.KEY_ENTER:
+ case KeyCodes.KEY_TAB:
+ case KeyCodes.KEY_SHIFT:
+ case KeyCodes.KEY_CTRL:
+ case KeyCodes.KEY_ALT:
+ case KeyCodes.KEY_DOWN:
+ case KeyCodes.KEY_UP:
+ case KeyCodes.KEY_PAGEDOWN:
+ case KeyCodes.KEY_PAGEUP:
+ case KeyCodes.KEY_ESCAPE:
+ // NOP
+ break;
+ default:
+ if (textInputEnabled) {
+ // when filtering, we always want to see the results on the
+ // first page first.
+ filterOptions(0);
+ }
+ break;
+ }
+ }
+ }
+
+ /**
+ * Resets the ComboBox to its initial state.
+ */
+ private void reset() {
+ debug("VComboBox: reset()");
+ if (currentSuggestion != null) {
+ String text = currentSuggestion.getReplacementString();
+ setText(text);
+ setSelectedItemIcon(currentSuggestion.getIconUri());
+
+ selectedOptionKey = currentSuggestion.key;
+
+ } else {
+ setText("");
+ setSelectedItemIcon(null);
+ updatePlaceholder();
+
+ selectedOptionKey = null;
+ }
+
+ lastFilter = "";
+ suggestionPopup.hide();
+ }
+
+ /**
+ * Listener for popupopener.
+ */
+ @Override
+ public void onClick(ClickEvent event) {
+ debug("VComboBox: onClick()");
+ if (textInputEnabled && event.getNativeEvent().getEventTarget()
+ .cast() == tb.getElement()) {
+ // Don't process clicks on the text field if text input is enabled
+ return;
+ }
+ if (enabled && !readonly) {
+ // ask suggestionPopup if it was just closed, we are using GWT
+ // Popup's auto close feature
+ if (!suggestionPopup.isJustClosed()) {
+ filterOptions(-1, "");
+ dataReceivedHandler.popupOpenerClicked();
+ }
+ DOM.eventPreventDefault(DOM.eventGetCurrentEvent());
+ focus();
+ tb.selectAll();
+ }
+ }
+
+ /**
+ * Update minimum width for combo box textarea based on input prompt and
+ * suggestions.
+ * <p>
+ * For internal use only. May be removed or replaced in the future.
+ */
+ public void updateSuggestionPopupMinWidth() {
+ debug("VComboBox: updateSuggestionPopupMinWidth()");
+
+ // used only to calculate minimum width
+ String captions = WidgetUtil.escapeHTML(inputPrompt);
+
+ for (ComboBoxSuggestion suggestion : currentSuggestions) {
+ // Collect captions so we can calculate minimum width for
+ // textarea
+ if (captions.length() > 0) {
+ captions += "|";
+ }
+ captions += WidgetUtil
+ .escapeHTML(suggestion.getReplacementString());
+ }
+
+ // Calculate minimum textarea width
+ suggestionPopupMinWidth = minWidth(captions);
+ }
+
+ /**
+ * Calculate minimum width for FilterSelect textarea.
+ * <p>
+ * For internal use only. May be removed or replaced in the future.
+ *
+ * @param captions
+ * pipe separated string listing all the captions to measure
+ * @return minimum width in pixels
+ */
+ public native int minWidth(String captions)
+ /*-{
+ if(!captions || captions.length <= 0)
+ return 0;
+ captions = captions.split("|");
+ var d = $wnd.document.createElement("div");
+ var html = "";
+ for(var i=0; i < captions.length; i++) {
+ html += "<div>" + captions[i] + "</div>";
+ // TODO apply same CSS classname as in suggestionmenu
+ }
+ d.style.position = "absolute";
+ d.style.top = "0";
+ d.style.left = "0";
+ d.style.visibility = "hidden";
+ d.innerHTML = html;
+ $wnd.document.body.appendChild(d);
+ var w = d.offsetWidth;
+ $wnd.document.body.removeChild(d);
+ return w;
+ }-*/;
+
+ /**
+ * A flag which prevents a focus event from taking place.
+ */
+ boolean iePreventNextFocus = false;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.FocusHandler#onFocus(com.google.gwt.event
+ * .dom.client.FocusEvent)
+ */
+
+ @Override
+ public void onFocus(FocusEvent event) {
+ debug("VComboBox: onFocus()");
+
+ /*
+ * When we disable a blur event in ie we need to refocus the textfield.
+ * This will cause a focus event we do not want to process, so in that
+ * case we just ignore it.
+ */
+ if (BrowserInfo.get().isIE() && iePreventNextFocus) {
+ iePreventNextFocus = false;
+ return;
+ }
+
+ focused = true;
+ updatePlaceholder();
+ addStyleDependentName("focus");
+
+ connector.sendFocusEvent();
+
+ connector.getConnection().getVTooltip()
+ .showAssistive(connector.getTooltipInfo(getElement()));
+ }
+
+ /**
+ * A flag which cancels the blur event and sets the focus back to the
+ * textfield if the Browser is IE.
+ */
+ boolean preventNextBlurEventInIE = false;
+
+ private String explicitSelectedCaption;
+ private boolean iconUpdating = false;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * com.google.gwt.event.dom.client.BlurHandler#onBlur(com.google.gwt.event
+ * .dom.client.BlurEvent)
+ */
+
+ @Override
+ public void onBlur(BlurEvent event) {
+ debug("VComboBox: onBlur()");
+
+ if (BrowserInfo.get().isIE() && preventNextBlurEventInIE) {
+ /*
+ * Clicking in the suggestion popup or on the popup button in IE
+ * causes a blur event to be sent for the field. In other browsers
+ * this is prevented by canceling/preventing default behavior for
+ * the focus event, in IE we handle it here by refocusing the text
+ * field and ignoring the resulting focus event for the textfield
+ * (in onFocus).
+ */
+ preventNextBlurEventInIE = false;
+
+ Element focusedElement = WidgetUtil.getFocusedElement();
+ if (getElement().isOrHasChild(focusedElement) || suggestionPopup
+ .getElement().isOrHasChild(focusedElement)) {
+
+ // IF the suggestion popup or another part of the VComboBox
+ // was focused, move the focus back to the textfield and prevent
+ // the triggered focus event (in onFocus).
+ iePreventNextFocus = true;
+ tb.setFocus(true);
+ return;
+ }
+ }
+
+ focused = false;
+ updatePlaceholder();
+ if (!readonly) {
+ reset();
+ suggestionPopup.hide();
+ }
+ removeStyleDependentName("focus");
+
+ connector.sendBlurEvent();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.vaadin.client.Focusable#focus()
+ */
+
+ @Override
+ public void focus() {
+ debug("VComboBox: focus()");
+ focused = true;
+ updatePlaceholder();
+ tb.setFocus(true);
+ }
+
+ /**
+ * Calculates the width of the select if the select has undefined width.
+ * Should be called when the width changes or when the icon changes.
+ * <p>
+ * For internal use only. May be removed or replaced in the future.
+ */
+ public void updateRootWidth() {
+ debug("VComboBox: updateRootWidth()");
+
+ if (connector.isUndefinedWidth()) {
+
+ /*
+ * When the select has a undefined with we need to check that we are
+ * only setting the text box width relative to the first page width
+ * of the items. If this is not done the text box width will change
+ * when the popup is used to view longer items than the text box is
+ * wide.
+ */
+ int w = WidgetUtil.getRequiredWidth(this);
+
+ if (dataReceivedHandler.isWaitingForInitialData()
+ && suggestionPopupMinWidth > w) {
+ /*
+ * We want to compensate for the paddings just to preserve the
+ * exact size as in Vaadin 6.x, but we get here before
+ * MeasuredSize has been initialized.
+ * Util.measureHorizontalPaddingAndBorder does not work with
+ * border-box, so we must do this the hard way.
+ */
+ Style style = getElement().getStyle();
+ String originalPadding = style.getPadding();
+ String originalBorder = style.getBorderWidth();
+ style.setPaddingLeft(0, Unit.PX);
+ style.setBorderWidth(0, Unit.PX);
+ style.setProperty("padding", originalPadding);
+ style.setProperty("borderWidth", originalBorder);
+
+ // Use util.getRequiredWidth instead of getOffsetWidth here
+
+ int iconWidth = selectedItemIcon == null ? 0
+ : WidgetUtil.getRequiredWidth(selectedItemIcon);
+ int buttonWidth = popupOpener == null ? 0
+ : WidgetUtil.getRequiredWidth(popupOpener);
+
+ /*
+ * Instead of setting the width of the wrapper, set the width of
+ * the combobox. Subtract the width of the icon and the
+ * popupopener
+ */
+
+ tb.setWidth((suggestionPopupMinWidth - iconWidth - buttonWidth)
+ + "px");
+ }
+
+ /*
+ * Lock the textbox width to its current value if it's not already
+ * locked. This can happen after setWidth("") which resets the
+ * textbox width to "100%".
+ */
+ if (!tb.getElement().getStyle().getWidth().endsWith("px")) {
+ int iconWidth = selectedItemIcon == null ? 0
+ : selectedItemIcon.getOffsetWidth();
+ tb.setWidth((tb.getOffsetWidth() - iconWidth) + "px");
+ }
+ }
+ }
+
+ /**
+ * Get the width of the select in pixels where the text area and icon has
+ * been included.
+ *
+ * @return The width in pixels
+ */
+ private int getMainWidth() {
+ return getOffsetWidth();
+ }
+
+ @Override
+ public void setWidth(String width) {
+ super.setWidth(width);
+ if (width.length() != 0) {
+ tb.setWidth("100%");
+ }
+ }
+
+ /**
+ * Handles special behavior of the mouse down event.
+ *
+ * @param event
+ */
+ private void handleMouseDownEvent(Event event) {
+ /*
+ * Prevent the keyboard focus from leaving the textfield by preventing
+ * the default behaviour of the browser. Fixes #4285.
+ */
+ if (event.getTypeInt() == Event.ONMOUSEDOWN) {
+ debug("VComboBox: blocking mouseDown event to avoid blur");
+
+ event.preventDefault();
+ event.stopPropagation();
+
+ /*
+ * In IE the above wont work, the blur event will still trigger. So,
+ * we set a flag here to prevent the next blur event from happening.
+ * This is not needed if do not already have focus, in that case
+ * there will not be any blur event and we should not cancel the
+ * next blur.
+ */
+ if (BrowserInfo.get().isIE() && focused) {
+ preventNextBlurEventInIE = true;
+ debug("VComboBox: Going to prevent next blur event on IE");
+ }
+ }
+ }
+
+ @Override
+ public void onMouseDown(MouseDownEvent event) {
+ debug("VComboBox.onMouseDown(): blocking mouseDown event to avoid blur");
+
+ event.preventDefault();
+ event.stopPropagation();
+
+ /*
+ * In IE the above wont work, the blur event will still trigger. So, we
+ * set a flag here to prevent the next blur event from happening. This
+ * is not needed if do not already have focus, in that case there will
+ * not be any blur event and we should not cancel the next blur.
+ */
+ if (BrowserInfo.get().isIE() && focused) {
+ preventNextBlurEventInIE = true;
+ debug("VComboBox: Going to prevent next blur event on IE");
+ }
+ }
+
+ @Override
+ protected void onDetach() {
+ super.onDetach();
+ suggestionPopup.hide();
+ }
+
+ @Override
+ public com.google.gwt.user.client.Element getSubPartElement(
+ String subPart) {
+ String[] parts = subPart.split("/");
+ if ("textbox".equals(parts[0])) {
+ return tb.getElement();
+ } else if ("button".equals(parts[0])) {
+ return popupOpener.getElement();
+ } else if ("popup".equals(parts[0]) && suggestionPopup.isAttached()) {
+ if (parts.length == 2) {
+ return suggestionPopup.menu.getSubPartElement(parts[1]);
+ }
+ return suggestionPopup.getElement();
+ }
+ return null;
+ }
+
+ @Override
+ public String getSubPartName(
+ com.google.gwt.user.client.Element subElement) {
+ if (tb.getElement().isOrHasChild(subElement)) {
+ return "textbox";
+ } else if (popupOpener.getElement().isOrHasChild(subElement)) {
+ return "button";
+ } else if (suggestionPopup.getElement().isOrHasChild(subElement)) {
+ return "popup";
+ }
+ return null;
+ }
+
+ @Override
+ public void setAriaRequired(boolean required) {
+ AriaHelper.handleInputRequired(tb, required);
+ }
+
+ @Override
+ public void setAriaInvalid(boolean invalid) {
+ AriaHelper.handleInputInvalid(tb, invalid);
+ }
+
+ @Override
+ public void bindAriaCaption(
+ com.google.gwt.user.client.Element captionElement) {
+ AriaHelper.bindCaption(tb, captionElement);
+ }
+
+ @Override
+ public boolean isWorkPending() {
+ return dataReceivedHandler.isWaitingForFilteringResponse()
+ || suggestionPopup.lazyPageScroller.isRunning() || iconUpdating;
+ }
+
+ /**
+ * Sets the caption of selected item, if "scroll to page" is disabled. This
+ * method is meant for internal use and may change in future versions.
+ *
+ * @since 7.7
+ * @param selectedCaption
+ * the caption of selected item
+ */
+ public void setSelectedCaption(String selectedCaption) {
+ explicitSelectedCaption = selectedCaption;
+ if (selectedCaption != null) {
+ setText(selectedCaption);
+ }
+ }
+
+ /**
+ * This method is meant for internal use and may change in future versions.
+ *
+ * @since 7.7
+ * @return the caption of selected item, if "scroll to page" is disabled
+ */
+ public String getSelectedCaption() {
+ return explicitSelectedCaption;
+ }
+
+ /**
+ * Returns a handler receiving notifications from the connector about
+ * communications.
+ *
+ * @return the dataReceivedHandler
+ */
+ public DataReceivedHandler getDataReceivedHandler() {
+ return dataReceivedHandler;
+ }
+
+ /**
+ * Sets the number of items to show per page, or 0 for showing all items.
+ *
+ * @param pageLength
+ * new page length or 0 for all items
+ */
+ public void setPageLength(int pageLength) {
+ this.pageLength = pageLength;
+ }
+
+ /**
+ * Sets the suggestion pop-up's width as a CSS string. By using relative
+ * units (e.g. "50%") it's possible to set the popup's width relative to the
+ * ComboBox itself.
+ *
+ * @param suggestionPopupWidth
+ * new popup width as CSS string, null for old default width
+ * calculation based on items
+ */
+ public void setSuggestionPopupWidth(String suggestionPopupWidth) {
+ this.suggestionPopupWidth = suggestionPopupWidth;
+ }
+
+ /**
+ * Sets whether creation of new items when there is no match is allowed or
+ * not.
+ *
+ * @param allowNewItems
+ * true to allow creation of new items, false to only allow
+ * selection of existing items
+ */
+ public void setAllowNewItems(boolean allowNewItems) {
+ this.allowNewItems = allowNewItems;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.client.ui.combobox;
+
+import com.vaadin.client.Profiler;
+import com.vaadin.client.communication.RpcProxy;
+import com.vaadin.client.communication.StateChangeEvent;
+import com.vaadin.client.connectors.data.HasDataSource;
+import com.vaadin.client.data.DataSource;
+import com.vaadin.client.ui.AbstractFieldConnector;
+import com.vaadin.client.ui.SimpleManagedLayout;
+import com.vaadin.client.ui.VComboBox;
+import com.vaadin.client.ui.VComboBox.DataReceivedHandler;
+import com.vaadin.shared.EventId;
+import com.vaadin.shared.Registration;
+import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc;
+import com.vaadin.shared.data.DataCommunicatorConstants;
+import com.vaadin.shared.ui.Connect;
+import com.vaadin.shared.ui.combobox.ComboBoxClientRpc;
+import com.vaadin.shared.ui.combobox.ComboBoxConstants;
+import com.vaadin.shared.ui.combobox.ComboBoxServerRpc;
+import com.vaadin.shared.ui.combobox.ComboBoxState;
+import com.vaadin.ui.ComboBox;
+
+import elemental.json.JsonObject;
+
+@Connect(ComboBox.class)
+public class ComboBoxConnector extends AbstractFieldConnector
+ implements HasDataSource, SimpleManagedLayout {
+
+ protected ComboBoxServerRpc rpc = RpcProxy.create(ComboBoxServerRpc.class,
+ this);
+
+ protected FocusAndBlurServerRpc focusAndBlurRpc = RpcProxy
+ .create(FocusAndBlurServerRpc.class, this);
+
+ private DataSource<JsonObject> dataSource;
+
+ private Registration dataChangeHandlerRegistration;
+
+ @Override
+ protected void init() {
+ super.init();
+ getWidget().connector = this;
+ registerRpc(ComboBoxClientRpc.class, new ComboBoxClientRpc() {
+ @Override
+ public void setSelectedItem(String selectedKey,
+ String selectedCaption) {
+ getDataReceivedHandler().updateSelectionFromServer(selectedKey,
+ selectedCaption);
+ }
+ });
+ }
+
+ @Override
+ public void onStateChanged(StateChangeEvent stateChangeEvent) {
+ super.onStateChanged(stateChangeEvent);
+
+ Profiler.enter("ComboBoxConnector.onStateChanged update content");
+
+ getWidget().readonly = isReadOnly();
+ getWidget().updateReadOnly();
+
+ // not a FocusWidget -> needs own tabindex handling
+ getWidget().tb.setTabIndex(getState().tabIndex);
+
+ getWidget().suggestionPopup.updateStyleNames(getState());
+
+ getWidget().nullSelectionAllowed = getState().emptySelectionAllowed;
+ // TODO having this true would mean that the empty selection item comes
+ // from the data source so none needs to be added - currently
+ // unsupported
+ getWidget().nullSelectItem = false;
+
+ // make sure the input prompt is updated
+ getWidget().updatePlaceholder();
+
+ getDataReceivedHandler().serverReplyHandled();
+
+ Profiler.leave("ComboBoxConnector.onStateChanged update content");
+ }
+
+ @Override
+ public VComboBox getWidget() {
+ return (VComboBox) super.getWidget();
+ }
+
+ private DataReceivedHandler getDataReceivedHandler() {
+ return getWidget().getDataReceivedHandler();
+ }
+
+ @Override
+ public ComboBoxState getState() {
+ return (ComboBoxState) super.getState();
+ }
+
+ @Override
+ public void layout() {
+ VComboBox widget = getWidget();
+ if (widget.initDone) {
+ widget.updateRootWidth();
+ }
+ }
+
+ @Override
+ public void setWidgetEnabled(boolean widgetEnabled) {
+ super.setWidgetEnabled(widgetEnabled);
+ getWidget().enabled = widgetEnabled;
+ getWidget().tb.setEnabled(widgetEnabled);
+ }
+
+ /*
+ * These methods exist to move communications out of VComboBox, and may be
+ * refactored/removed in the future
+ */
+
+ /**
+ * Send a message about a newly created item to the server.
+ *
+ * This method is for internal use only and may be removed in future
+ * versions.
+ *
+ * @since
+ * @param itemValue
+ * user entered string value for the new item
+ */
+ public void sendNewItem(String itemValue) {
+ rpc.createNewItem(itemValue);
+ getDataReceivedHandler().clearPendingNavigation();
+ }
+
+ /**
+ * Send a message to the server set the current filter.
+ *
+ * This method is for internal use only and may be removed in future
+ * versions.
+ *
+ * @since
+ * @param filter
+ * the current filter string
+ */
+ public void setFilter(String filter) {
+ if (filter != getWidget().lastFilter) {
+ getDataReceivedHandler().clearPendingNavigation();
+ }
+ rpc.setFilter(filter);
+ }
+
+ /**
+ * Send a message to the server to request a page of items with the current
+ * filter.
+ *
+ * This method is for internal use only and may be removed in future
+ * versions.
+ *
+ * @since
+ * @param page
+ * the page number to get or -1 to let the server/connector
+ * decide based on current selection (possibly loading more data
+ * from the server)
+ */
+ public void requestPage(int page) {
+ if (page < 0) {
+ if (getState().scrollToSelectedItem) {
+ getDataSource().ensureAvailability(0, 10000);
+ return;
+ } else {
+ page = 0;
+ }
+ }
+ int adjustment = (getWidget().nullSelectionAllowed
+ && "".equals(getWidget().lastFilter)) ? 1 : 0;
+ int startIndex = Math.max(0,
+ page * getWidget().pageLength - adjustment);
+ int pageLength = getWidget().pageLength > 0 ? getWidget().pageLength
+ : 10000;
+ getDataSource().ensureAvailability(startIndex, pageLength);
+ }
+
+ /**
+ * Send a message to the server updating the current selection.
+ *
+ * This method is for internal use only and may be removed in future
+ * versions.
+ *
+ * @since
+ * @param selectionKey
+ * the current selected item key
+ */
+ public void sendSelection(String selectionKey) {
+ rpc.setSelectedItem(selectionKey);
+ getDataReceivedHandler().clearPendingNavigation();
+ }
+
+ /**
+ * Notify the server that the combo box received focus.
+ *
+ * For timing reasons, ConnectorFocusAndBlurHandler is not used at the
+ * moment.
+ *
+ * This method is for internal use only and may be removed in future
+ * versions.
+ *
+ * @since
+ */
+ public void sendFocusEvent() {
+ boolean registeredListeners = hasEventListener(EventId.FOCUS);
+ if (registeredListeners) {
+ focusAndBlurRpc.focus();
+ getDataReceivedHandler().clearPendingNavigation();
+ }
+ }
+
+ /**
+ * Notify the server that the combo box lost focus.
+ *
+ * For timing reasons, ConnectorFocusAndBlurHandler is not used at the
+ * moment.
+ *
+ * This method is for internal use only and may be removed in future
+ * versions.
+ *
+ * @since
+ */
+ public void sendBlurEvent() {
+ boolean registeredListeners = hasEventListener(EventId.BLUR);
+ if (registeredListeners) {
+ focusAndBlurRpc.blur();
+ getDataReceivedHandler().clearPendingNavigation();
+ }
+ }
+
+ @Override
+ public void setDataSource(DataSource<JsonObject> dataSource) {
+ this.dataSource = dataSource;
+ dataChangeHandlerRegistration = dataSource
+ .addDataChangeHandler(range -> {
+ // try to find selected item if requested
+ if (getState().scrollToSelectedItem
+ && getState().pageLength > 0
+ && getWidget().currentPage < 0
+ && getWidget().selectedOptionKey != null) {
+ // search for the item with the selected key
+ getWidget().currentPage = 0;
+ for (int i = 0; i < getDataSource().size(); ++i) {
+ JsonObject row = getDataSource().getRow(i);
+ if (row != null) {
+ String key = row.getString(
+ DataCommunicatorConstants.KEY);
+ if (getWidget().selectedOptionKey.equals(key)) {
+ if (getWidget().nullSelectionAllowed) {
+ getWidget().currentPage = (i + 1)
+ / getState().pageLength;
+ } else {
+ getWidget().currentPage = i
+ / getState().pageLength;
+ }
+ break;
+ }
+ }
+ }
+ } else if (getWidget().currentPage < 0) {
+ getWidget().currentPage = 0;
+ }
+
+ getWidget().currentSuggestions.clear();
+
+ int start = getWidget().currentPage
+ * getWidget().pageLength;
+ int end = getWidget().pageLength > 0
+ ? start + getWidget().pageLength
+ : getDataSource().size();
+
+ if (getWidget().nullSelectionAllowed
+ && "".equals(getWidget().lastFilter)) {
+ // add special null selection item...
+ if (getWidget().currentPage == 0) {
+ getWidget().currentSuggestions
+ .add(getWidget().new ComboBoxSuggestion("",
+ "", null, null));
+ } else {
+ // ...or leave space for it
+ start = start - 1;
+ }
+ // in either case, the last item to show is
+ // shifted by one
+ end = end - 1;
+ }
+
+ for (int i = start; i < end; ++i) {
+ JsonObject row = getDataSource().getRow(i);
+
+ if (row != null) {
+ String key = row
+ .getString(DataCommunicatorConstants.KEY);
+ String caption = row
+ .getString(DataCommunicatorConstants.NAME);
+ String style = row
+ .getString(ComboBoxConstants.STYLE);
+ String untranslatedIconUri = row
+ .getString(ComboBoxConstants.ICON);
+ getWidget().currentSuggestions
+ .add(getWidget().new ComboBoxSuggestion(key,
+ caption, style,
+ untranslatedIconUri));
+ }
+ }
+ getWidget().totalMatches = getDataSource().size()
+ + (getState().emptySelectionAllowed ? 1 : 0);
+
+ getDataReceivedHandler().dataReceived();
+ });
+ }
+
+ @Override
+ public void onUnregister() {
+ super.onUnregister();
+ dataChangeHandlerRegistration.remove();
+ }
+
+ @Override
+ public DataSource<JsonObject> getDataSource() {
+ return dataSource;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.vaadin.ui;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+import com.vaadin.data.HasValue;
+import com.vaadin.event.FieldEvents;
+import com.vaadin.event.FieldEvents.BlurEvent;
+import com.vaadin.event.FieldEvents.BlurListener;
+import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl;
+import com.vaadin.event.FieldEvents.FocusEvent;
+import com.vaadin.event.FieldEvents.FocusListener;
+import com.vaadin.event.selection.SingleSelectionChange;
+import com.vaadin.event.selection.SingleSelectionListener;
+import com.vaadin.server.KeyMapper;
+import com.vaadin.server.Resource;
+import com.vaadin.server.ResourceReference;
+import com.vaadin.server.data.DataCommunicator;
+import com.vaadin.server.data.DataKeyMapper;
+import com.vaadin.server.data.DataSource;
+import com.vaadin.shared.Registration;
+import com.vaadin.shared.data.DataCommunicatorConstants;
+import com.vaadin.shared.data.selection.SelectionModel;
+import com.vaadin.shared.ui.combobox.ComboBoxClientRpc;
+import com.vaadin.shared.ui.combobox.ComboBoxConstants;
+import com.vaadin.shared.ui.combobox.ComboBoxServerRpc;
+import com.vaadin.shared.ui.combobox.ComboBoxState;
+
+import elemental.json.JsonObject;
+
+/**
+ * A filtering dropdown single-select. Items are filtered based on user input.
+ * Supports the creation of new items when a handler is set by the user.
+ *
+ * @param <T>
+ * item (bean) type in ComboBox
+ * @author Vaadin Ltd
+ */
+@SuppressWarnings("serial")
+public class ComboBox<T> extends
+ AbstractListing<T, ComboBox<T>.ComboBoxSelectionModel> implements
+ HasValue<T>, FieldEvents.BlurNotifier, FieldEvents.FocusNotifier {
+
+ /**
+ * Custom single selection model for ComboBox.
+ */
+ protected class ComboBoxSelectionModel implements SelectionModel.Single<T> {
+ private Optional<T> selectedItem = Optional.empty();
+ private List<SingleSelectionListener<T>> listeners = new ArrayList<>(2);
+
+ @Override
+ public void deselect(T item) {
+ selectedItem.ifPresent(selected -> {
+ if (selected.equals(item)) {
+ setValue(Optional.empty(), false);
+ }
+ });
+ }
+
+ /**
+ * Sets the selection. This method is primarily for internal use.
+ *
+ * @param value
+ * optional new value
+ * @param userOriginated
+ * true if the value comes from user input, false otherwise
+ */
+ protected void setValue(Optional<T> value, boolean userOriginated) {
+ if (selectedItem.equals(value)) {
+ return;
+ }
+ selectedItem = value;
+ String key = value
+ .map(v -> getDataCommunicator().getKeyMapper().key(v))
+ .orElse(null);
+ String selectedCaption = value
+ .map(v -> getItemCaptionProvider().apply(v)).orElse(null);
+ getRpcProxy(ComboBoxClientRpc.class).setSelectedItem(key,
+ selectedCaption);
+
+ fireEvent(userOriginated);
+ }
+
+ /**
+ * Adds a selection listener to this select. The listener is called when
+ * the value of this select is changed either by the user or
+ * programmatically.
+ *
+ * @param listener
+ * the value change listener, not null
+ * @return a registration for the listener
+ */
+ public Registration addSelectionListener(
+ SingleSelectionListener<T> listener) {
+ Objects.requireNonNull(listener, "listener cannot be null");
+ listeners.add(listener);
+ return () -> listeners.remove(listener);
+ }
+
+ @Override
+ public void select(T item) {
+ Objects.requireNonNull(item);
+ setValue(Optional.of(item), false);
+ }
+
+ @Override
+ public Optional<T> getSelectedItem() {
+ return selectedItem;
+ }
+
+ /**
+ * Fires a selection change event to all listeners.
+ *
+ * @param userOriginated
+ * true to indicate that the change was caused directly by a
+ * user action, false for programmatically set values
+ */
+ protected void fireEvent(boolean userOriginated) {
+ for (SingleSelectionListener<T> listener : listeners) {
+ listener.accept(new SingleSelectionChange<T>(ComboBox.this,
+ getSelectedItem().orElse(null), userOriginated));
+ }
+ }
+ }
+
+ /**
+ * Handler that adds a new item based on user input when the new items
+ * allowed mode is active.
+ */
+ @FunctionalInterface
+ public interface NewItemHandler extends Consumer<String>, Serializable {
+ }
+
+ /**
+ * ItemCaptionProvider can be used to customize the string shown to the user
+ * for an item.
+ *
+ * @see ComboBox#setItemCaptionProvider(ItemCaptionProvider)
+ * @param <T>
+ * item type in the combo box
+ */
+ @FunctionalInterface
+ public interface ItemCaptionProvider<T>
+ extends Function<T, String>, Serializable {
+ }
+
+ /**
+ * ItemStyleProvider can be used to add custom styles to combo box items
+ * shown in the popup. The CSS class name that will be added to the item
+ * style names is <tt>v-filterselect-item-[style name]</tt>.
+ *
+ * @see ComboBox#setItemStyleProvider(ItemStyleProvider)
+ * @param <T>
+ * item type in the combo box
+ */
+ @FunctionalInterface
+ public interface ItemStyleProvider<T>
+ extends Function<T, String>, Serializable {
+ }
+
+ /**
+ * ItemIconProvider can be used to add custom icons to combo box items shown
+ * in the popup.
+ *
+ * @see ComboBox#setItemIconProvider(ItemIconProvider)
+ * @param <T>
+ * item type in the combo box
+ */
+ @FunctionalInterface
+ public interface ItemIconProvider<T>
+ extends Function<T, Resource>, Serializable {
+ }
+
+ /**
+ * Filter can be used to customize the filtering of items based on user
+ * input.
+ *
+ * @see ComboBox#setFilter(ItemFilter)
+ * @param <T>
+ * item type in the combo box
+ */
+ @FunctionalInterface
+ public interface ItemFilter<T>
+ extends BiFunction<String, T, Boolean>, Serializable {
+ }
+
+ private ComboBoxServerRpc rpc = new ComboBoxServerRpc() {
+ @Override
+ public void createNewItem(String itemValue) {
+ // New option entered
+ if (getNewItemHandler() != null && itemValue != null
+ && itemValue.length() > 0) {
+ getNewItemHandler().accept(itemValue);
+ // rebuild list
+ filterstring = null;
+ }
+ }
+
+ @Override
+ public void setSelectedItem(String key) {
+ // it seems both of these happen, and mean empty selection...
+ if (key == null || "".equals(key)) {
+ getSelectionModel().setValue(Optional.empty(), true);
+ } else {
+ T item = getDataCommunicator().getKeyMapper().get(key);
+ getSelectionModel().setValue(Optional.ofNullable(item), true);
+ }
+ }
+
+ @Override
+ public void setFilter(String filterText) {
+ filterstring = filterText;
+ if (filterText != null) {
+ getDataCommunicator().setInMemoryFilter(
+ item -> filter.apply(filterstring, item));
+ } else {
+ getDataCommunicator().setInMemoryFilter(null);
+ }
+ }
+ };
+
+ private FocusAndBlurServerRpcImpl focusBlurRpc = new FocusAndBlurServerRpcImpl(
+ this) {
+ @Override
+ protected void fireEvent(Component.Event event) {
+ ComboBox.this.fireEvent(event);
+ }
+ };
+
+ private String filterstring;
+
+ /**
+ * Handler for new items entered by the user.
+ */
+ private NewItemHandler newItemHandler;
+
+ private ItemCaptionProvider<T> itemCaptionProvider = String::valueOf;
+
+ private ItemStyleProvider<T> itemStyleProvider = item -> null;
+ private ItemIconProvider<T> itemIconProvider = item -> null;
+
+ private ItemFilter<T> filter = (filterText, item) -> {
+ if (filterText == null) {
+ return true;
+ } else {
+ return getItemCaptionProvider().apply(item).toLowerCase(getLocale())
+ .contains(filterText.toLowerCase(getLocale()));
+ }
+ };
+
+ /**
+ * Constructs an empty combo box without a caption. The content of the combo
+ * box can be set with {@link #setDataSource(DataSource)} or
+ * {@link #setItems(Collection)}
+ */
+ public ComboBox() {
+ super(new DataCommunicator<T>() {
+ @Override
+ protected DataKeyMapper<T> createKeyMapper() {
+ return new KeyMapper<T>() {
+ @Override
+ public void remove(T removeobj) {
+ // never remove keys from ComboBox to support selection
+ // of items that are not currently visible
+ }
+ };
+ }
+ });
+ setSelectionModel(new ComboBoxSelectionModel());
+
+ init();
+ }
+
+ /**
+ * Constructs an empty combo box, whose content can be set with
+ * {@link #setDataSource(DataSource)} or {@link #setItems(Collection)}.
+ *
+ * @param caption
+ * the caption to show in the containing layout, null for no
+ * caption
+ */
+ public ComboBox(String caption) {
+ this();
+ setCaption(caption);
+ }
+
+ /**
+ * Constructs a combo box with a static in-memory data source with the given
+ * options.
+ *
+ * @param caption
+ * the caption to show in the containing layout, null for no
+ * caption
+ * @param options
+ * collection of options, not null
+ */
+ public ComboBox(String caption, Collection<T> options) {
+ this(caption, DataSource.create(options));
+ }
+
+ /**
+ * Constructs a combo box with the given data source.
+ *
+ * @param caption
+ * the caption to show in the containing layout, null for no
+ * caption
+ * @param dataSource
+ * the data source to use, not null
+ */
+ public ComboBox(String caption, DataSource<T> dataSource) {
+ this(caption);
+ setDataSource(dataSource);
+ }
+
+ /**
+ * Initialize the ComboBox with default settings and register client to
+ * server RPC implementation.
+ */
+ private void init() {
+ registerRpc(rpc);
+ registerRpc(focusBlurRpc);
+
+ addDataGenerator((T data, JsonObject jsonObject) -> {
+ jsonObject.put(DataCommunicatorConstants.NAME,
+ getItemCaptionProvider().apply(data));
+ String style = itemStyleProvider.apply(data);
+ if (style != null) {
+ jsonObject.put(ComboBoxConstants.STYLE, style);
+ }
+ Resource icon = itemIconProvider.apply(data);
+ if (icon != null) {
+ String iconUrl = ResourceReference
+ .create(icon, ComboBox.this, null).getURL();
+ jsonObject.put(ComboBoxConstants.ICON, iconUrl);
+ }
+ });
+ }
+
+ /**
+ * Gets the current placeholder text shown when the combo box would be
+ * empty.
+ *
+ * @see #setPlaceholder(String)
+ * @return the current placeholder string, or null if not enabled
+ */
+ public String getPlaceholder() {
+ return getState(false).placeholder;
+ }
+
+ /**
+ * Sets the placeholder string - a textual prompt that is displayed when the
+ * select would otherwise be empty, to prompt the user for input.
+ *
+ * @param placeholder
+ * the desired placeholder, or null to disable
+ */
+ public void setPlaceholder(String placeholder) {
+ getState().placeholder = placeholder;
+ }
+
+ /**
+ * Sets whether it is possible to input text into the field or whether the
+ * field area of the component is just used to show what is selected. By
+ * disabling text input, the comboBox will work in the same way as a
+ * {@link NativeSelect}
+ *
+ * @see #isTextInputAllowed()
+ *
+ * @param textInputAllowed
+ * true to allow entering text, false to just show the current
+ * selection
+ */
+ public void setTextInputAllowed(boolean textInputAllowed) {
+ getState().textInputAllowed = textInputAllowed;
+ }
+
+ /**
+ * Returns true if the user can enter text into the field to either filter
+ * the selections or enter a new value if {@link #isNewItemsAllowed()}
+ * returns true. If text input is disabled, the comboBox will work in the
+ * same way as a {@link NativeSelect}
+ *
+ * @return true if text input is allowed
+ */
+ public boolean isTextInputAllowed() {
+ return getState(false).textInputAllowed;
+ }
+
+ @Override
+ public void addBlurListener(BlurListener listener) {
+ addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener,
+ BlurListener.blurMethod);
+ }
+
+ @Override
+ public void removeBlurListener(BlurListener listener) {
+ removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener);
+ }
+
+ @Override
+ public void addFocusListener(FocusListener listener) {
+ addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener,
+ FocusListener.focusMethod);
+ }
+
+ @Override
+ public void removeFocusListener(FocusListener listener) {
+ removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener);
+ }
+
+ /**
+ * Returns the page length of the suggestion popup.
+ *
+ * @return the pageLength
+ */
+ public int getPageLength() {
+ return getState(false).pageLength;
+ }
+
+ /**
+ * Returns the suggestion pop-up's width as a CSS string.
+ *
+ * @see #setPopupWidth
+ * @since 7.7
+ * @return explicitly set popup width as CSS size string or null if not set
+ */
+ public String getPopupWidth() {
+ return getState(false).suggestionPopupWidth;
+ }
+
+ /**
+ * Sets the page length for the suggestion popup. Setting the page length to
+ * 0 will disable suggestion popup paging (all items visible).
+ *
+ * @param pageLength
+ * the pageLength to set
+ */
+ public void setPageLength(int pageLength) {
+ getState().pageLength = pageLength;
+ }
+
+ /**
+ * Returns whether the user is allowed to select nothing in the combo box.
+ *
+ * @return true if empty selection is allowed, false otherwise
+ */
+ public boolean isEmptySelectionAllowed() {
+ return getState(false).emptySelectionAllowed;
+ }
+
+ /**
+ * Sets whether the user is allowed to select nothing in the combo box. When
+ * true, a special empty item is shown to the user.
+ *
+ * @param emptySelectionAllowed
+ * true to allow not selecting anything, false to require
+ * selection
+ */
+ public void setEmptySelectionAllowed(boolean emptySelectionAllowed) {
+ getState().emptySelectionAllowed = emptySelectionAllowed;
+ }
+
+ /**
+ * Sets the suggestion pop-up's width as a CSS string. By using relative
+ * units (e.g. "50%") it's possible to set the popup's width relative to the
+ * ComboBox itself.
+ *
+ * @see #getPopupWidth()
+ * @since 7.7
+ * @param width
+ * the width
+ */
+ public void setPopupWidth(String width) {
+ getState().suggestionPopupWidth = width;
+ }
+
+ /**
+ * Sets whether to scroll the selected item visible (directly open the page
+ * on which it is) when opening the combo box popup or not.
+ *
+ * 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) {
+ getState().scrollToSelectedItem = scrollToSelectedItem;
+ }
+
+ /**
+ * Returns true if the select should find the page with the selected item
+ * when opening the popup.
+ *
+ * @see #setScrollToSelectedItem(boolean)
+ *
+ * @return true if the page with the selected item will be shown when
+ * opening the popup
+ */
+ public boolean isScrollToSelectedItem() {
+ return getState(false).scrollToSelectedItem;
+ }
+
+ /**
+ * Gets the item caption provider that is used to produce the strings shown
+ * in the combo box for each item.
+ *
+ * @return the item caption provider used, not null
+ */
+ public ItemCaptionProvider<T> getItemCaptionProvider() {
+ return itemCaptionProvider;
+ }
+
+ /**
+ * Sets the item caption provider that is used to produce the strings shown
+ * in the combo box for each item. By default,
+ * {@link String#valueOf(Object)} is used.
+ *
+ * @param itemCaptionProvider
+ * the item caption provider to use, not null
+ */
+ public void setItemCaptionProvider(
+ ItemCaptionProvider<T> itemCaptionProvider) {
+ Objects.requireNonNull(itemCaptionProvider,
+ "Item caption providers must not be null");
+ this.itemCaptionProvider = itemCaptionProvider;
+ getDataCommunicator().reset();
+ }
+
+ /**
+ * Sets the item style provider that is used to produce custom styles for
+ * showing items in the popup. The CSS class name that will be added to the
+ * item style names is <tt>v-filterselect-item-[style name]</tt>. Returning
+ * null from the provider results in no custom style name being set.
+ *
+ * @param itemStyleProvider
+ * the item style provider to set, not null
+ */
+ public void setItemStyleProvider(ItemStyleProvider<T> itemStyleProvider) {
+ Objects.requireNonNull(itemStyleProvider,
+ "Item style providers must not be null");
+ this.itemStyleProvider = itemStyleProvider;
+ getDataCommunicator().reset();
+ }
+
+ /**
+ * Gets the currently used item style provider that is used to generate CSS
+ * class names for items. The default item style provider returns null for
+ * all items, resulting in no custom item class names being set.
+ *
+ * @see #setItemStyleProvider(ItemStyleProvider)
+ *
+ * @return the currently used item style provider, not null
+ */
+ public ItemStyleProvider<T> getItemStyleProvider() {
+ return itemStyleProvider;
+ }
+
+ /**
+ * Sets the item icon provider that is used to produce custom icons for
+ * showing items in the popup. The provider can return null for items with
+ * no icon.
+ *
+ * @param itemIconProvider
+ * the item icon provider to set, not null
+ */
+ public void setItemIconProvider(ItemIconProvider<T> itemIconProvider) {
+ Objects.requireNonNull(itemIconProvider,
+ "Item icon providers must not be null");
+ this.itemIconProvider = itemIconProvider;
+ getDataCommunicator().reset();
+ }
+
+ /**
+ * Gets the currently used item icon provider. The default item icon
+ * provider returns null for all items, resulting in no icons being used.
+ *
+ * @see #setItemIconProvider(ItemIconProvider)
+ *
+ * @return the currently used item icon provider, not null
+ */
+ public ItemIconProvider<T> getItemIconProvider() {
+ return itemIconProvider;
+ }
+
+ /**
+ * Sets the handler that is called when user types a new item. The creation
+ * of new items is allowed when a new item handler has been set.
+ *
+ * @param newItemHandler
+ * handler called for new items, null to only permit the
+ * selection of existing items
+ */
+ public void setNewItemHandler(NewItemHandler newItemHandler) {
+ this.newItemHandler = newItemHandler;
+ getState().allowNewItems = (newItemHandler != null);
+ markAsDirty();
+ }
+
+ /**
+ * Returns the handler called when the user enters a new item (not present
+ * in the data source).
+ *
+ * @return new item handler or null if none specified
+ */
+ public NewItemHandler getNewItemHandler() {
+ return newItemHandler;
+ }
+
+ // HasValue methods delegated to the selection model
+
+ /**
+ * Returns the filter used to customize the list based on user input.
+ *
+ * @return the current filter, not null
+ */
+ public ItemFilter<T> getFilter() {
+ return filter;
+ }
+
+ /**
+ * Sets the filter used to customize the list based on user input. The
+ * default filter checks case-insensitively that the input string is
+ * contained in the item caption.
+ *
+ * @param filter
+ * the filter function to use, not null
+ */
+ public void setFilter(ItemFilter<T> filter) {
+ Objects.requireNonNull(filter, "Item filter must not be null");
+ this.filter = filter;
+ }
+
+ @Override
+ public void setValue(T value) {
+ getSelectionModel().setValue(Optional.ofNullable(value), false);
+
+ }
+
+ @Override
+ public T getValue() {
+ return getSelectionModel().getSelectedItem().orElse(null);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Registration addValueChangeListener(
+ HasValue.ValueChangeListener<? super T> listener) {
+ return getSelectionModel().addSelectionListener(event -> {
+ ((ValueChangeListener<T>) listener)
+ .accept(new ValueChange<T>(event.getConnector(),
+ event.getValue(), event.isUserOriginated()));
+ });
+ }
+
+ @Override
+ protected ComboBoxState getState() {
+ return (ComboBoxState) super.getState();
+ }
+
+ @Override
+ protected ComboBoxState getState(boolean markAsDirty) {
+ return (ComboBoxState) super.getState(markAsDirty);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.combobox;
+
+import com.vaadin.shared.communication.ClientRpc;
+
+/**
+ * Server to client RPC interface for ComboBox.
+ *
+ * @since
+ */
+public interface ComboBoxClientRpc extends ClientRpc {
+ /**
+ * Set the current selection.
+ *
+ * @param selectedKey
+ * the id of a single item or null to deselect the current value
+ * @param selectedCaption
+ * the caption of the selected item (used in case selection is
+ * outside the lazy loaded range)
+ */
+ public void setSelectedItem(String selectedKey, String selectedCaption);
+}
--- /dev/null
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.combobox;
+
+import java.io.Serializable;
+
+/**
+ * Constants related to the combo box component and its client-server
+ * communication.
+ *
+ * @since 8.0
+ * @author Vaadin Ltd
+ */
+public class ComboBoxConstants implements Serializable {
+ public static final String STYLE = "style";
+ public static final String ICON = "icon";
+}
--- /dev/null
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.combobox;
+
+import com.vaadin.shared.communication.ServerRpc;
+
+/**
+ * Client to server RPC interface for ComboBox.
+ *
+ * @since
+ */
+public interface ComboBoxServerRpc extends ServerRpc {
+ /**
+ * Create a new item in the combo box. This method can only be used when the
+ * ComboBox is configured to allow the creation of new items by the user.
+ *
+ * @param itemValue
+ * user entered string value for the new item
+ */
+ public void createNewItem(String itemValue);
+
+ /**
+ * Set the current selection.
+ *
+ * @param item
+ * the id of a single item or null to deselect the current value
+ */
+ public void setSelectedItem(String item);
+
+ /**
+ * Sets the filter to use.
+ *
+ * @param filter
+ * filter string interpreted according to the current filtering
+ * mode
+ */
+ public void setFilter(String filter);
+}
--- /dev/null
+/*
+ * Copyright 2000-2016 Vaadin Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.vaadin.shared.ui.combobox;
+
+import com.vaadin.shared.AbstractFieldState;
+import com.vaadin.shared.annotations.DelegateToWidget;
+import com.vaadin.shared.annotations.NoLayout;
+
+/**
+ * Shared state for the ComboBox component.
+ *
+ * @since 7.0
+ */
+public class ComboBoxState extends AbstractFieldState {
+ {
+ // TODO ideally this would be v-combobox, but that would affect a lot of
+ // themes
+ primaryStyleName = "v-filterselect";
+ }
+
+ /**
+ * If text input is not allowed, the ComboBox behaves like a pretty
+ * NativeSelect - the user can not enter any text and clicking the text
+ * field opens the drop down with options.
+ *
+ * @since
+ */
+ @DelegateToWidget
+ public boolean textInputAllowed = true;
+
+ /**
+ * The prompt to display in an empty field. Null when disabled.
+ */
+ @DelegateToWidget
+ @NoLayout
+ public String placeholder = null;
+
+ /**
+ * Number of items to show per page or 0 to disable paging.
+ */
+ @DelegateToWidget
+ public int pageLength = 10;
+
+ /**
+ * Suggestion pop-up's width as a CSS string. By using relative units (e.g.
+ * "50%") it's possible to set the popup's width relative to the ComboBox
+ * itself.
+ */
+ @DelegateToWidget
+ public String suggestionPopupWidth = null;
+
+ /**
+ * True to allow the user to send new items to the server, false to only
+ * select among existing items.
+ */
+ @DelegateToWidget
+ public boolean allowNewItems = false;
+
+ /**
+ * True to allow selecting nothing (a special empty selection item is shown
+ * at the beginning of the list), false not to allow empty selection by the
+ * user.
+ */
+ public boolean emptySelectionAllowed = true;
+
+ /**
+ * True to automatically scroll the ComboBox to show the selected item,
+ * false not to search for it in the results.
+ */
+ public boolean scrollToSelectedItem = false;
+
+}
--- /dev/null
+package com.vaadin.testbench.customelements;
+
+import org.junit.Assert;
+import org.openqa.selenium.WebElement;
+
+import com.vaadin.testbench.By;
+import com.vaadin.testbench.elementsbase.ServerClass;
+
+@ServerClass("com.vaadin.ui.ComboBox")
+public class ComboBoxElement
+ extends com.vaadin.testbench.elements.ComboBoxElement {
+
+ private static org.openqa.selenium.By bySuggestionPopup = By
+ .vaadin("#popup");
+
+ public WebElement getInputField() {
+ return findElement(By.vaadin("#textbox"));
+ }
+
+ @Override
+ public String getText() {
+ return getInputField().getAttribute("value");
+ }
+
+ @Override
+ public void clear() {
+ getInputField().clear();
+ }
+
+ public WebElement getSuggestionPopup() {
+ return findElement(bySuggestionPopup);
+ }
+
+ @Override
+ public void sendKeys(CharSequence... keysToSend) {
+ sendKeys(50, keysToSend);
+ }
+
+ /**
+ * Use this method to simulate typing into an element, which may set its
+ * value.
+ *
+ * @param delay
+ * delay after sending each individual key (mainly needed for
+ * PhantomJS)
+ * @param keysToSend
+ * keys to type into the element
+ */
+ public void sendKeys(int delay, CharSequence... keysToSend) {
+ WebElement input = getInputField();
+
+ for (CharSequence key : keysToSend) {
+ input.sendKeys(key);
+ try {
+ Thread.sleep(delay);
+ } catch (InterruptedException e) {
+ Assert.fail(e.getMessage());
+ }
+ }
+ }
+}
import com.vaadin.server.CompositeErrorMessage;
import com.vaadin.server.UserError;
import com.vaadin.ui.Button;
-import com.vaadin.v7.ui.ComboBox;
-import com.vaadin.v7.ui.TextField;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.TextField;
public class ErrorMessages extends TestBase {
tf.setComponentError(new UserError("This is a failure"));
addComponent(tf);
- ComboBox cb = new ComboBox("ComboBox with description and UserError");
+ ComboBox<String> cb = new ComboBox<>(
+ "ComboBox with description and UserError");
cb.setDescription("This is a combobox");
cb.setComponentError(new UserError("This is a failure"));
addComponent(cb);
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.DateField;
import com.vaadin.ui.Label;
import com.vaadin.ui.Layout;
import com.vaadin.ui.NativeButton;
import com.vaadin.ui.VerticalLayout;
-import com.vaadin.v7.ui.ComboBox;
import com.vaadin.v7.ui.OptionGroup;
import com.vaadin.v7.ui.TextField;
import com.vaadin.tests.VaadinClasses;
import com.vaadin.tests.components.TestBase;
import com.vaadin.tests.util.Log;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.ComponentContainer;
import com.vaadin.ui.Embedded;
import com.vaadin.ui.Label;
import com.vaadin.ui.VerticalLayout;
-import com.vaadin.v7.data.Property.ValueChangeEvent;
-import com.vaadin.v7.data.Property.ValueChangeListener;
-import com.vaadin.v7.ui.ComboBox;
public class IconsInCaption extends TestBase {
private Log log = new Log(5);
- private ComboBox containerSelect;
+ private ComboBox<Class<? extends ComponentContainer>> containerSelect;
- private ComboBox iconTypeSelect;
+ private ComboBox<String> iconTypeSelect;
@Override
protected void setup() {
- iconTypeSelect = new ComboBox("Icon container");
- iconTypeSelect.addItem(TYPE_EMBEDDED);
- iconTypeSelect.addItem(TYPE_CAPTION);
- iconTypeSelect.setImmediate(true);
- iconTypeSelect.setNullSelectionAllowed(false);
- iconTypeSelect.addListener(new ValueChangeListener() {
- @Override
- public void valueChange(ValueChangeEvent event) {
- updateContainer();
- }
- });
-
- containerSelect = new ComboBox("Container");
- for (Class<? extends ComponentContainer> cc : VaadinClasses
- .getComponentContainersSupportingUnlimitedNumberOfComponents()) {
- containerSelect.addItem(cc);
- }
- containerSelect.setImmediate(true);
- containerSelect.addListener(new ValueChangeListener() {
+ iconTypeSelect = new ComboBox<>("Icon container");
+ iconTypeSelect.setItems(TYPE_EMBEDDED, TYPE_CAPTION);
+ iconTypeSelect.setEmptySelectionAllowed(false);
+ iconTypeSelect.addValueChangeListener(event -> updateContainer());
- @Override
- public void valueChange(ValueChangeEvent event) {
- updateContainer();
-
- }
- });
+ containerSelect = new ComboBox<>("Container", VaadinClasses
+ .getComponentContainersSupportingUnlimitedNumberOfComponents());
+ containerSelect.addValueChangeListener(event -> updateContainer());
addComponent(log);
addComponent(iconTypeSelect);
}
protected void updateContainer() {
- Class<? extends ComponentContainer> containerClass = (Class<? extends ComponentContainer>) containerSelect
+ Class<? extends ComponentContainer> containerClass = containerSelect
.getValue();
if (containerClass == null) {
return;
import com.vaadin.server.UserError;
import com.vaadin.tests.components.TestBase;
-import com.vaadin.v7.data.Property.ValueChangeEvent;
-import com.vaadin.v7.data.Property.ValueChangeListener;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
public class ComboBoxBorder extends TestBase {
protected void setup() {
setTheme("tests-tickets");
- final ComboBox cb = new ComboBox("All errors",
+ final ComboBox<String> cb = new ComboBox<>("All errors",
Arrays.asList("Error", "Error 2"));
cb.setStyleName("ComboBoxBorder");
- cb.setImmediate(true);
cb.setWidth("200px"); // must have with to reproduce
- cb.addListener(new ValueChangeListener() {
- public void valueChange(ValueChangeEvent event) {
- cb.setComponentError(new UserError("Error"));
- }
- });
+ cb.addValueChangeListener(
+ event -> cb.setComponentError(new UserError("Error")));
addComponent(cb);
*/
package com.vaadin.tests.components.combobox;
-import java.util.ArrayList;
-import java.util.List;
-
import com.vaadin.server.FontAwesome;
import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.data.DataSource;
import com.vaadin.tests.components.AbstractTestUI;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
/**
* Test UI to check click on icon in the combobox.
@Override
protected void setup(VaadinRequest request) {
- final List<String> items = new ArrayList<>();
- items.add("A");
- items.add("B");
- items.add("C");
- final ComboBox combo = new ComboBox();
- combo.setImmediate(true);
- combo.setItemIcon(items.get(0), FontAwesome.ALIGN_CENTER);
- combo.setItemIcon(items.get(1), FontAwesome.ALIGN_CENTER);
- combo.setItemIcon(items.get(2), FontAwesome.ALIGN_CENTER);
- combo.addItems(items);
+ final ComboBox<String> combo = new ComboBox<>(null,
+ DataSource.create("A", "B", "C"));
+ combo.setItemIconProvider(item -> FontAwesome.ALIGN_CENTER);
combo.setTextInputAllowed(false);
addComponent(combo);
}
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
-import com.vaadin.v7.ui.ComboBox;
public class ComboBoxCursorPositionReset extends AbstractTestUI {
root.setSizeFull();
setContent(root);
- ComboBox combo = new ComboBox();
+ ComboBox<String> combo = new ComboBox<>();
combo.setImmediate(true);
root.addComponent(combo);
- combo.addItem("Hello World");
- combo.addItem("Please click on the text");
+ combo.setItems("Hello World", "Please click on the text");
combo.setValue("Please click on the text");
Label gap = new Label();
import com.vaadin.tests.util.Log;
import com.vaadin.tests.util.Person;
import com.vaadin.ui.Button;
-import com.vaadin.v7.data.Property.ValueChangeListener;
-import com.vaadin.v7.data.util.BeanItemContainer;
-import com.vaadin.v7.ui.AbstractSelect.ItemCaptionMode;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
public class ComboBoxDuplicateCaption extends TestBase {
p2.setLastName("Doe");
list.add(p2);
- BeanItemContainer<Person> container = new BeanItemContainer<>(
- Person.class);
- container.addAll(list);
-
- ComboBox box = new ComboBox("Duplicate captions test Box");
+ ComboBox<Person> box = new ComboBox<>("Duplicate captions test Box");
box.setId("ComboBox");
- box.setImmediate(true);
- box.addValueChangeListener(new ValueChangeListener() {
-
- @Override
- public void valueChange(
- com.vaadin.v7.data.Property.ValueChangeEvent event) {
- Person p = (Person) event.getProperty().getValue();
- log.log("Person = " + p.getFirstName() + " " + p.getLastName());
- }
+ box.addValueChangeListener(event -> {
+ Person p = event.getValue();
+ log.log("Person = " + p.getFirstName() + " " + p.getLastName());
});
- box.setContainerDataSource(container);
- box.setItemCaptionMode(ItemCaptionMode.PROPERTY);
- box.setItemCaptionPropertyId("lastName");
+ box.setItems(list);
+ box.setItemCaptionProvider(Person::getLastName);
addComponent(log);
@Override
protected String getDescription() {
- return "VFilterSelects with duplicate item captions should not try to do a select (exact match search) for onBlur if not waitingForFilteringResponse";
+ return "ComboBoxes with duplicate item captions should not try to do a select (exact match search) for onBlur if not waitingForFilteringResponse";
}
@Override
package com.vaadin.tests.components.combobox;
import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.data.DataSource;
import com.vaadin.tests.components.AbstractTestUI;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
public class ComboBoxEmptyItemsKeyboardNavigation extends AbstractTestUI {
@Override
protected void setup(VaadinRequest request) {
- ComboBox comboBox = new ComboBox();
- comboBox.addItems("foo", "bar");
+ ComboBox<String> comboBox = new ComboBox<>(null,
+ DataSource.create("foo", "bar"));
addComponent(comboBox);
}
package com.vaadin.tests.components.combobox;
+import java.util.ArrayList;
+import java.util.List;
+
import com.vaadin.tests.components.TestBase;
-import com.vaadin.v7.data.Property.ValueChangeEvent;
-import com.vaadin.v7.data.Property.ValueChangeListener;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
public class ComboBoxEnablesComboBox extends TestBase {
@Override
protected void setup() {
- ComboBox cb = new ComboBox("Always enabled");
- cb.setImmediate(true);
+ ComboBox<String> cb = new ComboBox<>("Always enabled");
populate(cb);
- cb.addListener(new ValueChangeListener() {
-
- @Override
- public void valueChange(ValueChangeEvent event) {
- cb2.setEnabled(true);
- }
-
- });
- cb2 = new ComboBox("Initially disabled");
- cb2.setImmediate(true);
+ cb.addValueChangeListener(event -> cb2.setEnabled(true));
+ cb2 = new ComboBox<String>("Initially disabled");
cb2.setEnabled(false);
populate(cb2);
addComponent(cb2);
}
- private void populate(ComboBox cb) {
+ private void populate(ComboBox<String> cb) {
+ List<String> items = new ArrayList<>();
for (int i = 1; i < 10; i++) {
- cb.addItem("Item " + i);
+ items.add("Item " + i);
}
+ cb.setItems(items);
}
@Override
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.tests.util.Log;
-import com.vaadin.v7.data.Item;
-import com.vaadin.v7.data.Property;
-import com.vaadin.v7.data.Property.ValueChangeEvent;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
public class ComboBoxIdenticalItems extends AbstractTestUI {
private Log log = new Log(5);
- @SuppressWarnings("unchecked")
@Override
protected void setup(VaadinRequest request) {
- final ComboBox select = new ComboBox("ComboBox");
- select.addContainerProperty("caption", String.class, null);
- Item item = select.addItem("one-1");
- item.getItemProperty("caption").setValue("One");
- item = select.addItem("one-2");
- item.getItemProperty("caption").setValue("One");
- item = select.addItem("two");
- item.getItemProperty("caption").setValue("Two");
- select.setItemCaptionPropertyId("caption");
- select.setNullSelectionAllowed(false);
- select.setImmediate(true);
- select.addValueChangeListener(new Property.ValueChangeListener() {
- @Override
- public void valueChange(ValueChangeEvent event) {
- log.log("Item " + select.getValue() + " selected");
-
- }
- });
+ final ComboBox<String> select = new ComboBox<>("ComboBox");
+ select.setItemCaptionProvider(
+ item -> item.startsWith("one") ? "One" : "Two");
+ select.setItems("one-1", "one-2", "two");
+ select.setEmptySelectionAllowed(false);
+ select.addValueChangeListener(
+ event -> log.log("Item " + select.getValue() + " selected"));
addComponent(log);
addComponent(select);
@Override
protected String getTestDescription() {
return "Keyboard selecting of a value is broken in combobox if two "
- + "items have the same caption. The first item's id is \"One-1\" "
- + "while the second one is \"One-2\". Selecting with mouse works "
+ + "items have the same caption. The first item's id is \"one-1\" "
+ + "while the second one is \"one-2\". Selecting with mouse works "
+ "as expected but selecting with keyboard always returns the "
- + "object \"One-1\".";
+ + "object \"one-1\".";
}
@Override
package com.vaadin.tests.components.combobox;
import com.vaadin.event.ShortcutAction.KeyCode;
+import com.vaadin.server.data.DataSource;
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.VerticalLayout;
import com.vaadin.ui.Window;
-import com.vaadin.v7.ui.ComboBox;
public class ComboBoxInPopup extends TestBase {
}
private Component createComboBox() {
- ComboBox cb = new ComboBox("A combo box");
-
- cb.addItem("Yes");
- cb.addItem("No");
- cb.addItem("Maybe");
- return cb;
+ return new ComboBox<String>("A combo box",
+ DataSource.create("Yes", "No", "Maybe"));
}
@Override
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.Button;
-import com.vaadin.ui.Button.ClickEvent;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
public class ComboBoxInputPrompt extends AbstractTestUI {
@Override
protected void setup(VaadinRequest request) {
- final ComboBox cb1 = new ComboBox("Normal");
- cb1.setInputPrompt("Normal input prompt");
+ final ComboBox<String> cb1 = new ComboBox<String>("Normal");
+ cb1.setPlaceholder("Normal input prompt");
- final ComboBox cb2 = new ComboBox("Disabled");
+ final ComboBox<String> cb2 = new ComboBox<String>("Disabled");
cb2.setEnabled(false);
- cb2.setInputPrompt("Disabled input prompt");
+ cb2.setPlaceholder("Disabled input prompt");
- final ComboBox cb3 = new ComboBox("Read-only");
+ final ComboBox<String> cb3 = new ComboBox<String>("Read-only");
cb3.setReadOnly(true);
- cb3.setInputPrompt("Read-only input prompt");
+ cb3.setPlaceholder("Read-only input prompt");
- Button enableButton = new Button("Toggle enabled",
- new Button.ClickListener() {
-
- @Override
- public void buttonClick(ClickEvent event) {
- cb2.setEnabled(!cb2.isEnabled());
- cb3.setReadOnly(!cb3.isReadOnly());
- }
- });
+ Button enableButton = new Button("Toggle enabled", event -> {
+ cb2.setEnabled(!cb2.isEnabled());
+ cb3.setReadOnly(!cb3.isReadOnly());
+ });
addComponents(cb1, cb2, cb3, enableButton);
}
package com.vaadin.tests.components.combobox;
+import com.vaadin.server.data.DataSource;
import com.vaadin.tests.components.TestBase;
import com.vaadin.tests.util.Log;
import com.vaadin.ui.Button;
-import com.vaadin.ui.Button.ClickEvent;
-import com.vaadin.v7.data.Property.ValueChangeEvent;
-import com.vaadin.v7.data.Property.ValueChangeListener;
-import com.vaadin.v7.data.util.IndexedContainer;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
public class ComboBoxInvalidNullSelection extends TestBase {
private static final Object CAPTION = "C";
- private IndexedContainer ds1;
- private IndexedContainer ds2;
- private ComboBox combo;
+ private DataSource<String> ds1;
+ private DataSource<String> ds2;
+ private ComboBox<String> combo;
private Log log = new Log(5);
@Override
createDataSources();
Button b = new Button("Swap data source");
- b.addListener(new Button.ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- if (combo.getContainerDataSource() == ds1) {
- combo.setContainerDataSource(ds2);
- } else {
- combo.setContainerDataSource(ds1);
- }
- combo.setValue("Item 3");
+ b.addClickListener(event -> {
+ if (combo.getDataSource() == ds1) {
+ combo.setDataSource(ds2);
+ } else {
+ combo.setDataSource(ds1);
}
+ combo.setValue("Item 3");
});
- combo = new ComboBox();
- combo.setImmediate(true);
- combo.setContainerDataSource(ds1);
- combo.addListener(new ValueChangeListener() {
-
- @Override
- public void valueChange(ValueChangeEvent event) {
- log.log("Value is now: " + combo.getValue());
- }
- });
+ combo = new ComboBox<>();
+ combo.setDataSource(ds1);
+ combo.addValueChangeListener(
+ event -> log.log("Value is now: " + combo.getValue()));
addComponent(log);
addComponent(b);
addComponent(combo);
}
private void createDataSources() {
- ds1 = new IndexedContainer();
- ds1.addContainerProperty(CAPTION, String.class, "");
- ds1.addItem("Item 1");
- ds1.addItem("Item 2");
- ds1.addItem("Item 3");
- ds1.addItem("Item 4");
+ ds1 = DataSource.create("Item 1", "Item 2", "Item 3", "Item 4");
- ds2 = new IndexedContainer();
- ds2.addContainerProperty(CAPTION, String.class, "");
- ds2.addItem("Item 3");
+ ds2 = DataSource.create("Item 3");
}
package com.vaadin.tests.components.combobox;
-import com.vaadin.server.Resource;
import com.vaadin.server.ThemeResource;
import com.vaadin.tests.components.TestBase;
-import com.vaadin.v7.data.Item;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
public class ComboBoxItemIcon extends TestBase {
@Override
protected void setup() {
{
- ComboBox cb = new ComboBox();
- cb.addContainerProperty("icon", Resource.class, null);
- cb.setItemIconPropertyId("icon");
-
- Item item = cb.addItem("FI");
- item.getItemProperty("icon").setValue(
- new ThemeResource("../tests-tickets/icons/fi.gif"));
- item = cb.addItem("SE");
- item.getItemProperty("icon").setValue(
- new ThemeResource("../tests-tickets/icons/se.gif"));
+ ComboBox<String> cb = new ComboBox<>();
+ cb.setItems("FI", "SE");
+ cb.setItemIconProvider(item -> new ThemeResource(
+ "../tests-tickets/icons/" + item.toLowerCase() + ".gif"));
addComponent(cb);
}
{
- ComboBox cb = new ComboBox();
- cb.addContainerProperty("icon", Resource.class, null);
- cb.setItemIconPropertyId("icon");
-
- Item item = cb.addItem("Finland");
- item.getItemProperty("icon").setValue(
- new ThemeResource("../tests-tickets/icons/fi.gif"));
- item = cb.addItem("Australia");
- item.getItemProperty("icon").setValue(
- new ThemeResource("../tests-tickets/icons/au.gif"));
- item = cb.addItem("Hungary");
- item.getItemProperty("icon").setValue(
- new ThemeResource("../tests-tickets/icons/hu.gif"));
+ ComboBox<String> cb = new ComboBox<>();
+ cb.setItems("Finland", "Australia", "Hungary");
+ cb.setItemIconProvider(
+ item -> new ThemeResource("../tests-tickets/icons/"
+ + item.substring(0, 2).toLowerCase() + ".gif"));
cb.setValue("Hungary");
addComponent(cb);
import java.util.Date;
-import com.vaadin.server.Resource;
import com.vaadin.server.ThemeResource;
+import com.vaadin.server.data.DataSource;
import com.vaadin.tests.components.TestBase;
-import com.vaadin.v7.data.Item;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
public class ComboBoxLargeIcons extends TestBase {
@Override
protected void setup() {
- ComboBox cb = new ComboBox();
- cb.addContainerProperty("icon", Resource.class, null);
- cb.setItemIconPropertyId("icon");
+ ComboBox<String> cb = new ComboBox<String>(null,
+ DataSource.create("folder-add", "folder-delete", "arrow-down",
+ "arrow-left", "arrow-right", "arrow-up", "document-add",
+ "document-delete", "document-doc", "document-edit",
+ "document-image", "document-pdf", "document-ppt",
+ "document-txt", "document-web", "document"));
getLayout().addComponent(cb);
- cb.setNullSelectionAllowed(false);
- String[] icons = new String[] { "folder-add", "folder-delete",
- "arrow-down", "arrow-left", "arrow-right", "arrow-up",
- "document-add", "document-delete", "document-doc",
- "document-edit", "document-image", "document-pdf",
- "document-ppt", "document-txt", "document-web", "document" };
- for (String icon : icons) {
- Item item = cb.addItem(icon);
- item.getItemProperty("icon")
- .setValue(new ThemeResource("../runo/icons/32/" + icon
- + ".png?" + new Date().getTime()));
- }
-
+ // FIXME cb.setNullSelectionAllowed(false);
+ cb.setItemIconProvider(icon -> new ThemeResource(
+ "../runo/icons/32/" + icon + ".png?" + new Date().getTime()));
}
}
*/
package com.vaadin.tests.components.combobox;
+import java.util.ArrayList;
+import java.util.List;
+
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Label;
-import com.vaadin.v7.data.Property;
-import com.vaadin.v7.ui.ComboBox;
public class ComboBoxMouseSelectEnter extends AbstractTestUI {
- protected ComboBox comboBox;
+ protected ComboBox<String> comboBox;
@Override
protected void setup(VaadinRequest request) {
- comboBox = new ComboBox();
+ List<String> items = new ArrayList<>();
+ for (int i = 0; i < 10; i++) {
+ items.add("a" + i);
+ }
+ comboBox = new ComboBox<>(null, items);
final Label label = new Label();
label.setId("value");
comboBox.setTextInputAllowed(true);
- comboBox.setNullSelectionAllowed(true);
- comboBox.setNullSelectionItemId(null);
-
- for (int i = 0; i < 10; i++) {
- comboBox.addItem("a" + i);
- }
+ comboBox.setEmptySelectionAllowed(true);
- comboBox.addValueChangeListener(new Property.ValueChangeListener() {
- @Override
- public void valueChange(Property.ValueChangeEvent event) {
- Object value = event.getProperty().getValue();
- if (value != null) {
- label.setValue(value.toString());
- } else {
- label.setValue("null");
- }
- }
- });
+ comboBox.addValueChangeListener(
+ event -> label.setValue(String.valueOf(event.getValue())));
addComponents(comboBox);
addComponent(label);
*/
package com.vaadin.tests.components.combobox;
+import java.util.ArrayList;
+import java.util.List;
+
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
/**
* Tests mousewheel handling in ComboBox.
}
private ComboBox createComboBox(String caption) {
- ComboBox cb = new ComboBox(caption);
- cb.setId(caption);
- cb.setImmediate(true);
+ List<String> data = new ArrayList<>();
for (int i = 1; i < 100; i++) {
- cb.addItem("Item " + i);
+ data.add("Item " + i);
}
+ ComboBox<String> cb = new ComboBox<>(caption, data);
+ cb.setId(caption);
return cb;
}
package com.vaadin.tests.components.combobox;
+import java.util.ArrayList;
+import java.util.List;
+
import com.vaadin.tests.components.TestBase;
-import com.vaadin.v7.shared.ui.combobox.FilteringMode;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
public class ComboBoxNavigation extends TestBase {
@Override
protected void setup() {
- ComboBox cb = new ComboBox();
+ List<String> items = new ArrayList<>();
for (int i = 1; i < 100; i++) {
- cb.addItem("Item " + i);
+ items.add("Item " + i);
}
+ ComboBox cb = new ComboBox(null, items);
- cb.setFilteringMode(FilteringMode.CONTAINS);
addComponent(cb);
}
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUIWithLog;
import com.vaadin.ui.Button;
-import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.VerticalLayout;
-import com.vaadin.v7.data.Property;
-import com.vaadin.v7.ui.ComboBox;
/**
* The Application's "main" class
final FormLayout formLayout = new FormLayout();
- final ComboBox combo = new ComboBox("Item:");
- combo.addItem("Item 1");
- combo.addItem("Item 2");
- combo.addItem("Item 3");
- combo.addItem("Item 4");
- combo.addValueChangeListener(new MyValueChangeListener());
+ final ComboBox<String> combo = new ComboBox<>("Item:");
+ combo.setItems("Item 1", "Item 2", "Item 3", "Item 4");
+ combo.addValueChangeListener(
+ event -> log.log("you made a selection change"));
combo.setImmediate(true);
Button btn1 = new Button("Click me");
- btn1.addClickListener(new Button.ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- log.log("you clicked me");
- }
- });
+ btn1.addClickListener(event -> log.log("you clicked me"));
formLayout.addComponent(combo);
formLayout.addComponent(btn1);
layout.addComponent(formLayout);
Button btn = new Button("Enable/Disable combobox",
- new Button.ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- combo.setEnabled(!combo.isEnabled());
- }
- });
+ event -> combo.setEnabled(!combo.isEnabled()));
layout.addComponent(btn);
- btn = new Button("Enable/Disable parent", new Button.ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- formLayout.setEnabled(!formLayout.isEnabled());
- }
- });
+ btn = new Button("Enable/Disable parent",
+ event -> formLayout.setEnabled(!formLayout.isEnabled()));
layout.addComponent(btn);
}
- private class MyValueChangeListener
- implements Property.ValueChangeListener {
- @Override
- public void valueChange(Property.ValueChangeEvent event) {
- log.log("you made a selection change");
- }
- }
-
@Override
protected String getTestDescription() {
return "Test for ensuring that disabling a parent properly disables the combobox";
*/
package com.vaadin.tests.components.combobox;
+import java.util.ArrayList;
+import java.util.List;
+
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Label;
-import com.vaadin.v7.ui.ComboBox;
public class ComboBoxPopupWhenBodyScrolls extends AbstractTestUI {
.add("body.v-generated-body { overflow: auto;height:auto;}");
getPage().getStyles().add(
"body.v-generated-body .v-ui.v-scrollable{ overflow: visible;height:auto !important;}");
- ComboBox cb = new ComboBox();
+ List<String> data = new ArrayList<>();
for (int i = 0; i < 10; i++) {
- cb.addItem("Item " + i);
+ data.add("Item " + i);
}
+ ComboBox<String> cb = new ComboBox<>(null, data);
Label spacer = new Label("foo");
spacer.setHeight("2000px");
package com.vaadin.tests.components.combobox;
import java.util.ArrayList;
+import java.util.List;
import com.vaadin.tests.components.ComponentTestCase;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Notification;
-import com.vaadin.v7.data.Property.ValueChangeEvent;
-import com.vaadin.v7.data.Property.ValueChangeListener;
-import com.vaadin.v7.ui.ComboBox;
public class ComboBoxScrollingToPageDisabled
extends ComponentTestCase<ComboBox> {
@Override
protected void initializeComponents() {
- ComboBox s = createSelect(null);
+ ComboBox<String> s = createSelect(null);
s.setScrollToSelectedItem(false);
populate(s, 100);
- Object selection = new ArrayList<Object>(s.getItemIds()).get(50);
- s.setValue(selection);
+ s.setValue("Item 50");
addTestComponent(s);
}
private void populate(ComboBox s, int nr) {
+ List<String> items = new ArrayList<>();
for (int i = 0; i < nr; i++) {
- addItem(s, "Item " + i);
+ items.add("Item " + i);
}
+ s.setItems(items);
}
- @SuppressWarnings("unchecked")
- private void addItem(ComboBox s, String string) {
- Object id = s.addItem();
- s.getItem(id).getItemProperty(CAPTION).setValue(string);
-
- }
-
- private ComboBox createSelect(String caption) {
- final ComboBox cb = new ComboBox();
- cb.setImmediate(true);
- cb.addContainerProperty(CAPTION, String.class, "");
- cb.setItemCaptionPropertyId(CAPTION);
+ private ComboBox<String> createSelect(String caption) {
+ final ComboBox<String> cb = new ComboBox<>();
cb.setCaption(caption);
- cb.addValueChangeListener(new ValueChangeListener() {
-
- @Override
- public void valueChange(ValueChangeEvent event) {
- Notification.show("Value now:" + cb.getValue() + " "
- + cb.getItemCaption(cb.getValue()));
-
- }
- });
+ cb.addValueChangeListener(event -> Notification
+ .show("Value now:" + cb.getValue() + " " + cb.getValue()));
return cb;
}
*/
package com.vaadin.tests.components.combobox;
+import java.util.ArrayList;
+import java.util.List;
+
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.AbstractLayout;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.VerticalLayout;
-import com.vaadin.v7.ui.ComboBox;
/**
* Test UI verifying navigating in combobox via arrow keys.
}
private void addComboBox(AbstractLayout layout) {
- ComboBox box = new ComboBox();
+ ComboBox<String> box = new ComboBox<>();
+ List<String> items = new ArrayList<>();
for (int i = 0; i < 100; i++) {
- box.addItem("item " + i);
+ items.add("item " + i);
}
+ box.setItems(items);
box.setPageLength(10);
- box.setNullSelectionAllowed(false);
+ box.setEmptySelectionAllowed(false);
layout.addComponent(box);
}
}
package com.vaadin.tests.components.combobox;
+import java.util.ArrayList;
+import java.util.List;
+
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Label;
-import com.vaadin.v7.data.Property;
-import com.vaadin.v7.ui.ComboBox;
-import com.vaadin.v7.ui.TextField;
+import com.vaadin.ui.TextField;
public class ComboBoxSelecting extends AbstractTestUI {
- protected ComboBox comboBox;
+ protected ComboBox<String> comboBox;
+ protected List<String> items = new ArrayList<>();
@Override
protected void setup(VaadinRequest request) {
- comboBox = new ComboBox();
- final Label label = new Label();
- label.setId("value");
-
- comboBox.setTextInputAllowed(true);
- comboBox.setNullSelectionAllowed(true);
- comboBox.setNullSelectionItemId(null);
-
for (char c = 'a'; c <= 'z'; c++) {
for (int i = 0; i < 100; i++) {
- comboBox.addItem("" + c + i);
+ items.add("" + c + i);
}
}
+ comboBox = new ComboBox<>(null, items);
+ final Label label = new Label();
+ label.setId("value");
- comboBox.addValueChangeListener(new Property.ValueChangeListener() {
- @Override
- public void valueChange(Property.ValueChangeEvent event) {
- Object value = event.getProperty().getValue();
- if (value != null) {
- label.setValue(value.toString());
- } else {
- label.setValue("null");
- }
-
+ comboBox.setTextInputAllowed(true);
+ comboBox.setEmptySelectionAllowed(true);
+
+ comboBox.addValueChangeListener(event -> {
+ String value = event.getValue();
+ if (value != null) {
+ label.setValue(value);
+ } else {
+ label.setValue("null");
}
});
package com.vaadin.tests.components.combobox;
import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.data.Query;
import com.vaadin.ui.Label;
-import com.vaadin.v7.data.Property;
public class ComboBoxSelectingWithNewItemsAllowed extends ComboBoxSelecting {
@Override
protected void setup(VaadinRequest request) {
super.setup(request);
- comboBox.setNewItemsAllowed(true);
-
- final Label label = new Label(
- String.valueOf(comboBox.getItemIds().size()));
+ final Label label = new Label(String.valueOf(items.size()));
label.setCaption("Item count:");
label.setId("count");
- comboBox.addValueChangeListener(new Property.ValueChangeListener() {
- @Override
- public void valueChange(Property.ValueChangeEvent event) {
- label.setValue(String.valueOf(comboBox.getItemIds().size()));
- }
+ comboBox.setNewItemHandler(text -> {
+ items.add(text);
+ comboBox.setItems(items);
+ comboBox.select(text);
+ label.setValue(String.valueOf(items.size()));
});
+
+ comboBox.addValueChangeListener(event -> label.setValue(
+ String.valueOf(comboBox.getDataSource().size(new Query()))));
addComponent(label);
}
import com.vaadin.event.FieldEvents;
import com.vaadin.event.FieldEvents.FocusEvent;
import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
-import com.vaadin.v7.ui.ComboBox;
public class ComboBoxSuggestionOnDetach extends TestBase {
layout.setSizeUndefined();
popup.setContent(layout);
- ComboBox comboBox = new ComboBox("Combo box",
+ ComboBox<String> comboBox = new ComboBox<>("Combo box",
Arrays.asList("Option 1", "Option 2", "Option 3"));
comboBox.addFocusListener(new FieldEvents.FocusListener() {
@Override
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
-import com.vaadin.v7.shared.ui.combobox.FilteringMode;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
public class ComboBoxSuggestionPageLength extends AbstractTestUI {
@Override
protected void setup(VaadinRequest request) {
- ComboBox cb = new ComboBox("Page length 0", items);
+ ComboBox<String> cb = new ComboBox<>("Page length 0", items);
cb.setPageLength(0);
- cb.setFilteringMode(FilteringMode.CONTAINS);
addComponent(cb);
- cb = new ComboBox("Page length 2", items);
+ cb = new ComboBox<>("Page length 2", items);
cb.setPageLength(2);
- cb.setFilteringMode(FilteringMode.CONTAINS);
addComponent(cb);
}
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
public class ComboBoxSuggestionPopupClose extends AbstractTestUI {
@Override
protected void setup(VaadinRequest request) {
- final ComboBox select = new ComboBox("ComboBox");
- select.addItem("one");
- select.addItem("two");
- select.addItem("three");
+ final ComboBox<String> select = new ComboBox<>("ComboBox");
+ select.setItems("one", "two", "three");
addComponent(select);
}
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
public class ComboBoxSuggestionPopupWidth extends AbstractTestUI {
@Override
protected void setup(VaadinRequest request) {
- ComboBox cb = new ComboBox(
+ ComboBox<String> cb = new ComboBox<>(
"200px wide ComboBox with 100% wide suggestion popup", items);
cb.setPopupWidth("100%");
cb.setWidth("200px");
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
public class ComboBoxSuggestionPopupWidthLegacy extends AbstractTestUI {
@Override
protected void setup(VaadinRequest request) {
- ComboBox legacy = new ComboBox(
+ ComboBox<String> legacy = new ComboBox<>(
"200px wide ComboBox with legacy mode suggestion popup setPopupWidth(null)",
items);
legacy.addStyleName("legacy");
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
public class ComboBoxSuggestionPopupWidthPercentage extends AbstractTestUI {
@Override
protected void setup(VaadinRequest request) {
- ComboBox percentage = new ComboBox(
+ ComboBox<String> percentage = new ComboBox<>(
"200px wide ComboBox with 200% wide suggestion popup", items);
percentage.addStyleName("percentage");
percentage.setWidth("200px");
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
public class ComboBoxSuggestionPopupWidthPixels extends AbstractTestUI {
@Override
protected void setup(VaadinRequest request) {
- ComboBox pixels = new ComboBox(
+ ComboBox<String> pixels = new ComboBox<>(
"200px wide ComboBox with 300px wide suggestion popup", items);
pixels.addStyleName("pixels");
pixels.setWidth("200px");
package com.vaadin.tests.components.combobox;
-import com.vaadin.server.Resource;
+import java.util.ArrayList;
+import java.util.List;
+
import com.vaadin.server.ThemeResource;
import com.vaadin.tests.components.TestBase;
-import com.vaadin.v7.data.Item;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
public class ComboBoxUndefinedWidthAndIcon extends TestBase {
@Override
protected void setup() {
- ComboBox cb = new ComboBox();
- cb.addContainerProperty("caption", String.class, null);
- cb.addContainerProperty("icon", Resource.class, null);
+ List<String> data = new ArrayList<>();
for (int i = 1; i < 200 + 1; i++) {
- Item item = cb.addItem(i);
- item.getItemProperty("caption").setValue("Item " + i);
- item.getItemProperty("icon")
- .setValue(new ThemeResource("../runo/icons/16/users.png"));
+ data.add("Item " + i);
}
- cb.setItemIconPropertyId("icon");
- cb.setItemCaptionPropertyId("caption");
+ ComboBox<String> cb = new ComboBox<>(null, data);
+ cb.setItemIconProvider(
+ item -> new ThemeResource("../runo/icons/16/users.png"));
addComponent(cb);
}
/*
* Copyright 2000-2014 Vaadin Ltd.
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
*/
package com.vaadin.tests.components.combobox;
+import java.util.ArrayList;
+import java.util.List;
+
import com.vaadin.annotations.Theme;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
@Theme("valo")
public class ComboBoxValoDoubleClick extends AbstractTestUI {
// bug. Manually a double click is just about the right timing.
@Override
protected void setup(VaadinRequest request) {
- ComboBox cb = new ComboBox("Double-click Me");
+ ComboBox<String> cb = new ComboBox<>("Double-click Me");
+ List<String> items = new ArrayList<String>();
for (int i = 0; i < 100; i++) {
- cb.addItem("Item-" + i);
+ items.add("Item-" + i);
}
+ cb.setItems(items);
addComponent(cb);
}
package com.vaadin.tests.components.combobox;
+import java.util.ArrayList;
+import java.util.List;
+
import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Label;
-import com.vaadin.v7.data.Property.ValueChangeEvent;
-import com.vaadin.v7.ui.ComboBox;
public class ComboBoxValueUpdate extends TestBase {
@Override
protected void setup() {
- ComboBox select = new ComboBox("");
- select.setImmediate(true);
+ List<String> items = new ArrayList<>();
for (int i = 0; i < 100; i++) {
- select.addItem("item " + i);
+ items.add("item " + i);
}
+ ComboBox<String> select = new ComboBox<>("", items);
final Label value = new Label();
- select.addListener(new ComboBox.ValueChangeListener() {
-
- @Override
- public void valueChange(ValueChangeEvent event) {
- System.err
- .println("Selected " + event.getProperty().getValue());
- value.setValue("Selected " + event.getProperty().getValue());
-
- }
+ select.addValueChangeListener(event -> {
+ System.err.println("Selected " + event.getValue());
+ value.setValue("Selected " + event.getValue());
});
getLayout().addComponent(select);
import java.util.ArrayList;
import java.util.List;
-import com.vaadin.event.FieldEvents;
-import com.vaadin.event.FieldEvents.BlurEvent;
-import com.vaadin.event.FieldEvents.FocusEvent;
import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.ui.TextField;
import com.vaadin.v7.data.util.ObjectProperty;
import com.vaadin.v7.shared.ui.label.ContentMode;
-import com.vaadin.v7.ui.ComboBox;
import com.vaadin.v7.ui.Label;
-import com.vaadin.v7.ui.TextField;
public class ComboFocusBlurEvents extends TestBase {
list.add("Item " + i);
}
- ComboBox cb = new ComboBox("Combobox", list);
- cb.setImmediate(true);
- cb.setInputPrompt("Enter text");
+ ComboBox<String> cb = new ComboBox<>("Combobox", list);
+ cb.setPlaceholder("Enter text");
cb.setDescription("Some Combobox");
addComponent(cb);
final ObjectProperty<String> log = new ObjectProperty<>("");
- cb.addFocusListener(new FieldEvents.FocusListener() {
- @Override
- public void focus(FocusEvent event) {
- log.setValue(log.getValue().toString() + "<br>" + counter
- + ": Focus event!");
- counter++;
- }
+ cb.addFocusListener(event -> {
+ log.setValue(log.getValue().toString() + "<br>" + counter
+ + ": Focus event!");
+ counter++;
});
- cb.addBlurListener(new FieldEvents.BlurListener() {
- @Override
- public void blur(BlurEvent event) {
- log.setValue(log.getValue().toString() + "<br>" + counter
- + ": Blur event!");
- counter++;
- }
+ cb.addBlurListener(event -> {
+ log.setValue(log.getValue().toString() + "<br>" + counter
+ + ": Blur event!");
+ counter++;
});
TextField field = new TextField("Some textfield");
- field.setImmediate(true);
addComponent(field);
Label output = new Label(log);
package com.vaadin.tests.components.combobox;
+import java.util.ArrayList;
+import java.util.List;
+
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Label;
-import com.vaadin.v7.data.Property.ValueChangeEvent;
-import com.vaadin.v7.data.Property.ValueChangeListener;
-import com.vaadin.v7.ui.ComboBox;
@SuppressWarnings("serial")
public class ComboSelectedValueBeyondTheFirstDropdownPage
@Override
protected void setup(VaadinRequest request) {
Label value = getLabel();
- ComboBox combobox = getComboBox(value);
+ ComboBox<String> combobox = getComboBox(value);
addComponent(combobox);
addComponent(value);
return value;
}
- private ComboBox getComboBox(final Label value) {
- final ComboBox combobox = new ComboBox("MyCaption");
+ private ComboBox<String> getComboBox(final Label value) {
+ final ComboBox<String> combobox = new ComboBox<>("MyCaption");
combobox.setDescription(
"ComboBox with more than 10 elements in it's dropdown list.");
- combobox.setImmediate(true);
-
+ List<String> items = new ArrayList<>();
for (int i = 1; i <= ITEM_COUNT; i++) {
- combobox.addItem(String.format(ITEM_NAME_TEMPLATE, i));
+ items.add(String.format(ITEM_NAME_TEMPLATE, i));
}
+ combobox.setItems(items);
- combobox.addValueChangeListener(new ValueChangeListener() {
- @Override
- public void valueChange(ValueChangeEvent event) {
- value.setValue(String.valueOf(event.getProperty().getValue()));
- }
- });
+ combobox.addValueChangeListener(
+ event -> value.setValue(String.valueOf(event.getValue())));
return combobox;
}
import java.util.Arrays;
import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Component;
import com.vaadin.ui.PopupView;
-import com.vaadin.v7.ui.ComboBox;
import com.vaadin.v7.ui.TextArea;
public class ComboboxInPopupViewWithItems extends TestBase {
class PopupContent implements PopupView.Content {
- private final ComboBox cb = new ComboBox(null,
+ private final ComboBox<String> cb = new ComboBox<>(null,
Arrays.asList("Item 1", "Item 2", "Item 3"));
@Override
*/
package com.vaadin.tests.components.combobox;
-import java.util.ArrayList;
-
import com.vaadin.server.Page;
import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.data.DataSource;
import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.MenuBar;
import com.vaadin.ui.MenuBar.MenuItem;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Notification.Type;
-import com.vaadin.v7.ui.ComboBox;
/**
* Test UI for combobox popup which should be closed on any click outside it.
protected void setup(VaadinRequest request) {
HorizontalLayout layout = new HorizontalLayout();
layout.setSpacing(true);
- ArrayList<String> options = new ArrayList<>();
- options.add("1");
- options.add("2");
- options.add("3");
- ComboBox combo = new ComboBox(null, options);
+ ComboBox<String> combo = new ComboBox<>(null,
+ DataSource.create("1", "2", "3"));
layout.addComponent(combo);
MenuBar menubar = getMenubar();
package com.vaadin.tests.components.combobox;
+import java.util.ArrayList;
+import java.util.List;
+
import com.vaadin.annotations.Theme;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.HorizontalLayout;
-import com.vaadin.v7.ui.ComboBox;
@Theme("valo")
public class ComboboxPopupScrolling extends AbstractTestUIWithLog {
protected void setup(VaadinRequest request) {
ComboBox combobox = new ComboBox("100px wide combobox");
combobox.setWidth("100px");
- combobox.addItem("AMERICAN SAMOA");
- combobox.addItem("ANTIGUA AND BARBUDA");
+ combobox.setItems("AMERICAN SAMOA", "ANTIGUA AND BARBUDA");
ComboBox combobox2 = new ComboBox("250px wide combobox");
combobox2.setWidth("250px");
- combobox2.addItem("AMERICAN SAMOA");
- combobox2.addItem("ANTIGUA AND BARBUDA");
+ combobox2.setItems("AMERICAN SAMOA", "ANTIGUA AND BARBUDA");
ComboBox combobox3 = new ComboBox("Undefined wide combobox");
combobox3.setWidth(null);
- combobox3.addItem("AMERICAN SAMOA");
- combobox3.addItem("ANTIGUA AND BARBUDA");
+ combobox3.setItems("AMERICAN SAMOA", "ANTIGUA AND BARBUDA");
ComboBox combobox4 = new ComboBox("Another 100px wide combobox");
combobox4.setWidth("100px");
+ List<String> items = new ArrayList<>();
for (int i = 0; i < 10; i++) {
- combobox4.addItem("AMERICAN SAMOA " + i);
- combobox4.addItem("ANTIGUA AND BARBUDA " + i);
+ items.add("AMERICAN SAMOA " + i);
+ items.add("ANTIGUA AND BARBUDA " + i);
}
+ combobox4.setItems(items);
HorizontalLayout hl = new HorizontalLayout(combobox, combobox2,
combobox3, combobox4);
package com.vaadin.tests.components.combobox;
+import com.vaadin.server.data.DataSource;
import com.vaadin.tests.components.TestBase;
import com.vaadin.ui.Button;
-import com.vaadin.ui.Button.ClickEvent;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
public class ComboboxPrimaryStyleNames extends TestBase {
@Override
protected void setup() {
- final ComboBox box = new ComboBox();
+ final ComboBox<String> box = new ComboBox(null,
+ DataSource.create("Value 1", "Value 2", "Value 3", "Value 4"));
box.setImmediate(true);
- box.addContainerProperty("caption", String.class, "");
- box.setItemCaptionPropertyId("caption");
box.setPrimaryStyleName("my-combobox");
- addItem(box, "Value 1");
- addItem(box, "Value 2");
- addItem(box, "Value 3");
- addItem(box, "Value 4");
-
addComponent(box);
- addComponent(
- new Button("Set primary style", new Button.ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- box.setPrimaryStyleName("my-second-combobox");
- }
- }));
+ addComponent(new Button("Set primary style",
+ event -> box.setPrimaryStyleName("my-second-combobox")));
}
return 9901;
}
- private void addItem(ComboBox s, String string) {
- Object id = s.addItem();
- s.getItem(id).getItemProperty("caption").setValue(string);
- }
-
}
package com.vaadin.tests.components.combobox;
import com.vaadin.server.VaadinRequest;
+import com.vaadin.server.data.DataSource;
import com.vaadin.tests.components.AbstractTestUIWithLog;
import com.vaadin.ui.Button;
-import com.vaadin.ui.Button.ClickEvent;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
/**
* Test UI for adding a stylename to a combobox with an undefined width.
@Override
protected void setup(VaadinRequest request) {
- final ComboBox cbFoo = new ComboBox();
- cbFoo.setImmediate(true);
+ final ComboBox<String> cbFoo = new ComboBox<>(null, DataSource.create(
+ "A really long string that causes an inline width to be set"));
cbFoo.setSizeUndefined();
- cbFoo.addItem(
- "A really long string that causes an inline width to be set");
Button btn = new Button("Click to break CB",
- new Button.ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- cbFoo.addStyleName("foofoo");
-
- }
- });
+ event -> cbFoo.addStyleName("foofoo"));
addComponent(cbFoo);
addComponent(btn);
package com.vaadin.tests.components.combobox;
+import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import com.vaadin.server.ThemeResource;
import com.vaadin.tests.components.ComponentTestCase;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Component;
-import com.vaadin.v7.ui.ComboBox;
public class Comboboxes extends ComponentTestCase<ComboBox> {
- private static final Object CAPTION = "caption";
+ private static class StringBean {
+ private String value;
+
+ public StringBean(String value) {
+ this.value = value;
+ }
+
+ public String getValue() {
+ return value;
+ }
+ }
@Override
protected Class<ComboBox> getTestClass() {
@Override
protected void initializeComponents() {
- ComboBox s;
-
- s = createSelect(null);
- s.setWidth(null);
- addTestComponent(s);
-
- s = createSelect("Undefined wide, empty select");
- s.setWidth(null);
- addTestComponent(s);
-
- s = createSelect("Undefined wide select with 5 items");
- s.setWidth(null);
- addItem(s, "The first item");
- addItem(s, "The second item");
- addItem(s, "The third item");
- addItem(s, "The fourth item");
- addItem(s, "The fifth item");
- addTestComponent(s);
-
- s = createSelect("Undefined wide select with 50 items");
- s.setWidth(null);
- populate(s, 50);
- addTestComponent(s);
-
- s = createSelect(null);
- s.setWidth("100px");
- addTestComponent(s);
-
- s = createSelect("100px wide, empty select");
- s.setWidth("100px");
- addTestComponent(s);
-
- s = createSelect("150px wide select with 5 items");
- s.setWidth("150px");
- addItem(s, "The first item");
- addItem(s, "The second item");
- addItem(s, "The third item");
- addItem(s, "The fourth item");
- addItem(s, "The fifth item");
- addTestComponent(s);
-
- s = createSelect("200px wide select with 50 items");
- s.setWidth("200px");
- populate(s, 50);
- addTestComponent(s);
-
- s = new PageLength0ComboBox();
- s.setImmediate(true);
- s.addContainerProperty(CAPTION, String.class, "");
- s.setItemCaptionPropertyId(CAPTION);
- s.setCaption("Pagelength 0");
- populate(s, 15);
- addTestComponent(s);
+ ComboBox<String> s1 = createSelect(null);
+ s1.setWidth(null);
+ addTestComponent(s1);
+
+ ComboBox<String> s2 = createSelect("Undefined wide, empty select");
+ s2.setWidth(null);
+ addTestComponent(s2);
+
+ ComboBox<String> s3 = createSelect(
+ "Undefined wide select with 5 items");
+ s3.setWidth(null);
+ s3.setItems("The first item", "The second item", "The third item",
+ "The fourth item", "The fifth item");
+ addTestComponent(s3);
+
+ ComboBox<StringBean> s4 = new ComboBox<>(
+ "Undefined wide select with 50 items");
+ s4.setWidth(null);
+ populate(s4, 50);
+ s4.setItemCaptionProvider(StringBean::getValue);
+ s4.setScrollToSelectedItem(true);
+ addTestComponent(s4);
+
+ ComboBox<String> s5 = createSelect(null);
+ s5.setWidth("100px");
+ addTestComponent(s5);
+
+ ComboBox<String> s6 = createSelect("100px wide, empty select");
+ s6.setWidth("100px");
+ addTestComponent(s6);
+
+ ComboBox<String> s7 = createSelect("150px wide select with 5 items");
+ s7.setWidth("150px");
+ s7.setItems("The first item", "The second item", "The third item",
+ "The fourth item", "The fifth item");
+ addTestComponent(s7);
+
+ ComboBox<StringBean> s8 = new ComboBox<>(
+ "200px wide select with 50 items");
+ s8.setWidth("200px");
+ populate(s8, 50);
+ s8.setItemCaptionProvider(StringBean::getValue);
+ addTestComponent(s8);
+
+ ComboBox<StringBean> s9 = new PageLength0ComboBox();
+ s9.setImmediate(true);
+ s9.setCaption("Pagelength 0");
+ populate(s9, 15);
+ s9.setItemCaptionProvider(StringBean::getValue);
+ addTestComponent(s9);
}
- public class PageLength0ComboBox extends ComboBox {
+ public class PageLength0ComboBox extends ComboBox<StringBean> {
public PageLength0ComboBox() {
super();
setPageLength(0);
}
}
- private void populate(ComboBox s, int nr) {
+ private void populate(ComboBox<StringBean> s, int nr) {
+ List<StringBean> beans = new ArrayList<>();
String text = " an item ";
String caption = "";
caption += i;
}
- addItem(s, caption);
+ beans.add(new StringBean(caption));
}
-
+ s.setItems(beans);
}
- private void addItem(ComboBox s, String string) {
- Object id = s.addItem();
- s.getItem(id).getItemProperty(CAPTION).setValue(string);
-
- }
-
- private ComboBox createSelect(String caption) {
- ComboBox cb = new ComboBox();
- cb.setImmediate(true);
- cb.addContainerProperty(CAPTION, String.class, "");
- cb.setItemCaptionPropertyId(CAPTION);
- cb.setCaption(caption);
-
- return cb;
+ private ComboBox<String> createSelect(String caption) {
+ return new ComboBox<>(caption);
}
@Override
actions.add(createIconSelect());
}
+ @SuppressWarnings("rawtypes")
private Component createIconSelect() {
LinkedHashMap<String, String> options = new LinkedHashMap<>();
return createSelectAction("Icon", options, "<None>",
new Command<ComboBox, String>() {
+ @SuppressWarnings("unchecked")
@Override
public void execute(ComboBox c, String value, Object data) {
- for (Object id : c.getItemIds()) {
- if (value == null) {
- c.setItemIcon(id, null);
- } else {
- c.setItemIcon(id, new ThemeResource(
- value + "?" + new Date().getTime()));
- }
+ if (value == null) {
+ c.setItemIconProvider(item -> null);
+ } else {
+ c.setItemIconProvider(item -> new ThemeResource(
+ value + "?" + new Date().getTime()));
}
}
});
+++ /dev/null
-package com.vaadin.tests.components.combobox;
-
-import com.vaadin.event.ShortcutAction.KeyCode;
-import com.vaadin.server.VaadinRequest;
-import com.vaadin.ui.Button;
-import com.vaadin.ui.Button.ClickEvent;
-import com.vaadin.ui.FormLayout;
-import com.vaadin.ui.UI;
-import com.vaadin.ui.VerticalLayout;
-import com.vaadin.ui.Window;
-import com.vaadin.v7.ui.ComboBox;
-
-/**
- * Ticket #12163: when a combo box popup is open in a subwindow, escape should
- * only close it and not the window, also on Safari 6.
- */
-public class EscapeClosesComboboxNotWindow extends UI {
- final Window window = new Window("Window");
-
- @Override
- protected void init(VaadinRequest request) {
- final VerticalLayout layout = new VerticalLayout();
- layout.setMargin(true);
- setContent(layout);
-
- Button button = new Button("Click Me");
- button.addClickListener(new Button.ClickListener() {
- @Override
- public void buttonClick(ClickEvent event) {
- final FormLayout content = new FormLayout();
- ComboBox cb = new ComboBox();
- cb.addItem("foo");
- cb.addItem("bar");
- content.addComponent(cb);
- window.setContent(content);
- window.setCloseShortcut(KeyCode.ESCAPE);
- UI.getCurrent().addWindow(window);
- }
- });
- layout.addComponent(button);
- }
-
-}
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
-import com.vaadin.v7.data.Property.ValueChangeEvent;
-import com.vaadin.v7.data.Property.ValueChangeListener;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
import com.vaadin.v7.ui.NativeSelect;
public class FilteringTurkishLocale extends AbstractTestUI {
@Override
protected void setup(VaadinRequest request) {
- final ComboBox comboBox = new ComboBox("Box",
- Arrays.asList("I without dot", "İ with dot"));
- comboBox.setNullSelectionAllowed(false);
+ final ComboBox<String> comboBox = new ComboBox<>("Box",
+ Arrays.asList("I dotless", "İ dotted"));
+ comboBox.setEmptySelectionAllowed(false);
NativeSelect localeSelect = new NativeSelect("Locale",
Arrays.asList(Locale.ENGLISH, new Locale("tr")));
- localeSelect.addValueChangeListener(new ValueChangeListener() {
- @Override
- public void valueChange(ValueChangeEvent event) {
- comboBox.setLocale((Locale) event.getProperty().getValue());
- }
- });
+ localeSelect.addValueChangeListener(event -> comboBox
+ .setLocale((Locale) event.getProperty().getValue()));
localeSelect.setValue(Locale.ENGLISH);
addComponents(localeSelect, comboBox);
package com.vaadin.tests.components.combobox;
import com.vaadin.tests.components.AbstractTestCase;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Layout;
import com.vaadin.ui.LegacyWindow;
-import com.vaadin.v7.ui.ComboBox;
@SuppressWarnings("serial")
public class GridLayoutComboBoxZoomOut extends AbstractTestCase {
// formLayout.setWidth("100%");
formLayout.setWidth("1000px");
- ComboBox countryField = new ComboBox();
- countryField.addItem("Finland");
- countryField.addItem("Sweden");
- countryField.addItem("Canada");
- countryField.addItem("USA");
+ ComboBox<String> countryField = new ComboBox<>();
+ countryField.setItems("Finland", "Sweden", "Canada", "USA");
countryField.setCaption("Country");
countryField.setWidth("100%");
formLayout.addComponent(countryField);
- ComboBox statusField = new ComboBox();
- statusField.addItem("Available");
- statusField.addItem("On vacation");
- statusField.addItem("Busy");
- statusField.addItem("Left the building");
+ ComboBox<String> statusField = new ComboBox<>();
+ statusField.setItems("Available", "On vacation", "Busy",
+ "Left the building");
statusField.setCaption("Status");
statusField.setWidth("100%");
formLayout.addComponent(statusField);
package com.vaadin.tests.components.combobox;
-import com.vaadin.server.Resource;
+import java.util.ArrayList;
+import java.util.List;
+
import com.vaadin.server.ThemeResource;
import com.vaadin.tests.components.TestBase;
-import com.vaadin.v7.data.Item;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
public class PopUpWidth extends TestBase {
"Browse this (check that width does not change)"));
}
- private ComboBox createComboBox(String caption) {
- ComboBox cb = new ComboBox(caption);
- cb.addContainerProperty("caption", String.class, null);
- cb.addContainerProperty("icon", Resource.class, null);
+ private ComboBox<Integer> createComboBox(String caption) {
+ ComboBox<Integer> cb = new ComboBox<>(caption);
+ List<Integer> items = new ArrayList<>();
for (int i = 1; i < 200 + 1; i++) {
- Item item = cb.addItem(i);
- item.getItemProperty("caption").setValue("Item " + i);
- item.getItemProperty("icon")
- .setValue(new ThemeResource("../runo/icons/16/users.png"));
+ items.add(i);
}
- cb.setItemIconPropertyId("icon");
- cb.setItemCaptionPropertyId("caption");
+ cb.setItems(items);
+ cb.setItemIconProvider(
+ item -> new ThemeResource("../runo/icons/16/users.png"));
+ cb.setItemCaptionProvider(item -> "Item " + item);
return cb;
}
import com.vaadin.tests.components.TestBase;
import com.vaadin.ui.CheckBox;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
public class WidthToggleReadOnly extends TestBase {
addComponent(createReadOnlyForComboBox(combo));
}
- private ComboBox createNewComboBoxA(String caption) {
- ComboBox combo = new ComboBox(caption);
- combo.addItem("first");
+ private ComboBox<String> createNewComboBoxA(String caption) {
+ ComboBox<String> combo = new ComboBox<>(caption);
+ combo.setItems("first");
combo.setValue("first");
addComponent(combo);
readonly.setValue(combo.isReadOnly());
readonly.addValueChangeListener(
event -> combo.setReadOnly(event.getValue()));
- readonly.setImmediate(true);
addComponent(readonly);
return readonly;
}
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.Button;
import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.FormLayout;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.TextField;
import com.vaadin.v7.ui.NativeSelect;
-import com.vaadin.v7.ui.TextField;
public class CaptionEnableDisable extends AbstractTestUI {
textField.setEnabled(false);
layout.addComponent(textField);
- final ComboBox combobox = new ComboBox("Combobox");
+ final ComboBox<String> combobox = new ComboBox<>("Combobox");
combobox.setEnabled(false);
layout.addComponent(combobox);
checkBox.setEnabled(false);
layout.addComponent(checkBox);
- layout.addComponent(new Button("Toggle components enabled",
- new Button.ClickListener() {
- @Override
- public void buttonClick(Button.ClickEvent event) {
- combobox.setEnabled(!combobox.isEnabled());
- textField.setEnabled(!textField.isEnabled());
- checkBox.setEnabled(!checkBox.isEnabled());
- nativeSelect.setEnabled(!nativeSelect.isEnabled());
- }
- }));
+ layout.addComponent(new Button("Toggle components enabled", event -> {
+ combobox.setEnabled(!combobox.isEnabled());
+ textField.setEnabled(!textField.isEnabled());
+ checkBox.setEnabled(!checkBox.isEnabled());
+ nativeSelect.setEnabled(!nativeSelect.isEnabled());
+ }));
return layout;
}
package com.vaadin.tests.components.notification;
+import java.util.LinkedHashMap;
+
import com.vaadin.server.Page;
import com.vaadin.server.VaadinRequest;
import com.vaadin.shared.ui.ValueChangeMode;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Notification;
import com.vaadin.ui.Notification.Type;
import com.vaadin.ui.NotificationConfiguration;
import com.vaadin.ui.TextField;
import com.vaadin.ui.UI;
-import com.vaadin.v7.data.Item;
-import com.vaadin.v7.ui.ComboBox;
import com.vaadin.v7.ui.NativeSelect;
import com.vaadin.v7.ui.TextArea;
private NativeSelect role;
private TextArea tf;
- private ComboBox type;
+ private ComboBox<Notification.Type> type;
@SuppressWarnings("unchecked")
@Override
tf.setImmediate(false);
tf.setRows(10);
addComponent(tf);
- type = new ComboBox();
- type.setNullSelectionAllowed(false);
- type.addContainerProperty(CAPTION, String.class, "");
-
- type.setItemCaptionPropertyId(CAPTION);
-
- Item item = type.addItem(Notification.Type.HUMANIZED_MESSAGE);
- item.getItemProperty(CAPTION).setValue("Humanized");
-
- item = type.addItem(Notification.Type.ERROR_MESSAGE);
- item.getItemProperty(CAPTION).setValue("Error");
-
- item = type.addItem(Notification.Type.WARNING_MESSAGE);
- item.getItemProperty(CAPTION).setValue("Warning");
-
- item = type.addItem(Notification.Type.TRAY_NOTIFICATION);
- item.getItemProperty(CAPTION).setValue("Tray");
-
- item = type.addItem(Notification.Type.ASSISTIVE_NOTIFICATION);
- item.getItemProperty(CAPTION).setValue("Assistive");
-
- type.setValue(type.getItemIds().iterator().next());
+ type = new ComboBox<>();
+ LinkedHashMap<Notification.Type, String> items = new LinkedHashMap<>();
+ items.put(Notification.Type.HUMANIZED_MESSAGE, "Humanized");
+ items.put(Notification.Type.ERROR_MESSAGE, "Error");
+ items.put(Notification.Type.WARNING_MESSAGE, "Warning");
+ items.put(Notification.Type.TRAY_NOTIFICATION, "Tray");
+ items.put(Notification.Type.ASSISTIVE_NOTIFICATION, "Assistive");
+
+ type.setItemCaptionProvider(item -> items.get(item));
+ type.setItems(items.keySet());
+
+ type.setValue(items.keySet().iterator().next());
addComponent(type);
Button showNotification = new Button("Show notification",
private class SettingHandler implements ClickListener {
@Override
public void buttonClick(ClickEvent event) {
- Type typeValue = (Type) type.getValue();
+ Type typeValue = type.getValue();
Notification n = new Notification(tf.getValue(), typeValue);
n.setDelayMsec(-1);
private class DefaultHandler implements ClickListener {
@Override
public void buttonClick(ClickEvent event) {
- Notification n = new Notification(tf.getValue(),
- (Type) type.getValue());
+ Notification n = new Notification(tf.getValue(), type.getValue());
n.setHtmlContentAllowed(true);
n.show(Page.getCurrent());
}
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Component;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.VerticalLayout;
-import com.vaadin.v7.ui.ComboBox;
public class InsertComponentInHorizontalLayout extends AbstractTestUI {
private VerticalLayout layout;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.Alignment;
import com.vaadin.ui.Button;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Embedded;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.HorizontalSplitPanel;
import com.vaadin.ui.NativeButton;
import com.vaadin.ui.Slider;
import com.vaadin.ui.VerticalLayout;
-import com.vaadin.v7.ui.ComboBox;
import com.vaadin.v7.ui.NativeSelect;
import com.vaadin.v7.ui.Table;
HorizontalLayout volume = new HorizontalLayout();
HorizontalLayout status = new HorizontalLayout();
HorizontalLayout viewmodes = new HorizontalLayout();
- ComboBox search = new ComboBox();
+ ComboBox<String> search = new ComboBox<>();
// Add the components and align them properly
top.addComponent(playback);
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.Panel;
import com.vaadin.ui.VerticalLayout;
-import com.vaadin.v7.ui.ComboBox;
import com.vaadin.v7.ui.TextField;
public class UndefinedSizeScrollbars extends AbstractTestUI {
text2.setCaption("Text2");
text2.setRequired(true);
- ComboBox combo = new ComboBox();
+ ComboBox<String> combo = new ComboBox<>();
combo.setCaption("Combo1");
CheckBox check = new CheckBox();
*/
package com.vaadin.tests.components.select;
+import java.util.Arrays;
import java.util.Locale;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUIWithLog;
-import com.vaadin.v7.shared.ui.combobox.FilteringMode;
-import com.vaadin.v7.ui.ComboBox;
+import com.vaadin.ui.ComboBox;
+import com.vaadin.v7.data.util.converter.StringToEnumConverter;
import com.vaadin.v7.ui.NativeSelect;
import com.vaadin.v7.ui.Tree;
protected void setup(VaadinRequest request) {
setLocale(new Locale("fi", "FI"));
- ComboBox cb = new ComboBox();
- cb.setFilteringMode(FilteringMode.CONTAINS);
- for (Constant c : Constant.values()) {
- cb.addItem(c);
- }
+ ComboBox<Constant> cb = new ComboBox<>(null,
+ Arrays.asList(Constant.values()));
+ cb.setItemCaptionProvider(value -> StringToEnumConverter
+ .enumToString(value, getLocale()));
addComponent(cb);
NativeSelect ns = new NativeSelect();
+++ /dev/null
-package com.vaadin.tests.components.select;
-
-import com.vaadin.tests.components.combobox.ComboBoxes2;
-import com.vaadin.v7.ui.Select;
-
-public class SelectTest extends ComboBoxes2<Select> {
-
- @SuppressWarnings("unchecked")
- @Override
- protected Class<Select> getTestClass() {
- return Select.class;
- }
-
-}
@Override
protected String getDescription() {
- return "VFilterSelect popup opener width is not updated when the style or theme changes";
+ return "ComboBox popup opener width is not updated when the style or theme changes";
}
@Override
import java.math.BigDecimal;
import java.text.NumberFormat;
+import java.util.Arrays;
import java.util.Date;
import java.util.Locale;
import com.vaadin.tests.data.bean.Sex;
import com.vaadin.tests.util.Log;
import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.ComboBox;
import com.vaadin.v7.data.Property.ValueChangeEvent;
import com.vaadin.v7.data.Property.ValueChangeListener;
import com.vaadin.v7.data.util.BeanItemContainer;
import com.vaadin.v7.data.util.converter.Converter;
import com.vaadin.v7.data.util.converter.StringToDoubleConverter;
-import com.vaadin.v7.ui.ComboBox;
import com.vaadin.v7.ui.Table;
public class DoublesInTable extends TestBase {
}
private ComboBox createLocaleSelect() {
- ComboBox cb = new ComboBox();
- cb.setNullSelectionAllowed(false);
- for (Locale l : Locale.getAvailableLocales()) {
- cb.addItem(l);
- }
- cb.setImmediate(true);
+ ComboBox<Locale> cb = new ComboBox<>(null,
+ Arrays.asList(Locale.getAvailableLocales()));
cb.setValue(Locale.US);
- cb.addListener(new ValueChangeListener() {
-
- @Override
- public void valueChange(ValueChangeEvent event) {
- recreateTable();
- }
- });
+ cb.addListener(event -> recreateTable());
return cb;
}
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUIWithLog;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Label;
-import com.vaadin.v7.ui.ComboBox;
public class ComboboxSelectedItemText extends AbstractTestUIWithLog {
@Override
getLayout().addComponent(new Label(
"Select first ANTIGUA AND BARBUDA from the first combobox. Then select ANTIGUA AND BARBUDA from the second combobox. Finally, click the popup button on the first combobox. Before fix you would see UA AND BAR in the field."));
- ComboBox combobox = new ComboBox("Text input enabled:");
+ ComboBox<String> combobox = new ComboBox<>("Text input enabled:");
combobox.setWidth("100px");
- combobox.addItem("AMERICAN SAMOA");
- combobox.addItem("ANTIGUA AND BARBUDA");
+ combobox.setItems("AMERICAN SAMOA", "ANTIGUA AND BARBUDA");
- ComboBox combobox2 = new ComboBox("Text input disabled:");
+ ComboBox<String> combobox2 = new ComboBox<>("Text input disabled:");
combobox2.setWidth("100px");
combobox2.setTextInputAllowed(false);
- combobox2.addItem("AMERICAN SAMOA");
- combobox2.addItem("ANTIGUA AND BARBUDA");
+ combobox2.setItems("AMERICAN SAMOA", "ANTIGUA AND BARBUDA");
getLayout().addComponent(combobox);
getLayout().addComponent(combobox2);
package com.vaadin.tests.components.upload;
import java.io.OutputStream;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUIWithLog;
import com.vaadin.ui.Button;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Component;
import com.vaadin.ui.DragAndDropWrapper;
import com.vaadin.ui.Html5File;
import com.vaadin.ui.Panel;
-import com.vaadin.v7.ui.ComboBox;
public class DragAndDropUploadAndInteractions extends AbstractTestUIWithLog {
@Override
protected void setup(VaadinRequest request) {
- ComboBox comboBox = new ComboBox();
+ ComboBox<String> comboBox = new ComboBox<>();
+ List<String> items = new ArrayList<>();
for (int i = 0; i < 10; i++) {
- comboBox.addItem("Test " + i);
+ items.add("Test " + i);
}
+ comboBox.setItems(items);
addComponent(comboBox);
Button b = new Button("Dummy");
addComponent(b);
import com.vaadin.server.VaadinRequest;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.Alignment;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
-import com.vaadin.v7.ui.ComboBox;
/**
*
VerticalLayout content = new VerticalLayout();
w.setContent(content);
content.setHeight("1000px");
- ComboBox cb = new ComboBox();
+ ComboBox<String> cb = new ComboBox<>();
cb.setId(COMBOBOX_ID);
content.addComponent(cb);
content.setComponentAlignment(cb, Alignment.BOTTOM_CENTER);
package com.vaadin.tests.components.window;
+import java.util.ArrayList;
+import java.util.List;
+
import com.vaadin.server.VaadinRequest;
import com.vaadin.shared.ui.window.WindowMode;
import com.vaadin.tests.components.AbstractTestUI;
import com.vaadin.ui.Button;
-import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.ComponentContainer;
import com.vaadin.ui.NativeButton;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
-import com.vaadin.ui.Window.CloseEvent;
-import com.vaadin.ui.Window.CloseListener;
import com.vaadin.ui.Window.WindowModeChangeEvent;
import com.vaadin.ui.Window.WindowModeChangeListener;
-import com.vaadin.v7.data.Item;
-import com.vaadin.v7.data.Property.ValueChangeEvent;
-import com.vaadin.v7.data.Property.ValueChangeListener;
-import com.vaadin.v7.ui.ComboBox;
public class WindowMaximizeRestoreTest extends AbstractTestUI {
- Button.ClickListener addListener = new Button.ClickListener() {
-
- @Override
- public void buttonClick(ClickEvent event) {
- addWindow(createNewWindow());
- }
- };
-
@Override
protected void setup(VaadinRequest request) {
Button addButton = new Button("Add new Window");
- addButton.addListener(addListener);
+ addButton.addClickListener(event -> {
+ addWindow(createNewWindow());
+ addWindowAgain.setValue(null);
+ });
addComponent(addButton);
- addWindowAgain = new ComboBox("Add Window Again");
- addWindowAgain.setBuffered(false);
- addWindowAgain.setImmediate(true);
- addWindowAgain.addValueChangeListener(new ValueChangeListener() {
-
- @Override
- public void valueChange(ValueChangeEvent event) {
-
- Object value = event.getProperty().getValue();
- if (value != null && value instanceof Window) {
- UI.getCurrent().addWindow((Window) value);
- addWindowAgain.removeItem(value);
- }
+ addWindowAgain = new ComboBox<>("Add Window Again");
+ addWindowAgain
+ .setItemCaptionProvider(window -> window.getData().toString());
+ addWindowAgain.addValueChangeListener(event -> {
+ Object value = event.getValue();
+ if (value != null && value instanceof Window) {
+ UI.getCurrent().addWindow((Window) value);
+ windowList.remove(value);
+ addWindowAgain.setItems(windowList);
}
});
addComponent(addWindowAgain);
}
private int windowCount = 0;
- private ComboBox addWindowAgain;
+ private ComboBox<Window> addWindowAgain;
+ private List<Window> windowList = new ArrayList<>();
private Window createNewWindow() {
final Window w = new Window("Window " + (++windowCount));
w.setPositionX(200);
w.setPositionY(200);
final NativeButton maximize = new NativeButton("Maximize");
- Button.ClickListener listener = new Button.ClickListener() {
-
- @Override
- public void buttonClick(ClickEvent event) {
- if (w.getWindowMode() == WindowMode.MAXIMIZED) {
- w.setWindowMode(WindowMode.NORMAL);
- maximize.setCaption("Maximize");
- } else {
- w.setWindowMode(WindowMode.MAXIMIZED);
- maximize.setCaption("Restore");
- }
+ maximize.addClickListener(event -> {
+ if (w.getWindowMode() == WindowMode.MAXIMIZED) {
+ w.setWindowMode(WindowMode.NORMAL);
+ maximize.setCaption("Maximize");
+ } else {
+ w.setWindowMode(WindowMode.MAXIMIZED);
+ maximize.setCaption("Restore");
}
-
- };
- maximize.addClickListener(listener);
+ });
((ComponentContainer) w.getContent()).addComponent(maximize);
w.addWindowModeChangeListener(new WindowModeChangeListener() {
event -> w.setClosable(closeable.getValue()));
((ComponentContainer) w.getContent()).addComponent(closeable);
NativeButton contentFull = new NativeButton("Set Content Size Full",
- new Button.ClickListener() {
-
- @Override
- public void buttonClick(ClickEvent event) {
- w.getContent().setSizeFull();
- }
- });
+ event -> w.getContent().setSizeFull());
contentFull.setWidth("100%");
((ComponentContainer) w.getContent()).addComponent(contentFull);
NativeButton center = new NativeButton("Center");
- center.addClickListener(new Button.ClickListener() {
-
- @Override
- public void buttonClick(ClickEvent event) {
- w.center();
- }
- });
+ center.addClickListener(event -> w.center());
((ComponentContainer) w.getContent()).addComponent(center);
- w.addCloseListener(new CloseListener() {
-
- @Override
- public void windowClose(CloseEvent e) {
- Item item = addWindowAgain.addItem(w);
- addWindowAgain.setItemCaption(w,
- "Window " + w.getData().toString());
- }
+ w.addCloseListener(e -> {
+ windowList.add(w);
+ addWindowAgain.setItems(windowList);
});
return w;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;
import com.vaadin.ui.CheckBox;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Component;
import com.vaadin.ui.CssLayout;
import com.vaadin.ui.DateField;
import com.vaadin.v7.data.Item;
import com.vaadin.v7.data.Property.ValueChangeEvent;
import com.vaadin.v7.data.Property.ValueChangeListener;
-import com.vaadin.v7.ui.ComboBox;
import com.vaadin.v7.ui.NativeSelect;
import com.vaadin.v7.ui.OptionGroup;
import com.vaadin.v7.ui.PasswordField;
components.add(new CheckBox("Default CheckBox"));
- ComboBox comboBox = new ComboBox("Default ComboBox");
- comboBox.addItem("Item1");
+ ComboBox<String> comboBox = new ComboBox<>("Default ComboBox");
+ comboBox.setItems("Item1");
components.add(comboBox);
OptionGroup radioGroup = new OptionGroup("Single Items");
import java.util.Collection;
import java.util.List;
+import com.vaadin.server.data.Query;
import com.vaadin.tests.components.TestBase;
import com.vaadin.ui.AbsoluteLayout;
import com.vaadin.ui.Accordion;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.ComboBox;
import com.vaadin.ui.ComponentContainer;
import com.vaadin.ui.CssLayout;
import com.vaadin.ui.FormLayout;
import com.vaadin.ui.TabSheet;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.VerticalSplitPanel;
-import com.vaadin.v7.data.Property.ValueChangeEvent;
-import com.vaadin.v7.data.Property.ValueChangeListener;
-import com.vaadin.v7.ui.ComboBox;
public class MovingComponentsWhileOldParentInvisible extends TestBase {
lab = new Label("Label inside the component container");
lab.setWidth(null);
- ComboBox componentContainerSelect = new ComboBox("Container") {
- {
- setPageLength(0);
- }
- };
+ ComboBox<Class<? extends HasComponents>> componentContainerSelect = new ComboBox<>(
+ "Container");
+ componentContainerSelect.setPageLength(0);
componentContainerSelect.setId("componentContainerSelect");
componentContainerSelect.setWidth("300px");
- componentContainerSelect.setImmediate(true);
- componentContainerSelect.setNullSelectionAllowed(false);
// componentContainer.addContainerProperty(CAPTION, String.class, "");
// componentContainer.addContainerProperty(CLASS, Class.class, "");
- for (Class<? extends HasComponents> cls : getComponentContainers()) {
- componentContainerSelect.addItem(cls);
- }
- componentContainerSelect.addListener(new ValueChangeListener() {
-
- @Override
- @SuppressWarnings("unchecked")
- public void valueChange(ValueChangeEvent event) {
- HasComponents oldCC = cc;
- cc = createComponentContainer(
- (Class<? extends HasComponents>) event.getProperty()
- .getValue());
- addToCC(lab);
- replaceComponent(oldCC, cc);
- }
+ componentContainerSelect.setItems(getComponentContainers());
+ componentContainerSelect.addValueChangeListener(event -> {
+ HasComponents oldCC = cc;
+ cc = createComponentContainer(event.getValue());
+ addToCC(lab);
+ replaceComponent(oldCC, cc);
});
- componentContainerSelect.setValue(
- componentContainerSelect.getItemIds().iterator().next());
+ componentContainerSelect.setValue(componentContainerSelect
+ .getDataSource().apply(new Query()).iterator().next());
Button but1 = new Button("Move in and out of component container",
new Button.ClickListener() {
import org.openqa.selenium.Keys;
import org.openqa.selenium.interactions.Actions;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.testbench.elements.LabelElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
public class ComboBoxBorderTest extends MultiBrowserTest {
@Test
import org.junit.Test;
import org.openqa.selenium.By;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
/**
* Test to check whether combobox is expanded when icon is clicked.
import org.openqa.selenium.WebElement;
import com.vaadin.testbench.By;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.tests.tb3.SingleBrowserTestPhantomJS2;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
public class ComboBoxEmptyItemsKeyboardNavigationTest
extends SingleBrowserTestPhantomJS2 {
import org.openqa.selenium.support.ui.ExpectedCondition;
import com.vaadin.testbench.By;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.testbench.parallel.BrowserUtil;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
/**
* Test for identical item captions in ComboBox.
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.testbench.elements.ButtonElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
public class ComboBoxInputPromptTest extends MultiBrowserTest {
private String getInputPromptValue(ComboBoxElement comboBox) {
WebElement input = comboBox.findElement(By.tagName("input"));
- return input.getAttribute("value");
+ return input.getAttribute("placeholder");
}
private ComboBoxElement getComboBoxWithCaption(String caption) {
import org.junit.Test;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
public class ComboBoxItemIconTest extends MultiBrowserTest {
@Test
import org.openqa.selenium.interactions.Actions;
import com.vaadin.testbench.By;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
import com.vaadin.v7.testbench.customelements.NativeSelectElement;
public class ComboBoxLargeIconsTest extends MultiBrowserTest {
import org.openqa.selenium.support.ui.ExpectedCondition;
import com.vaadin.testbench.By;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.testbench.elements.LabelElement;
import com.vaadin.testbench.parallel.BrowserUtil;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
public class ComboBoxMouseSelectEnterTest extends MultiBrowserTest {
import com.vaadin.testbench.By;
import com.vaadin.testbench.commands.TestBenchElementCommands;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.testbench.elements.CheckBoxElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
public class ComboBoxNoTextInputTest extends MultiBrowserTest {
ComboBoxElement cb = $(ComboBoxElement.class).first();
click(cb);
// popup is opened lazily
- waitForElementPresent(
- By.vaadin("//com.vaadin.v7.ui.ComboBox[0]#popup"));
+ waitForElementPresent(By.vaadin("//com.vaadin.ui.ComboBox[0]#popup"));
}
@Test
import org.junit.Test;
import org.openqa.selenium.WebElement;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
public class ComboBoxPopupWhenBodyScrollsTest extends MultiBrowserTest {
import org.junit.Test;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.testbench.elements.LabelElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
/**
* When pressed down key, while positioned on the last item - should show next
import org.openqa.selenium.support.ui.ExpectedCondition;
import com.vaadin.testbench.By;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
/**
* When pressed down key, while positioned on the last item - should show next
import org.openqa.selenium.support.ui.ExpectedCondition;
import com.vaadin.testbench.By;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.testbench.elements.LabelElement;
import com.vaadin.testbench.parallel.BrowserUtil;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
public class ComboBoxSelectingTest extends MultiBrowserTest {
assertThatSelectedValueIs("z5");
// longer delay for this one because otherwise it keeps failing when run
// on local machine
- comboBoxElement.sendKeys(200, Keys.BACK_SPACE, Keys.BACK_SPACE,
+ int delay = 200;
+ if (BrowserUtil.isPhantomJS(getDesiredCapabilities())) {
+ delay = 500;
+ }
+ comboBoxElement.sendKeys(delay, Keys.BACK_SPACE, Keys.BACK_SPACE,
Keys.TAB);
assertThatSelectedValueIs("", "null");
import org.openqa.selenium.support.ui.ExpectedCondition;
import com.vaadin.testbench.By;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.testbench.elements.LabelElement;
import com.vaadin.testbench.parallel.BrowserUtil;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
public class ComboBoxSelectingWithNewItemsAllowedTest extends MultiBrowserTest {
private ComboBoxElement comboBoxElement;
import org.openqa.selenium.WebElement;
import com.vaadin.testbench.By;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
public class ComboBoxSuggestionPageLengthTest extends MultiBrowserTest {
import org.openqa.selenium.WebElement;
import com.vaadin.testbench.By;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
/**
* @author Vaadin Ltd
import org.openqa.selenium.WebElement;
import com.vaadin.testbench.By;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
/**
* @author Vaadin Ltd
import org.openqa.selenium.WebElement;
import com.vaadin.testbench.By;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
/**
* @author Vaadin Ltd
import org.openqa.selenium.WebElement;
import com.vaadin.testbench.By;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
/**
* @author Vaadin Ltd
import org.openqa.selenium.WebElement;
import com.vaadin.testbench.By;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
/**
* @author Vaadin Ltd
import org.junit.Test;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.testbench.elements.LabelElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
@SuppressWarnings("serial")
public class ComboSelectedValueBeyondTheFirstDropdownPageTest
import org.openqa.selenium.WebElement;
import org.openqa.selenium.interactions.Actions;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.testbench.elements.MenuBarElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
/**
* Test that checks whether Combobox popup is closed on click to autoopen
@Test
public void closeComboboxPopupOnClickToMenuBar() {
+ setDebug(true);
openTestURL();
openPopup();
private void openPopup() {
ComboBoxElement combobox = $(ComboBoxElement.class).first();
- combobox.click();
combobox.openPopup();
- combobox.focus();
Actions actions = new Actions(getDriver());
actions.moveToElement(
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
public class ComboboxPopupScrollingTest extends MultiBrowserTest {
import org.junit.Test;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.testbench.elements.ButtonElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
/**
* Tests that changing a stylename will not cause the width parameter to be
import org.junit.Test;
import com.vaadin.testbench.By;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
import com.vaadin.v7.testbench.customelements.NativeSelectElement;
public class FilteringTurkishLocaleTest extends MultiBrowserTest {
Assert.assertEquals("There should be only one suggestion", 1,
suggestions.size());
- Assert.assertEquals("İ with dot", suggestions.get(0));
+ Assert.assertEquals("İ dotted", suggestions.get(0));
}
@Test
Assert.assertEquals("There should be only one suggestion", 1,
suggestions.size());
- Assert.assertEquals("I without dot", suggestions.get(0));
+ Assert.assertEquals("I dotless", suggestions.get(0));
}
private List<String> getFilterSuggestions(String string) {
import com.vaadin.testbench.By;
import com.vaadin.testbench.TestBenchElement;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.tests.tb3.SingleBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
import com.vaadin.v7.testbench.customelements.NativeSelectElement;
public class EnumSelectTest extends SingleBrowserTest {
WebElement comboBox = vaadinElement(
"/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot["
- + indexToTest + "]/VFilterSelect[0]");
+ + indexToTest + "]/VComboBox[0]");
WebElement comboBoxFocus = vaadinElement(
"/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot["
- + indexToFocus + "]/VFilterSelect[0]");
+ + indexToFocus + "]/VComboBox[0]");
// Select an element from the first (to test) combobox.
waitForPopup(comboBox);
WebElement comboBoxPopup = vaadinElement(
"/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot["
- + indexToTest + "]/VFilterSelect[0]#popup");
+ + indexToTest + "]/VComboBox[0]#popup");
comboBoxPopup.findElements(By.tagName("td")).get(2).click();
// Select an element from the second (to focus) combobox to remove
waitForPopup(comboBoxFocus);
comboBoxPopup = vaadinElement(
"/VVerticalLayout[0]/Slot[2]/VVerticalLayout[0]/Slot["
- + indexToFocus + "]/VFilterSelect[0]#popup");
+ + indexToFocus + "]/VComboBox[0]#popup");
comboBoxPopup.findElements(By.tagName("td")).get(2).click();
// click the button of the first combobox. This would reveal the
import com.vaadin.testbench.By;
import com.vaadin.testbench.commands.TestBenchElementCommands;
+import com.vaadin.testbench.customelements.ComboBoxElement;
import com.vaadin.testbench.customelements.WindowElement;
import com.vaadin.tests.tb3.MultiBrowserTest;
-import com.vaadin.v7.testbench.customelements.ComboBoxElement;
/**
* Tests that a ComboBox at the bottom of a Window remains visible when clicked.