You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ComboBox.java 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  1. /*
  2. * Copyright 2011 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.ui;
  17. import java.util.ArrayList;
  18. import java.util.Collection;
  19. import java.util.Iterator;
  20. import java.util.LinkedList;
  21. import java.util.List;
  22. import java.util.Map;
  23. import com.vaadin.data.Container;
  24. import com.vaadin.data.util.filter.SimpleStringFilter;
  25. import com.vaadin.event.FieldEvents;
  26. import com.vaadin.event.FieldEvents.BlurEvent;
  27. import com.vaadin.event.FieldEvents.BlurListener;
  28. import com.vaadin.event.FieldEvents.FocusEvent;
  29. import com.vaadin.event.FieldEvents.FocusListener;
  30. import com.vaadin.server.PaintException;
  31. import com.vaadin.server.PaintTarget;
  32. import com.vaadin.server.Resource;
  33. import com.vaadin.shared.ui.combobox.ComboBoxConstants;
  34. import com.vaadin.shared.ui.combobox.FilteringMode;
  35. /**
  36. * A filtering dropdown single-select. Suitable for newItemsAllowed, but it's
  37. * turned of by default to avoid mistakes. Items are filtered based on user
  38. * input, and loaded dynamically ("lazy-loading") from the server. You can turn
  39. * on newItemsAllowed and change filtering mode (and also turn it off), but you
  40. * can not turn on multi-select mode.
  41. *
  42. */
  43. @SuppressWarnings("serial")
  44. public class ComboBox extends AbstractSelect implements
  45. AbstractSelect.Filtering, FieldEvents.BlurNotifier,
  46. FieldEvents.FocusNotifier {
  47. private String inputPrompt = null;
  48. /**
  49. * Holds value of property pageLength. 0 disables paging.
  50. */
  51. protected int pageLength = 10;
  52. private int columns = 0;
  53. // Current page when the user is 'paging' trough options
  54. private int currentPage = -1;
  55. private FilteringMode filteringMode = FilteringMode.STARTSWITH;
  56. private String filterstring;
  57. private String prevfilterstring;
  58. /**
  59. * Number of options that pass the filter, excluding the null item if any.
  60. */
  61. private int filteredSize;
  62. /**
  63. * Cache of filtered options, used only by the in-memory filtering system.
  64. */
  65. private List<Object> filteredOptions;
  66. /**
  67. * Flag to indicate that request repaint is called by filter request only
  68. */
  69. private boolean optionRequest;
  70. /**
  71. * True if the container is being filtered temporarily and item set change
  72. * notifications should be suppressed.
  73. */
  74. private boolean filteringContainer;
  75. /**
  76. * Flag to indicate whether to scroll the selected item visible (select the
  77. * page on which it is) when opening the popup or not. Only applies to
  78. * single select mode.
  79. *
  80. * This requires finding the index of the item, which can be expensive in
  81. * many large lazy loading containers.
  82. */
  83. private boolean scrollToSelectedItem = true;
  84. /**
  85. * If text input is not allowed, the ComboBox behaves like a pretty
  86. * NativeSelect - the user can not enter any text and clicking the text
  87. * field opens the drop down with options
  88. */
  89. private boolean textInputAllowed = true;
  90. public ComboBox() {
  91. setNewItemsAllowed(false);
  92. }
  93. public ComboBox(String caption, Collection<?> options) {
  94. super(caption, options);
  95. setNewItemsAllowed(false);
  96. }
  97. public ComboBox(String caption, Container dataSource) {
  98. super(caption, dataSource);
  99. setNewItemsAllowed(false);
  100. }
  101. public ComboBox(String caption) {
  102. super(caption);
  103. setNewItemsAllowed(false);
  104. }
  105. /**
  106. * Gets the current input prompt.
  107. *
  108. * @see #setInputPrompt(String)
  109. * @return the current input prompt, or null if not enabled
  110. */
  111. public String getInputPrompt() {
  112. return inputPrompt;
  113. }
  114. /**
  115. * Sets the input prompt - a textual prompt that is displayed when the
  116. * select would otherwise be empty, to prompt the user for input.
  117. *
  118. * @param inputPrompt
  119. * the desired input prompt, or null to disable
  120. */
  121. public void setInputPrompt(String inputPrompt) {
  122. this.inputPrompt = inputPrompt;
  123. markAsDirty();
  124. }
  125. @Override
  126. public void paintContent(PaintTarget target) throws PaintException {
  127. if (inputPrompt != null) {
  128. target.addAttribute(ComboBoxConstants.ATTR_INPUTPROMPT, inputPrompt);
  129. }
  130. if (!textInputAllowed) {
  131. target.addAttribute(ComboBoxConstants.ATTR_NO_TEXT_INPUT, true);
  132. }
  133. // clear caption change listeners
  134. getCaptionChangeListener().clear();
  135. // The tab ordering number
  136. if (getTabIndex() != 0) {
  137. target.addAttribute("tabindex", getTabIndex());
  138. }
  139. // If the field is modified, but not committed, set modified attribute
  140. if (isModified()) {
  141. target.addAttribute("modified", true);
  142. }
  143. if (isNewItemsAllowed()) {
  144. target.addAttribute("allownewitem", true);
  145. }
  146. boolean needNullSelectOption = false;
  147. if (isNullSelectionAllowed()) {
  148. target.addAttribute("nullselect", true);
  149. needNullSelectOption = (getNullSelectionItemId() == null);
  150. if (!needNullSelectOption) {
  151. target.addAttribute("nullselectitem", true);
  152. }
  153. }
  154. // Constructs selected keys array
  155. String[] selectedKeys = new String[(getValue() == null
  156. && getNullSelectionItemId() == null ? 0 : 1)];
  157. target.addAttribute("pagelength", pageLength);
  158. target.addAttribute("filteringmode", getFilteringMode().toString());
  159. // Paints the options and create array of selected id keys
  160. int keyIndex = 0;
  161. target.startTag("options");
  162. if (currentPage < 0) {
  163. optionRequest = false;
  164. currentPage = 0;
  165. filterstring = "";
  166. }
  167. boolean nullFilteredOut = filterstring != null
  168. && !"".equals(filterstring)
  169. && filteringMode != FilteringMode.OFF;
  170. // null option is needed and not filtered out, even if not on current
  171. // page
  172. boolean nullOptionVisible = needNullSelectOption && !nullFilteredOut;
  173. // first try if using container filters is possible
  174. List<?> options = getOptionsWithFilter(nullOptionVisible);
  175. if (null == options) {
  176. // not able to use container filters, perform explicit in-memory
  177. // filtering
  178. options = getFilteredOptions();
  179. filteredSize = options.size();
  180. options = sanitetizeList(options, nullOptionVisible);
  181. }
  182. final boolean paintNullSelection = needNullSelectOption
  183. && currentPage == 0 && !nullFilteredOut;
  184. if (paintNullSelection) {
  185. target.startTag("so");
  186. target.addAttribute("caption", "");
  187. target.addAttribute("key", "");
  188. target.endTag("so");
  189. }
  190. final Iterator<?> i = options.iterator();
  191. // Paints the available selection options from data source
  192. while (i.hasNext()) {
  193. final Object id = i.next();
  194. if (!isNullSelectionAllowed() && id != null
  195. && id.equals(getNullSelectionItemId()) && !isSelected(id)) {
  196. continue;
  197. }
  198. // Gets the option attribute values
  199. final String key = itemIdMapper.key(id);
  200. final String caption = getItemCaption(id);
  201. final Resource icon = getItemIcon(id);
  202. getCaptionChangeListener().addNotifierForItem(id);
  203. // Paints the option
  204. target.startTag("so");
  205. if (icon != null) {
  206. target.addAttribute("icon", icon);
  207. }
  208. target.addAttribute("caption", caption);
  209. if (id != null && id.equals(getNullSelectionItemId())) {
  210. target.addAttribute("nullselection", true);
  211. }
  212. target.addAttribute("key", key);
  213. if (isSelected(id) && keyIndex < selectedKeys.length) {
  214. target.addAttribute("selected", true);
  215. selectedKeys[keyIndex++] = key;
  216. }
  217. target.endTag("so");
  218. }
  219. target.endTag("options");
  220. target.addAttribute("totalitems", size()
  221. + (needNullSelectOption ? 1 : 0));
  222. if (filteredSize > 0 || nullOptionVisible) {
  223. target.addAttribute("totalMatches", filteredSize
  224. + (nullOptionVisible ? 1 : 0));
  225. }
  226. // Paint variables
  227. target.addVariable(this, "selected", selectedKeys);
  228. if (isNewItemsAllowed()) {
  229. target.addVariable(this, "newitem", "");
  230. }
  231. target.addVariable(this, "filter", filterstring);
  232. target.addVariable(this, "page", currentPage);
  233. currentPage = -1; // current page is always set by client
  234. optionRequest = true;
  235. }
  236. /**
  237. * Sets whether it is possible to input text into the field or whether the
  238. * field area of the component is just used to show what is selected. By
  239. * disabling text input, the comboBox will work in the same way as a
  240. * {@link NativeSelect}
  241. *
  242. * @see #isTextInputAllowed()
  243. *
  244. * @param textInputAllowed
  245. * true to allow entering text, false to just show the current
  246. * selection
  247. */
  248. public void setTextInputAllowed(boolean textInputAllowed) {
  249. this.textInputAllowed = textInputAllowed;
  250. markAsDirty();
  251. }
  252. /**
  253. * Returns true if the user can enter text into the field to either filter
  254. * the selections or enter a new value if {@link #isNewItemsAllowed()}
  255. * returns true. If text input is disabled, the comboBox will work in the
  256. * same way as a {@link NativeSelect}
  257. *
  258. * @return
  259. */
  260. public boolean isTextInputAllowed() {
  261. return textInputAllowed;
  262. }
  263. /**
  264. * Returns the filtered options for the current page using a container
  265. * filter.
  266. *
  267. * As a size effect, {@link #filteredSize} is set to the total number of
  268. * items passing the filter.
  269. *
  270. * The current container must be {@link Filterable} and {@link Indexed}, and
  271. * the filtering mode must be suitable for container filtering (tested with
  272. * {@link #canUseContainerFilter()}).
  273. *
  274. * Use {@link #getFilteredOptions()} and
  275. * {@link #sanitetizeList(List, boolean)} if this is not the case.
  276. *
  277. * @param needNullSelectOption
  278. * @return filtered list of options (may be empty) or null if cannot use
  279. * container filters
  280. */
  281. protected List<?> getOptionsWithFilter(boolean needNullSelectOption) {
  282. Container container = getContainerDataSource();
  283. if (pageLength == 0) {
  284. // no paging: return all items
  285. filteredSize = container.size();
  286. return new ArrayList<Object>(container.getItemIds());
  287. }
  288. if (!(container instanceof Filterable)
  289. || !(container instanceof Indexed)
  290. || getItemCaptionMode() != ITEM_CAPTION_MODE_PROPERTY) {
  291. return null;
  292. }
  293. Filterable filterable = (Filterable) container;
  294. Filter filter = buildFilter(filterstring, filteringMode);
  295. // adding and removing filters leads to extraneous item set
  296. // change events from the underlying container, but the ComboBox does
  297. // not process or propagate them based on the flag filteringContainer
  298. if (filter != null) {
  299. filteringContainer = true;
  300. filterable.addContainerFilter(filter);
  301. }
  302. // try-finally to ensure that the filter is removed from container even
  303. // if a exception is thrown...
  304. try {
  305. Indexed indexed = (Indexed) container;
  306. int indexToEnsureInView = -1;
  307. // if not an option request (item list when user changes page), go
  308. // to page with the selected item after filtering if accepted by
  309. // filter
  310. Object selection = getValue();
  311. if (isScrollToSelectedItem() && !optionRequest && selection != null) {
  312. // ensure proper page
  313. indexToEnsureInView = indexed.indexOfId(selection);
  314. }
  315. filteredSize = container.size();
  316. currentPage = adjustCurrentPage(currentPage, needNullSelectOption,
  317. indexToEnsureInView, filteredSize);
  318. int first = getFirstItemIndexOnCurrentPage(needNullSelectOption,
  319. filteredSize);
  320. int last = getLastItemIndexOnCurrentPage(needNullSelectOption,
  321. filteredSize, first);
  322. // Compute the number of items to fetch from the indexes given or
  323. // based on the filtered size of the container
  324. int lastItemToFetch = Math.min(last, filteredSize - 1);
  325. int nrOfItemsToFetch = (lastItemToFetch + 1) - first;
  326. List<?> options = indexed.getItemIds(first, nrOfItemsToFetch);
  327. return options;
  328. } finally {
  329. // to the outside, filtering should not be visible
  330. if (filter != null) {
  331. filterable.removeContainerFilter(filter);
  332. filteringContainer = false;
  333. }
  334. }
  335. }
  336. /**
  337. * Constructs a filter instance to use when using a Filterable container in
  338. * the <code>ITEM_CAPTION_MODE_PROPERTY</code> mode.
  339. *
  340. * Note that the client side implementation expects the filter string to
  341. * apply to the item caption string it sees, so changing the behavior of
  342. * this method can cause problems.
  343. *
  344. * @param filterString
  345. * @param filteringMode
  346. * @return
  347. */
  348. protected Filter buildFilter(String filterString,
  349. FilteringMode filteringMode) {
  350. Filter filter = null;
  351. if (null != filterString && !"".equals(filterString)) {
  352. switch (filteringMode) {
  353. case OFF:
  354. break;
  355. case STARTSWITH:
  356. filter = new SimpleStringFilter(getItemCaptionPropertyId(),
  357. filterString, true, true);
  358. break;
  359. case CONTAINS:
  360. filter = new SimpleStringFilter(getItemCaptionPropertyId(),
  361. filterString, true, false);
  362. break;
  363. }
  364. }
  365. return filter;
  366. }
  367. @Override
  368. public void containerItemSetChange(Container.ItemSetChangeEvent event) {
  369. if (!filteringContainer) {
  370. super.containerItemSetChange(event);
  371. }
  372. }
  373. /**
  374. * Makes correct sublist of given list of options.
  375. *
  376. * If paint is not an option request (affected by page or filter change),
  377. * page will be the one where possible selection exists.
  378. *
  379. * Detects proper first and last item in list to return right page of
  380. * options. Also, if the current page is beyond the end of the list, it will
  381. * be adjusted.
  382. *
  383. * @param options
  384. * @param needNullSelectOption
  385. * flag to indicate if nullselect option needs to be taken into
  386. * consideration
  387. */
  388. private List<?> sanitetizeList(List<?> options, boolean needNullSelectOption) {
  389. if (pageLength != 0 && options.size() > pageLength) {
  390. int indexToEnsureInView = -1;
  391. // if not an option request (item list when user changes page), go
  392. // to page with the selected item after filtering if accepted by
  393. // filter
  394. Object selection = getValue();
  395. if (isScrollToSelectedItem() && !optionRequest && selection != null) {
  396. // ensure proper page
  397. indexToEnsureInView = options.indexOf(selection);
  398. }
  399. int size = options.size();
  400. currentPage = adjustCurrentPage(currentPage, needNullSelectOption,
  401. indexToEnsureInView, size);
  402. int first = getFirstItemIndexOnCurrentPage(needNullSelectOption,
  403. size);
  404. int last = getLastItemIndexOnCurrentPage(needNullSelectOption,
  405. size, first);
  406. return options.subList(first, last + 1);
  407. } else {
  408. return options;
  409. }
  410. }
  411. /**
  412. * Returns the index of the first item on the current page. The index is to
  413. * the underlying (possibly filtered) contents. The null item, if any, does
  414. * not have an index but takes up a slot on the first page.
  415. *
  416. * @param needNullSelectOption
  417. * true if a null option should be shown before any other options
  418. * (takes up the first slot on the first page, not counted in
  419. * index)
  420. * @param size
  421. * number of items after filtering (not including the null item,
  422. * if any)
  423. * @return first item to show on the UI (index to the filtered list of
  424. * options, not taking the null item into consideration if any)
  425. */
  426. private int getFirstItemIndexOnCurrentPage(boolean needNullSelectOption,
  427. int size) {
  428. // Not all options are visible, find out which ones are on the
  429. // current "page".
  430. int first = currentPage * pageLength;
  431. if (needNullSelectOption && currentPage > 0) {
  432. first--;
  433. }
  434. return first;
  435. }
  436. /**
  437. * Returns the index of the last item on the current page. The index is to
  438. * the underlying (possibly filtered) contents. If needNullSelectOption is
  439. * true, the null item takes up the first slot on the first page,
  440. * effectively reducing the first page size by one.
  441. *
  442. * @param needNullSelectOption
  443. * true if a null option should be shown before any other options
  444. * (takes up the first slot on the first page, not counted in
  445. * index)
  446. * @param size
  447. * number of items after filtering (not including the null item,
  448. * if any)
  449. * @param first
  450. * index in the filtered view of the first item of the page
  451. * @return index in the filtered view of the last item on the page
  452. */
  453. private int getLastItemIndexOnCurrentPage(boolean needNullSelectOption,
  454. int size, int first) {
  455. // page length usable for non-null items
  456. int effectivePageLength = pageLength
  457. - (needNullSelectOption && (currentPage == 0) ? 1 : 0);
  458. return Math.min(size - 1, first + effectivePageLength - 1);
  459. }
  460. /**
  461. * Adjusts the index of the current page if necessary: make sure the current
  462. * page is not after the end of the contents, and optionally go to the page
  463. * containg a specific item. There are no side effects but the adjusted page
  464. * index is returned.
  465. *
  466. * @param page
  467. * page number to use as the starting point
  468. * @param needNullSelectOption
  469. * true if a null option should be shown before any other options
  470. * (takes up the first slot on the first page, not counted in
  471. * index)
  472. * @param indexToEnsureInView
  473. * index of an item that should be included on the page (in the
  474. * data set, not counting the null item if any), -1 for none
  475. * @param size
  476. * number of items after filtering (not including the null item,
  477. * if any)
  478. */
  479. private int adjustCurrentPage(int page, boolean needNullSelectOption,
  480. int indexToEnsureInView, int size) {
  481. if (indexToEnsureInView != -1) {
  482. int newPage = (indexToEnsureInView + (needNullSelectOption ? 1 : 0))
  483. / pageLength;
  484. page = newPage;
  485. }
  486. // adjust the current page if beyond the end of the list
  487. if (page * pageLength > size) {
  488. page = (size + (needNullSelectOption ? 1 : 0)) / pageLength;
  489. }
  490. return page;
  491. }
  492. /**
  493. * Filters the options in memory and returns the full filtered list.
  494. *
  495. * This can be less efficient than using container filters, so use
  496. * {@link #getOptionsWithFilter(boolean)} if possible (filterable container
  497. * and suitable item caption mode etc.).
  498. *
  499. * @return
  500. */
  501. protected List<?> getFilteredOptions() {
  502. if (null == filterstring || "".equals(filterstring)
  503. || FilteringMode.OFF == filteringMode) {
  504. prevfilterstring = null;
  505. filteredOptions = new LinkedList<Object>(getItemIds());
  506. return filteredOptions;
  507. }
  508. if (filterstring.equals(prevfilterstring)) {
  509. return filteredOptions;
  510. }
  511. Collection<?> items;
  512. if (prevfilterstring != null
  513. && filterstring.startsWith(prevfilterstring)) {
  514. items = filteredOptions;
  515. } else {
  516. items = getItemIds();
  517. }
  518. prevfilterstring = filterstring;
  519. filteredOptions = new LinkedList<Object>();
  520. for (final Iterator<?> it = items.iterator(); it.hasNext();) {
  521. final Object itemId = it.next();
  522. String caption = getItemCaption(itemId);
  523. if (caption == null || caption.equals("")) {
  524. continue;
  525. } else {
  526. caption = caption.toLowerCase();
  527. }
  528. switch (filteringMode) {
  529. case CONTAINS:
  530. if (caption.indexOf(filterstring) > -1) {
  531. filteredOptions.add(itemId);
  532. }
  533. break;
  534. case STARTSWITH:
  535. default:
  536. if (caption.startsWith(filterstring)) {
  537. filteredOptions.add(itemId);
  538. }
  539. break;
  540. }
  541. }
  542. return filteredOptions;
  543. }
  544. /**
  545. * Invoked when the value of a variable has changed.
  546. *
  547. * @see com.vaadin.ui.AbstractComponent#changeVariables(java.lang.Object,
  548. * java.util.Map)
  549. */
  550. @Override
  551. public void changeVariables(Object source, Map<String, Object> variables) {
  552. // Not calling super.changeVariables due the history of select
  553. // component hierarchy
  554. // Selection change
  555. if (variables.containsKey("selected")) {
  556. final String[] ka = (String[]) variables.get("selected");
  557. // Single select mode
  558. if (ka.length == 0) {
  559. // Allows deselection only if the deselected item is visible
  560. final Object current = getValue();
  561. final Collection<?> visible = getVisibleItemIds();
  562. if (visible != null && visible.contains(current)) {
  563. setValue(null, true);
  564. }
  565. } else {
  566. final Object id = itemIdMapper.get(ka[0]);
  567. if (id != null && id.equals(getNullSelectionItemId())) {
  568. setValue(null, true);
  569. } else {
  570. setValue(id, true);
  571. }
  572. }
  573. }
  574. String newFilter;
  575. if ((newFilter = (String) variables.get("filter")) != null) {
  576. // this is a filter request
  577. currentPage = ((Integer) variables.get("page")).intValue();
  578. filterstring = newFilter;
  579. if (filterstring != null) {
  580. filterstring = filterstring.toLowerCase();
  581. }
  582. requestRepaint();
  583. } else if (isNewItemsAllowed()) {
  584. // New option entered (and it is allowed)
  585. final String newitem = (String) variables.get("newitem");
  586. if (newitem != null && newitem.length() > 0) {
  587. getNewItemHandler().addNewItem(newitem);
  588. // rebuild list
  589. filterstring = null;
  590. prevfilterstring = null;
  591. }
  592. }
  593. if (variables.containsKey(FocusEvent.EVENT_ID)) {
  594. fireEvent(new FocusEvent(this));
  595. }
  596. if (variables.containsKey(BlurEvent.EVENT_ID)) {
  597. fireEvent(new BlurEvent(this));
  598. }
  599. }
  600. @Override
  601. public void setFilteringMode(FilteringMode filteringMode) {
  602. this.filteringMode = filteringMode;
  603. }
  604. @Override
  605. public FilteringMode getFilteringMode() {
  606. return filteringMode;
  607. }
  608. @Override
  609. public void addBlurListener(BlurListener listener) {
  610. addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener,
  611. BlurListener.blurMethod);
  612. }
  613. /**
  614. * @deprecated As of 7.0, replaced by {@link #addBlurListener(BlurListener)}
  615. **/
  616. @Override
  617. @Deprecated
  618. public void addListener(BlurListener listener) {
  619. addBlurListener(listener);
  620. }
  621. @Override
  622. public void removeBlurListener(BlurListener listener) {
  623. removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener);
  624. }
  625. /**
  626. * @deprecated As of 7.0, replaced by
  627. * {@link #removeBlurListener(BlurListener)}
  628. **/
  629. @Override
  630. @Deprecated
  631. public void removeListener(BlurListener listener) {
  632. removeBlurListener(listener);
  633. }
  634. @Override
  635. public void addFocusListener(FocusListener listener) {
  636. addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener,
  637. FocusListener.focusMethod);
  638. }
  639. /**
  640. * @deprecated As of 7.0, replaced by
  641. * {@link #addFocusListener(FocusListener)}
  642. **/
  643. @Override
  644. @Deprecated
  645. public void addListener(FocusListener listener) {
  646. addFocusListener(listener);
  647. }
  648. @Override
  649. public void removeFocusListener(FocusListener listener) {
  650. removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener);
  651. }
  652. /**
  653. * @deprecated As of 7.0, replaced by
  654. * {@link #removeFocusListener(FocusListener)}
  655. **/
  656. @Override
  657. @Deprecated
  658. public void removeListener(FocusListener listener) {
  659. removeFocusListener(listener);
  660. }
  661. /**
  662. * ComboBox does not support multi select mode.
  663. *
  664. * @deprecated As of 7.0, use {@link ListSelect}, {@link OptionGroup} or
  665. * {@link TwinColSelect} instead
  666. * @see com.vaadin.ui.AbstractSelect#setMultiSelect(boolean)
  667. * @throws UnsupportedOperationException
  668. * if trying to activate multiselect mode
  669. */
  670. @Deprecated
  671. @Override
  672. public void setMultiSelect(boolean multiSelect) {
  673. if (multiSelect) {
  674. throw new UnsupportedOperationException("Multiselect not supported");
  675. }
  676. }
  677. /**
  678. * ComboBox does not support multi select mode.
  679. *
  680. * @deprecated As of 7.0, use {@link ListSelect}, {@link OptionGroup} or
  681. * {@link TwinColSelect} instead
  682. *
  683. * @see com.vaadin.ui.AbstractSelect#isMultiSelect()
  684. *
  685. * @return false
  686. */
  687. @Deprecated
  688. @Override
  689. public boolean isMultiSelect() {
  690. return false;
  691. }
  692. /**
  693. * Sets whether to scroll the selected item visible (directly open the page
  694. * on which it is) when opening the combo box popup or not. Only applies to
  695. * single select mode.
  696. *
  697. * This requires finding the index of the item, which can be expensive in
  698. * many large lazy loading containers.
  699. *
  700. * @param scrollToSelectedItem
  701. * true to find the page with the selected item when opening the
  702. * selection popup
  703. */
  704. public void setScrollToSelectedItem(boolean scrollToSelectedItem) {
  705. this.scrollToSelectedItem = scrollToSelectedItem;
  706. }
  707. /**
  708. * Returns true if the select should find the page with the selected item
  709. * when opening the popup (single select combo box only).
  710. *
  711. * @see #setScrollToSelectedItem(boolean)
  712. *
  713. * @return true if the page with the selected item will be shown when
  714. * opening the popup
  715. */
  716. public boolean isScrollToSelectedItem() {
  717. return scrollToSelectedItem;
  718. }
  719. }