Guest User

Untitled

a guest
Oct 21st, 2017
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.89 KB | None | 0 0
  1. import java.util.ArrayList;
  2. import java.util.Collection;
  3. import java.util.Iterator;
  4. import java.util.LinkedList;
  5. import java.util.List;
  6.  
  7. /**
  8. * Utility structure to represent expandable list.
  9. */
  10. public class ExpandableList<T> implements Iterable<ExpandableList.Node<T>> {
  11.  
  12. /**
  13. * List of parent nodes attached to this list
  14. */
  15. private final List<Node<T>> directNodes = new LinkedList<>();
  16. /**
  17. * All nodes in the list (actual list)
  18. */
  19. private final List<Node<T>> nodes = new LinkedList<>();
  20.  
  21. private final Observer<T> nodeObserver = new Observer<T>() {
  22. @Override
  23. public void onChanged(Node<T> node) {
  24. invalidate();
  25. notifyObservers(node);
  26. }
  27. };
  28. private final List<Observer<T>> observers = new ArrayList<>(0);
  29.  
  30. public ExpandableList() {
  31. }
  32.  
  33. public ExpandableList(Collection<Node<T>> nodes) {
  34. directNodes.addAll(nodes);
  35. invalidate();
  36. }
  37.  
  38. /**
  39. * Add parent node to this tree.
  40. *
  41. * @param node node
  42. * @return count of nodes added to current list
  43. */
  44. public int add(Node<T> node) {
  45. return add(directNodes.size(), node);
  46. }
  47.  
  48. /**
  49. * Add parent node to this tree.
  50. *
  51. * @param index index at which the node is to be inserted
  52. * @param node node
  53. * @return count of nodes added to current list
  54. */
  55. public int add(int index, Node<T> node) {
  56. if (directNodes.indexOf(node) != -1) {
  57. return 0;
  58. }
  59. try {
  60. directNodes.add(index, node);
  61. node.addObserver(nodeObserver);
  62. return addInternal(node);
  63. } finally {
  64. notifyObservers(node);
  65. }
  66. }
  67.  
  68. /**
  69. * Remove parent node from this tree.
  70. *
  71. * @param node node
  72. * @return count of nodes removed from the current list
  73. */
  74. public int remove(Node<T> node) {
  75. if (!directNodes.remove(node)) {
  76. return 0;
  77. }
  78. try {
  79. node.removeObserver(nodeObserver);
  80. return removeInternal(node);
  81. } finally {
  82. notifyObservers(node);
  83. }
  84. }
  85.  
  86. /**
  87. * Expand parent node.
  88. *
  89. * @param node node
  90. * @return count of nodes added to the current list (returns {@code 0} if parent was already expanded)
  91. */
  92. public int expand(Node<T> node) {
  93. if (!node.isExpanded()) {
  94. try {
  95. int old = nodes.size();
  96. node.setExpanded(true);
  97. return nodes.size() - old;
  98. } finally {
  99. notifyObservers(node);
  100. }
  101. }
  102. return 0;
  103. }
  104.  
  105. /**
  106. * Collapse parent node.
  107. *
  108. * @param node node
  109. * @return count of nodes removed from the current list (returns {@code 0} if parent was already collapsed)
  110. */
  111. public int collapse(Node<T> node) {
  112. if (node.isExpanded()) {
  113. try {
  114. int old = nodes.size();
  115. node.setExpanded(false);
  116. return old - nodes.size();
  117. } finally {
  118. notifyObservers(node);
  119. }
  120. }
  121. return 0;
  122. }
  123.  
  124. /**
  125. * Collapse all parent nodes.
  126. */
  127. public void collapseAll() {
  128. expandNodes(false);
  129. }
  130.  
  131. /**
  132. * Expand all parent nodes.
  133. */
  134. public void expandAll() {
  135. expandNodes(true);
  136. }
  137.  
  138. /**
  139. * Retrieve a payload for the node at {@code index}.
  140. *
  141. * @param index index of node to get payload from
  142. * @return payload of node at {@code index}
  143. */
  144. public T getPayload(int index) {
  145. return getNode(index).getPayload();
  146. }
  147.  
  148. /**
  149. * Get list node at {@code index}.
  150. *
  151. * @param index [0, {@link #listSize()})
  152. * @return node at {@code index}
  153. */
  154. public Node<T> getNode(int index) {
  155. return nodes.get(index);
  156. }
  157.  
  158. /**
  159. * Get parent at {@code index}.
  160. *
  161. * @param index [0; {@link #parentsSize()})
  162. * @return parent at {@code index}
  163. */
  164. public Node<T> getParent(int index) {
  165. return directNodes.get(index);
  166. }
  167.  
  168. /**
  169. * Index of parent node in parent's list.
  170. *
  171. * @param parent parent
  172. * @return index of parent
  173. * @see #parentsSize()
  174. * @see #getParent(int)
  175. */
  176. public int indexOfParent(Node<T> parent) {
  177. return directNodes.indexOf(parent);
  178. }
  179.  
  180. /**
  181. * Get index of node within list.
  182. *
  183. * @param node node
  184. * @return index of node
  185. * @see #listSize()
  186. * @see #getNode(int)
  187. */
  188. public int indexOf(Node<T> node) {
  189. return nodes.indexOf(node);
  190. }
  191.  
  192. /**
  193. * @return total number of parents in this tree
  194. */
  195. public int parentsSize() {
  196. return directNodes.size();
  197. }
  198.  
  199. /**
  200. * @return total number of list nodes in current state
  201. */
  202. public int listSize() {
  203. return nodes.size();
  204. }
  205.  
  206. /**
  207. * @return total number of all nodes (including collapsed)
  208. */
  209. public int absoluteSize() {
  210. return computeAbsoluteSize();
  211. }
  212.  
  213. /**
  214. * Invalidate tree to recalculate list content and positions.
  215. * This can be used if some of parents have been changed manually.
  216. */
  217. public void invalidate() {
  218. nodes.clear();
  219. for (Node<T> parent : directNodes) {
  220. addInternal(parent);
  221. }
  222. }
  223.  
  224. @Override
  225. public Iterator<Node<T>> iterator() {
  226. return nodes.iterator();
  227. }
  228.  
  229. ///////////////////////////////////////////////////////////////////////////
  230. // Observers
  231. ///////////////////////////////////////////////////////////////////////////
  232.  
  233. public void addObserver(Observer<T> observer) {
  234. if (observers.indexOf(observer) == -1) {
  235. observers.add(observers.size(), observer);
  236. }
  237. }
  238.  
  239. public void removeObserver(Observer<T> observer) {
  240. observers.remove(observer);
  241. }
  242.  
  243. public interface Observer<T> {
  244. void onChanged(Node<T> node);
  245. }
  246.  
  247. ///////////////////////////////////////////////////////////////////////////
  248. // Internal
  249. ///////////////////////////////////////////////////////////////////////////
  250.  
  251. private int addInternal(Node<T> node) {
  252. nodes.add(node);
  253. int count = 1;
  254. if (!node.expanded) {
  255. return count;
  256. }
  257. for (Node<T> child : node.children) {
  258. count += addInternal(child);
  259. }
  260. return count;
  261. }
  262.  
  263. private int removeInternal(Node<T> node) {
  264. nodes.remove(node);
  265. int count = 1;
  266. if (!node.expanded) {
  267. return count;
  268. }
  269. for (Node<T> child : node.children) {
  270. count += removeInternal(child);
  271. }
  272. return count;
  273. }
  274.  
  275. private int computeAbsoluteSize() {
  276. int count = 0;
  277. for (Node<T> node : directNodes) {
  278. count += node.internalSize();
  279. }
  280. return count;
  281. }
  282.  
  283. private void notifyObservers(Node<T> node) {
  284. for (int i = observers.size() - 1; i >= 0; i--) {
  285. observers.get(i).onChanged(node);
  286. }
  287. }
  288.  
  289. private void expandNodes(boolean expanded) {
  290. for (Node<T> node : directNodes) {
  291. node.setExpanded(expanded);
  292. }
  293. }
  294.  
  295. ///////////////////////////////////////////////////////////////////////////
  296. // Node
  297. ///////////////////////////////////////////////////////////////////////////
  298.  
  299. /**
  300. * List node
  301. */
  302. public static class Node<T> implements Observer<T> {
  303.  
  304. private T payload;
  305.  
  306. private Node<T> parent = null;
  307. private boolean expanded = false;
  308. private final List<Node<T>> children = new LinkedList<>();
  309.  
  310. private final List<Observer<T>> observers = new ArrayList<>(0);
  311.  
  312. /**
  313. * Construct a new node with empty payload.
  314. */
  315. public Node() {
  316. }
  317.  
  318. /**
  319. * Construct a new node with given payload.
  320. *
  321. * @param payload payload
  322. */
  323. public Node(T payload) {
  324. setPayload(payload);
  325. }
  326.  
  327. /**
  328. * Expand or collapse node.
  329. *
  330. * @param expanded new state
  331. */
  332. public void setExpanded(boolean expanded) {
  333. if (this.expanded != expanded) {
  334. this.expanded = expanded;
  335. if (!children.isEmpty()) {
  336. onChanged(this);
  337. }
  338. }
  339. }
  340.  
  341. /**
  342. * Detach this node from the parent.
  343. */
  344. public boolean detach() {
  345. return parent != null && parent.remove(this);
  346. }
  347.  
  348. /**
  349. * Add child to node.
  350. * If node is attached to a tree, it's required to call {@link #invalidate()} to update tree state.
  351. *
  352. * @param child child node
  353. */
  354. public void add(Node<T> child) {
  355. add(children.size(), child);
  356. }
  357.  
  358.  
  359. /**
  360. * Add child to node.
  361. * If node is attached to a tree, it's required to call {@link #invalidate()} to update tree state.
  362. *
  363. * @param index index at which child is to be insterted
  364. * @param child child node
  365. */
  366. public void add(int index, Node<T> child) {
  367. if (child.parent != this) {
  368. children.add(index, child);
  369. child.parent = this;
  370. child.addObserver(this);
  371. onChanged(this);
  372. }
  373. }
  374.  
  375. /**
  376. * Remove child from node.
  377. *
  378. * @param child child node
  379. */
  380. private boolean remove(Node<T> child) {
  381. if (removeInternal(child)) {
  382. onChanged(this);
  383. return true;
  384. }
  385. return false;
  386. }
  387.  
  388. /**
  389. * Remove all child nodes.
  390. */
  391. public void removeChildren() {
  392. if (!children.isEmpty()) {
  393. for (int i = children.size() - 1; i >= 0; i--) {
  394. removeInternal(children.get(i));
  395. }
  396. onChanged(this);
  397. }
  398. }
  399.  
  400. /**
  401. * Get index of child in parent.
  402. *
  403. * @param child node
  404. * @return index of {@code child}, or {@code -1} if not found in parent's list
  405. */
  406. public int indexOf(Node<T> child) {
  407. if (child == this || child.parent != this) {
  408. return -1;
  409. }
  410. return children.indexOf(child);
  411. }
  412.  
  413. /**
  414. * Get current node state.
  415. *
  416. * @return current state
  417. */
  418. public boolean isExpanded() {
  419. return expanded;
  420. }
  421.  
  422. /**
  423. * @return the parent of this node. Can be {@link null} if node has no parent.
  424. */
  425. public Node<T> getParent() {
  426. return parent;
  427. }
  428.  
  429. /**
  430. * Set node payload.
  431. *
  432. * @param payload new payload
  433. */
  434. public void setPayload(T payload) {
  435. this.payload = payload;
  436. }
  437.  
  438. /**
  439. * Get node payload.
  440. *
  441. * @return node payload
  442. */
  443. public T getPayload() {
  444. return payload;
  445. }
  446.  
  447. public int getParentIndex() {
  448. return parent != null ? parent.indexOf(this) : -1;
  449. }
  450.  
  451. /**
  452. * Get child node by index.
  453. *
  454. * @param index index of node to get
  455. * @return node at {@code index}
  456. */
  457. public Node<T> getChild(int index) {
  458. return children.get(index);
  459. }
  460.  
  461. /**
  462. * @return count of child nodes
  463. */
  464. public int getChildCount() {
  465. return children.size();
  466. }
  467.  
  468. /**
  469. * @return internal size of the node, including nested
  470. */
  471. public int internalSize() {
  472. int count = 1;
  473. for (Node<T> child : children) {
  474. count += child.internalSize();
  475. }
  476. return count;
  477. }
  478.  
  479. ///////////////////////////////////////////////////////////////////////////
  480. // Internal
  481. ///////////////////////////////////////////////////////////////////////////
  482.  
  483. private boolean removeInternal(Node<T> child) {
  484. if (children.remove(child)) {
  485. child.removeObserver(this);
  486. child.parent = null;
  487. return true;
  488. }
  489. return false;
  490. }
  491.  
  492. ///////////////////////////////////////////////////////////////////////////
  493. // NodeObserver
  494. ///////////////////////////////////////////////////////////////////////////
  495.  
  496. public void addObserver(Observer<T> observer) {
  497. if (observers.indexOf(observer) == -1) {
  498. observers.add(observers.size(), observer);
  499. }
  500. }
  501.  
  502. public void removeObserver(Observer<T> observer) {
  503. observers.remove(observer);
  504. }
  505.  
  506. @Override
  507. public void onChanged(Node<T> node) {
  508. for (int i = observers.size() - 1; i >= 0; i--) {
  509. observers.get(i).onChanged(node);
  510. }
  511. }
  512. }
  513.  
  514. }
Add Comment
Please, Sign In to add comment