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.

Tree.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. /*
  2. * Copyright 2000-2016 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.Collection;
  18. import java.util.HashMap;
  19. import java.util.HashSet;
  20. import java.util.Map;
  21. import java.util.Objects;
  22. import java.util.Set;
  23. import com.vaadin.data.Binder;
  24. import com.vaadin.data.HasDataProvider;
  25. import com.vaadin.data.SelectionModel;
  26. import com.vaadin.data.provider.DataGenerator;
  27. import com.vaadin.data.provider.DataProvider;
  28. import com.vaadin.data.provider.HierarchicalDataProvider;
  29. import com.vaadin.event.CollapseEvent;
  30. import com.vaadin.event.CollapseEvent.CollapseListener;
  31. import com.vaadin.event.ExpandEvent;
  32. import com.vaadin.event.ExpandEvent.ExpandListener;
  33. import com.vaadin.event.selection.SelectionListener;
  34. import com.vaadin.server.Resource;
  35. import com.vaadin.shared.Registration;
  36. import com.vaadin.shared.ui.grid.HeightMode;
  37. import com.vaadin.shared.ui.tree.TreeRendererState;
  38. import com.vaadin.ui.Grid.SelectionMode;
  39. import com.vaadin.ui.renderers.AbstractRenderer;
  40. import elemental.json.JsonObject;
  41. /**
  42. * Tree component. A Tree can be used to select an item from a hierarchical set
  43. * of items.
  44. *
  45. * @author Vaadin Ltd
  46. * @since 8.1
  47. *
  48. * @param <T>
  49. * the data type
  50. */
  51. public class Tree<T> extends Composite implements HasDataProvider<T> {
  52. /**
  53. * String renderer that handles icon resources and stores their identifiers
  54. * into data objects.
  55. *
  56. * @since 8.1
  57. */
  58. public final class TreeRenderer extends AbstractRenderer<T, String>
  59. implements DataGenerator<T> {
  60. /**
  61. * Constructs a new TreeRenderer.
  62. */
  63. protected TreeRenderer() {
  64. super(String.class);
  65. }
  66. private Map<T, String> resourceKeyMap = new HashMap<>();
  67. private int counter = 0;
  68. @Override
  69. public void generateData(T item, JsonObject jsonObject) {
  70. Resource resource = iconProvider.apply(item);
  71. if (resource == null) {
  72. destroyData(item);
  73. return;
  74. }
  75. if (!resourceKeyMap.containsKey(item)) {
  76. resourceKeyMap.put(item, "icon" + (counter++));
  77. }
  78. setResource(resourceKeyMap.get(item), resource);
  79. jsonObject.put("itemIcon", resourceKeyMap.get(item));
  80. }
  81. @Override
  82. public void destroyData(T item) {
  83. if (resourceKeyMap.containsKey(item)) {
  84. setResource(resourceKeyMap.get(item), null);
  85. resourceKeyMap.remove(item);
  86. }
  87. }
  88. @Override
  89. public void destroyAllData() {
  90. Set<T> keys = new HashSet<>(resourceKeyMap.keySet());
  91. for (T key : keys) {
  92. destroyData(key);
  93. }
  94. }
  95. @Override
  96. protected TreeRendererState getState() {
  97. return (TreeRendererState) super.getState();
  98. }
  99. @Override
  100. protected TreeRendererState getState(boolean markAsDirty) {
  101. return (TreeRendererState) super.getState(markAsDirty);
  102. }
  103. }
  104. private TreeGrid<T> treeGrid = new TreeGrid<>();
  105. private ItemCaptionGenerator<T> captionGenerator = String::valueOf;
  106. private IconGenerator<T> iconProvider = t -> null;
  107. /**
  108. * Constructs a new Tree Component.
  109. */
  110. public Tree() {
  111. setCompositionRoot(treeGrid);
  112. TreeRenderer renderer = new TreeRenderer();
  113. treeGrid.getDataCommunicator().addDataGenerator(renderer);
  114. treeGrid.addColumn(i -> captionGenerator.apply(i), renderer)
  115. .setId("column");
  116. treeGrid.setHierarchyColumn("column");
  117. while (treeGrid.getHeaderRowCount() > 0) {
  118. treeGrid.removeHeaderRow(0);
  119. }
  120. treeGrid.setPrimaryStyleName("v-tree8");
  121. setWidth("100%");
  122. treeGrid.setHeightUndefined();
  123. treeGrid.setHeightMode(HeightMode.UNDEFINED);
  124. treeGrid.addExpandListener(e -> fireExpandEvent(e.getExpandedItem(),
  125. e.isUserOriginated()));
  126. treeGrid.addCollapseListener(e -> fireCollapseEvent(
  127. e.getCollapsedItem(), e.isUserOriginated()));
  128. }
  129. /**
  130. * Constructs a new Tree Component.
  131. *
  132. * @param caption
  133. * the caption for component
  134. */
  135. public Tree(String caption) {
  136. this();
  137. setCaption(caption);
  138. }
  139. @Override
  140. public HierarchicalDataProvider<T, ?> getDataProvider() {
  141. return treeGrid.getDataProvider();
  142. }
  143. @Override
  144. public void setDataProvider(DataProvider<T, ?> dataProvider) {
  145. treeGrid.setDataProvider(dataProvider);
  146. }
  147. /**
  148. * Adds an ExpandListener to this Tree.
  149. *
  150. * @see ExpandEvent
  151. *
  152. * @param listener
  153. * the listener to add
  154. * @return a registration for the listener
  155. */
  156. public Registration addExpandListener(ExpandListener<T> listener) {
  157. return addListener(ExpandEvent.class, listener,
  158. ExpandListener.EXPAND_METHOD);
  159. }
  160. /**
  161. * Adds a CollapseListener to this Tree.
  162. *
  163. * @see CollapseEvent
  164. *
  165. * @param listener
  166. * the listener to add
  167. * @return a registration for the listener
  168. */
  169. public Registration addCollapseListener(CollapseListener<T> listener) {
  170. return addListener(CollapseEvent.class, listener,
  171. CollapseListener.COLLAPSE_METHOD);
  172. }
  173. /**
  174. * Fires an expand event with given item.
  175. *
  176. * @param item
  177. * the expanded item
  178. * @param userOriginated
  179. * whether the expand was triggered by a user interaction or the
  180. * server
  181. */
  182. protected void fireExpandEvent(T item, boolean userOriginated) {
  183. fireEvent(new ExpandEvent<>(this, item, userOriginated));
  184. }
  185. /**
  186. * Fires a collapse event with given item.
  187. *
  188. * @param item
  189. * the collapsed item
  190. * @param userOriginated
  191. * whether the collapse was triggered by a user interaction or
  192. * the server
  193. */
  194. protected void fireCollapseEvent(T item, boolean userOriginated) {
  195. fireEvent(new CollapseEvent<>(this, item, userOriginated));
  196. }
  197. /**
  198. * Expands the given items.
  199. * <p>
  200. * If an item is currently expanded, does nothing. If an item does not have
  201. * any children, does nothing.
  202. *
  203. * @param items
  204. * the items to expand
  205. */
  206. public void expand(T... items) {
  207. treeGrid.expand(items);
  208. }
  209. /**
  210. * Expands the given items.
  211. * <p>
  212. * If an item is currently expanded, does nothing. If an item does not have
  213. * any children, does nothing.
  214. *
  215. * @param items
  216. * the items to expand
  217. */
  218. public void expand(Collection<T> items) {
  219. treeGrid.expand(items);
  220. }
  221. /**
  222. * Collapse the given items.
  223. * <p>
  224. * For items that are already collapsed, does nothing.
  225. *
  226. * @param items
  227. * the collection of items to collapse
  228. */
  229. public void collapse(T... items) {
  230. treeGrid.collapse(items);
  231. }
  232. /**
  233. * Collapse the given items.
  234. * <p>
  235. * For items that are already collapsed, does nothing.
  236. *
  237. * @param items
  238. * the collection of items to collapse
  239. */
  240. public void collapse(Collection<T> items) {
  241. treeGrid.collapse(items);
  242. }
  243. /**
  244. * This method is a shorthand that delegates to the currently set selection
  245. * model.
  246. *
  247. * @see #getSelectionModel()
  248. *
  249. * @return set of selected items
  250. */
  251. public Set<T> getSelectedItems() {
  252. return treeGrid.getSelectedItems();
  253. }
  254. /**
  255. * This method is a shorthand that delegates to the currently set selection
  256. * model.
  257. *
  258. * @param item
  259. * item to select
  260. *
  261. * @see SelectionModel#select(Object)
  262. * @see #getSelectionModel()
  263. */
  264. public void select(T item) {
  265. treeGrid.select(item);
  266. }
  267. /**
  268. * This method is a shorthand that delegates to the currently set selection
  269. * model.
  270. *
  271. * @param item
  272. * item to deselect
  273. *
  274. * @see SelectionModel#deselect(Object)
  275. * @see #getSelectionModel()
  276. */
  277. public void deselect(T item) {
  278. treeGrid.deselect(item);
  279. }
  280. /**
  281. * Adds a selection listener to the current selection model.
  282. * <p>
  283. * <strong>NOTE:</strong> If selection mode is switched with
  284. * {@link setSelectionMode(SelectionMode)}, then this listener is not
  285. * triggered anymore when selection changes!
  286. *
  287. * @param listener
  288. * the listener to add
  289. * @return a registration handle to remove the listener
  290. *
  291. * @throws UnsupportedOperationException
  292. * if selection has been disabled with
  293. * {@link SelectionMode.NONE}
  294. */
  295. public Registration addSelectionListener(SelectionListener<T> listener) {
  296. return treeGrid.addSelectionListener(listener);
  297. }
  298. /**
  299. * Use this tree as a single select in {@link Binder}. Throws
  300. * {@link IllegalStateException} if the tree is not using
  301. * {@link SelectionMode#SINGLE}.
  302. *
  303. * @return the single select wrapper that can be used in binder
  304. */
  305. public SingleSelect<T> asSingleSelect() {
  306. return treeGrid.asSingleSelect();
  307. }
  308. /**
  309. * Returns the selection model for this Tree.
  310. *
  311. * @return the selection model, not <code>null</code>
  312. */
  313. public SelectionModel<T> getSelectionModel() {
  314. return treeGrid.getSelectionModel();
  315. }
  316. @Override
  317. public void setItems(Collection<T> items) {
  318. treeGrid.setItems(items);
  319. }
  320. /**
  321. * Sets the item caption generator that is used to produce the strings shown
  322. * as the text for each item. By default, {@link String#valueOf(Object)} is
  323. * used.
  324. *
  325. * @param captionGenerator
  326. * the item caption provider to use, not <code>null</code>
  327. */
  328. public void setItemCaptionGenerator(
  329. ItemCaptionGenerator<T> captionGenerator) {
  330. Objects.requireNonNull(captionGenerator,
  331. "Caption generator must not be null");
  332. this.captionGenerator = captionGenerator;
  333. treeGrid.getDataCommunicator().reset();
  334. }
  335. /**
  336. * Sets the item icon generator that is used to produce custom icons for
  337. * items. The generator can return <code>null</code> for items with no icon.
  338. *
  339. * @see IconGenerator
  340. *
  341. * @param iconGenerator
  342. * the item icon generator to set, not <code>null</code>
  343. * @throws NullPointerException
  344. * if {@code itemIconGenerator} is {@code null}
  345. */
  346. public void setItemIconGenerator(IconGenerator<T> iconGenerator) {
  347. Objects.requireNonNull(iconGenerator,
  348. "Item icon generator must not be null");
  349. this.iconProvider = iconGenerator;
  350. treeGrid.getDataCommunicator().reset();
  351. }
  352. /**
  353. * @deprecated This component's height is always set to be undefined.
  354. * Calling this method will have no effect.
  355. */
  356. @Override
  357. @Deprecated
  358. public void setHeight(String height) {
  359. }
  360. /**
  361. * @deprecated This component's height is always set to be undefined.
  362. * Calling this method will have no effect.
  363. */
  364. @Override
  365. @Deprecated
  366. public void setHeight(float height, Unit unit) {
  367. }
  368. /**
  369. * @deprecated This component's height is always set to be undefined.
  370. * Calling this method will have no effect.
  371. */
  372. @Override
  373. @Deprecated
  374. public void setHeightUndefined() {
  375. }
  376. @Override
  377. public void setCaption(String caption) {
  378. treeGrid.setCaption(caption);
  379. }
  380. @Override
  381. public String getCaption() {
  382. return treeGrid.getCaption();
  383. }
  384. @Override
  385. public void setIcon(Resource icon) {
  386. treeGrid.setIcon(icon);
  387. }
  388. @Override
  389. public Resource getIcon() {
  390. return treeGrid.getIcon();
  391. }
  392. }