summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/src/main/java/com/vaadin/client/ui/VComboBox.java4
-rw-r--r--client/src/main/java/com/vaadin/client/ui/combobox/ComboBoxConnector.java173
-rw-r--r--server/src/main/java/com/vaadin/ui/ComboBox.java37
-rw-r--r--shared/src/main/java/com/vaadin/shared/ui/combobox/ComboBoxState.java5
-rw-r--r--uitest/src/main/java/com/vaadin/tests/components/combobox/ComboBoxEmptyCaption.java48
-rw-r--r--uitest/src/test/java/com/vaadin/tests/components/combobox/ComboBoxEmptyCaptionTest.java84
6 files changed, 275 insertions, 76 deletions
diff --git a/client/src/main/java/com/vaadin/client/ui/VComboBox.java b/client/src/main/java/com/vaadin/client/ui/VComboBox.java
index b19f9944ba..6ecea2d116 100644
--- a/client/src/main/java/com/vaadin/client/ui/VComboBox.java
+++ b/client/src/main/java/com/vaadin/client/ui/VComboBox.java
@@ -1592,7 +1592,7 @@ public class VComboBox extends Composite implements Field, KeyDownHandler,
* <p>
* For internal use only. May be removed or replaced in the future.
*/
- public final List<ComboBoxSuggestion> currentSuggestions = new ArrayList<ComboBoxSuggestion>();
+ public final List<ComboBoxSuggestion> currentSuggestions = new ArrayList<>();
/** For internal use only. May be removed or replaced in the future. */
public String serverSelectedKey;
@@ -2067,7 +2067,7 @@ public class VComboBox extends Composite implements Field, KeyDownHandler,
Unit.PX);
}
- private static Set<Integer> navigationKeyCodes = new HashSet<Integer>();
+ private static Set<Integer> navigationKeyCodes = new HashSet<>();
static {
navigationKeyCodes.add(KeyCodes.KEY_DOWN);
navigationKeyCodes.add(KeyCodes.KEY_UP);
diff --git a/client/src/main/java/com/vaadin/client/ui/combobox/ComboBoxConnector.java b/client/src/main/java/com/vaadin/client/ui/combobox/ComboBoxConnector.java
index 8b56483e8f..a4a9c17f4d 100644
--- a/client/src/main/java/com/vaadin/client/ui/combobox/ComboBoxConnector.java
+++ b/client/src/main/java/com/vaadin/client/ui/combobox/ComboBoxConnector.java
@@ -15,6 +15,8 @@
*/
package com.vaadin.client.ui.combobox;
+import java.util.List;
+
import com.vaadin.client.Profiler;
import com.vaadin.client.annotations.OnStateChange;
import com.vaadin.client.communication.StateChangeEvent;
@@ -25,6 +27,7 @@ import com.vaadin.client.ui.HasErrorIndicator;
import com.vaadin.client.ui.HasRequiredIndicator;
import com.vaadin.client.ui.SimpleManagedLayout;
import com.vaadin.client.ui.VComboBox;
+import com.vaadin.client.ui.VComboBox.ComboBoxSuggestion;
import com.vaadin.client.ui.VComboBox.DataReceivedHandler;
import com.vaadin.shared.EventId;
import com.vaadin.shared.Registration;
@@ -87,6 +90,15 @@ public class ComboBoxConnector extends AbstractListingConnector
Profiler.leave("ComboBoxConnector.onStateChanged update content");
}
+ @OnStateChange("emptySelectionCaption")
+ private void onEmptySelectionCaptionChange() {
+ List<ComboBoxSuggestion> suggestions = getWidget().currentSuggestions;
+ if (!suggestions.isEmpty() && isFirstPage()) {
+ suggestions.remove(0);
+ addEmptySelectionItem();
+ }
+ }
+
@OnStateChange({ "selectedItemKey", "selectedItemCaption" })
private void onSelectionChange() {
getDataReceivedHandler().updateSelectionFromServer(
@@ -249,80 +261,7 @@ public class ComboBoxConnector extends AbstractListingConnector
public void setDataSource(DataSource<JsonObject> dataSource) {
super.setDataSource(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 = getRowKey(row);
- 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 = getRowKey(row);
- 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();
- });
+ .addDataChangeHandler(range -> refreshData());
}
@Override
@@ -335,4 +274,90 @@ public class ComboBoxConnector extends AbstractListingConnector
public boolean isRequiredIndicatorVisible() {
return getState().required && !isReadOnly();
}
+
+ private void refreshData() {
+ updateCurrentPage();
+
+ 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 (isFirstPage()) {
+ addEmptySelectionItem();
+ } else {
+ // ...or leave space for it
+ start = start - 1;
+ }
+ // in either case, the last item to show is
+ // shifted by one
+ end = end - 1;
+ }
+
+ updateSuggestions(start, end);
+ getWidget().totalMatches = getDataSource().size()
+ + (getState().emptySelectionAllowed ? 1 : 0);
+
+ getDataReceivedHandler().dataReceived();
+ }
+
+ private void updateSuggestions(int start, int end) {
+ for (int i = start; i < end; ++i) {
+ JsonObject row = getDataSource().getRow(i);
+
+ if (row != null) {
+ String key = getRowKey(row);
+ 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));
+ }
+ }
+ }
+
+ private boolean isFirstPage() {
+ return getWidget().currentPage == 0;
+ }
+
+ private void addEmptySelectionItem() {
+ if (isFirstPage()) {
+ getWidget().currentSuggestions.add(0,
+ getWidget().new ComboBoxSuggestion("",
+ getState().emptySelectionCaption, null, null));
+ }
+ }
+
+ private void updateCurrentPage() {
+ // 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 = getRowKey(row);
+ 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;
+ }
+ }
}
diff --git a/server/src/main/java/com/vaadin/ui/ComboBox.java b/server/src/main/java/com/vaadin/ui/ComboBox.java
index 9034fabf11..093c5e9c7a 100644
--- a/server/src/main/java/com/vaadin/ui/ComboBox.java
+++ b/server/src/main/java/com/vaadin/ui/ComboBox.java
@@ -402,6 +402,43 @@ public class ComboBox<T> extends AbstractSingleSelect<T>
}
/**
+ * Returns the empty selection caption.
+ * <p>
+ * The empty string {@code ""} is the default empty selection caption.
+ *
+ * @see #setEmptySelectionAllowed(boolean)
+ * @see #isEmptySelectionAllowed()
+ * @see #setEmptySelectionCaption(String)
+ * @see #isSelected(Object)
+ * @see #select(Object)
+ *
+ * @return the empty selection caption, not {@code null}
+ */
+ public String getEmptySelectionCaption() {
+ return getState(false).emptySelectionCaption;
+ }
+
+ /**
+ * Sets the empty selection caption.
+ * <p>
+ * The empty string {@code ""} is the default empty selection caption.
+ * <p>
+ * If empty selection is allowed via the
+ * {@link #setEmptySelectionAllowed(boolean)} method (it is by default) then
+ * the empty item will be shown with the given caption.
+ *
+ * @param caption
+ * the caption to set, not {@code null}
+ * @see #getNullSelectionItemId()
+ * @see #isSelected(Object)
+ * @see #select(Object)
+ */
+ public void setEmptySelectionCaption(String caption) {
+ Objects.nonNull(caption);
+ getState().emptySelectionCaption = caption;
+ }
+
+ /**
* 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.
diff --git a/shared/src/main/java/com/vaadin/shared/ui/combobox/ComboBoxState.java b/shared/src/main/java/com/vaadin/shared/ui/combobox/ComboBoxState.java
index 154735ce26..01a02a4a5f 100644
--- a/shared/src/main/java/com/vaadin/shared/ui/combobox/ComboBoxState.java
+++ b/shared/src/main/java/com/vaadin/shared/ui/combobox/ComboBoxState.java
@@ -88,4 +88,9 @@ public class ComboBoxState extends AbstractSingleSelectState {
*/
public String selectedItemCaption;
+ /**
+ * Caption for item which represents empty selection.
+ */
+ public String emptySelectionCaption = "";
+
}
diff --git a/uitest/src/main/java/com/vaadin/tests/components/combobox/ComboBoxEmptyCaption.java b/uitest/src/main/java/com/vaadin/tests/components/combobox/ComboBoxEmptyCaption.java
new file mode 100644
index 0000000000..3d32c54a7e
--- /dev/null
+++ b/uitest/src/main/java/com/vaadin/tests/components/combobox/ComboBoxEmptyCaption.java
@@ -0,0 +1,48 @@
+/*
+ * 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.tests.components.combobox;
+
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+import com.vaadin.server.VaadinRequest;
+import com.vaadin.tests.components.AbstractTestUI;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.ComboBox;
+
+/**
+ * @author Vaadin Ltd
+ *
+ */
+public class ComboBoxEmptyCaption extends AbstractTestUI {
+
+ @Override
+ protected void setup(VaadinRequest request) {
+ ComboBox<String> combo = new ComboBox<>();
+ combo.setItems(
+ IntStream.range(1, 100).mapToObj(number -> "item" + number)
+ .collect(Collectors.toList()));
+ addComponent(combo);
+ Button setCaption = new Button("Set empty selection caption to 'empty'",
+ event -> combo.setEmptySelectionCaption("empty"));
+ Button resetCaption = new Button(
+ "Set empty selection caption to empty string",
+ event -> combo.setEmptySelectionCaption(""));
+ Button disableCaption = new Button("Disable empty selection caption",
+ event -> combo.setEmptySelectionAllowed(false));
+ addComponents(setCaption, resetCaption, disableCaption);
+ }
+}
diff --git a/uitest/src/test/java/com/vaadin/tests/components/combobox/ComboBoxEmptyCaptionTest.java b/uitest/src/test/java/com/vaadin/tests/components/combobox/ComboBoxEmptyCaptionTest.java
new file mode 100644
index 0000000000..0cb890dfda
--- /dev/null
+++ b/uitest/src/test/java/com/vaadin/tests/components/combobox/ComboBoxEmptyCaptionTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.tests.components.combobox;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.vaadin.testbench.elements.ButtonElement;
+import com.vaadin.testbench.elements.ComboBoxElement;
+import com.vaadin.tests.tb3.MultiBrowserTest;
+
+/**
+ * @author Vaadin Ltd
+ *
+ */
+public class ComboBoxEmptyCaptionTest extends MultiBrowserTest {
+
+ @Before
+ public void setUp() {
+ openTestURL();
+ }
+
+ @Test
+ public void emptyItemCaption() {
+ ComboBoxElement combo = $(ComboBoxElement.class).first();
+ // empty string in caption becomes &nbsp; because of #7506
+ ensureSuggestions(combo, " ", "item1", "item2", "item3", "item4",
+ "item5", "item6", "item7", "item8", "item9");
+ }
+
+ @Test
+ public void hasEmptyItemCaption() {
+ ComboBoxElement combo = $(ComboBoxElement.class).first();
+ // set some caption for the empty selection element
+ $(ButtonElement.class).first().click();
+ ensureSuggestions(combo, "empty", "item1", "item2", "item3", "item4",
+ "item5", "item6", "item7", "item8", "item9");
+ }
+
+ @Test
+ public void resetEmptyItem() {
+ ComboBoxElement combo = $(ComboBoxElement.class).first();
+ // set some caption for the empty selection element
+ $(ButtonElement.class).first().click();
+ // set empty string back as an empty caption
+ $(ButtonElement.class).get(1).click();
+ ensureSuggestions(combo, " ", "item1", "item2", "item3", "item4",
+ "item5", "item6", "item7", "item8", "item9");
+ }
+
+ @Test
+ public void disableEmptyItem() {
+ ComboBoxElement combo = $(ComboBoxElement.class).first();
+ // set some caption for the empty selection element
+ $(ButtonElement.class).get(2).click();
+ ensureSuggestions(combo, "item1", "item2", "item3", "item4", "item5",
+ "item6", "item7", "item8", "item9", "item10");
+ }
+
+ private void ensureSuggestions(ComboBoxElement element,
+ String... suggestions) {
+ element.openPopup();
+ System.out.println(element.getPopupSuggestions());
+ Assert.assertEquals(Arrays.asList(suggestions),
+ new ArrayList<>(element.getPopupSuggestions()));
+ }
+}