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 29KB

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