View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.myfaces.tobago.model;
21  
22  import javax.swing.tree.TreeNode;
23  import java.io.Serializable;
24  import java.util.ArrayList;
25  import java.util.Collections;
26  import java.util.HashSet;
27  import java.util.Set;
28  
29  /**
30   * Manages the expanded state of an tree.
31   *
32   * @since 2.0.0
33   */
34  public class ExpandedState implements Serializable {
35  
36    private int defaultExpandedLevels;
37    private Set<TreePath> expandedSet;
38    private Set<TreePath> collapsedSet;
39  
40    /**
41     * Creates a new state object to store which nodes of a tree are expanded and collapsed in a view.
42     *
43     * @param defaultExpandedLevels All nodes up to this level are expanded by default.
44     */
45    public ExpandedState(final int defaultExpandedLevels) {
46      this.defaultExpandedLevels = defaultExpandedLevels;
47      this.expandedSet = new HashSet<TreePath>();
48      this.collapsedSet = new HashSet<TreePath>();
49    }
50  
51    /**
52     * Checks if a node is expanded.
53     *
54     * @param node The node to check.
55     * @return Is the node expanded?
56     */
57    public boolean isExpanded(final TreeNode node) {
58      final TreePath path = new TreePath(node);
59      return isExpanded(path);
60    }
61  
62    /**
63     * Checks if a node is expanded.
64     *
65     * @param path The path of the node to check.
66     * @return Is the node behind this path is expanded?
67     */
68    public boolean isExpanded(final TreePath path) {
69      if (expandedSet.contains(path)) {
70        return true;
71      }
72      if (collapsedSet.contains(path)) {
73        return false;
74      }
75      return path.getLength() < defaultExpandedLevels;
76    }
77  
78    /**
79     * Expands a single node.
80     *
81     * @param node The node to expand. Also the parents will be expanded since Tobago 3.0.0.
82     */
83    public void expand(final TreeNode node) {
84      expand(node, true);
85    }
86  
87    /**
88     * Expands a single node.
89     *
90     * @param node The node to expand.
91     * @param parents Should the parents also be expanded?
92     */
93    public void expand(final TreeNode node, final boolean parents) {
94      final TreePath path = new TreePath(node);
95      expand(path, parents);
96    }
97  
98    /**
99     * Expands a single node.
100    *
101    * @param path The path of the node to expand. Also the parents will be expanded since Tobago 3.0.0.
102    */
103   public void expand(final TreePath path) {
104     expand(path, true);
105   }
106 
107   /**
108    * Expands a single node.
109    *
110    * @param path The path of the node to expand.
111    * @param parents Should the parents also be expanded?
112    */
113   public void expand(final TreePath path, final boolean parents) {
114     if (path.getLength() >= defaultExpandedLevels) {
115       expandedSet.add(path);
116     } else {
117       collapsedSet.remove(path);
118     }
119     if (parents && !path.isRoot()) {
120       expand(path.getParent(), true);
121     }
122   }
123 
124   /**
125    * Expands all nodes that level are lower or equals the parameter level.
126    *
127    * @param level The level to expand.
128    */
129   public void expand(final int level) {
130     final ArrayList<TreePath> toRemove = new ArrayList<TreePath>();
131     if (level > defaultExpandedLevels) {
132       defaultExpandedLevels = level;
133       for (final TreePath treePath : expandedSet) {
134         if (treePath.getLength() < defaultExpandedLevels) {
135           toRemove.add(treePath);
136         }
137       }
138       expandedSet.removeAll(toRemove);
139       collapsedSet.clear();
140     } else {
141       for (final TreePath treePath : collapsedSet) {
142         if (treePath.getLength() < level) {
143           toRemove.add(treePath);
144         }
145       }
146       collapsedSet.removeAll(toRemove);
147     }
148   }
149 
150   /**
151    * Expands a nodes of the tree.
152    */
153   public void expandAll() {
154     defaultExpandedLevels = Integer.MAX_VALUE;
155     expandedSet.clear();
156     collapsedSet.clear();
157   }
158 
159   /**
160    * Collapses a single node.
161    *
162    * @param node The node to collapse.
163    */
164   public void collapse(final TreeNode node) {
165     final TreePath path = new TreePath(node);
166     collapse(path);
167   }
168 
169   /**
170    * Collapses a single node.
171    *
172    * @param path The path of the node to collapse.
173    */
174   public void collapse(final TreePath path) {
175     if (path.getLength() < defaultExpandedLevels) {
176       collapsedSet.add(path);
177     } else {
178       expandedSet.remove(path);
179     }
180   }
181 
182   /**
183    * Collapses all nodes that level are higher or equals the parameter level.
184    *
185    * @param level The level to expand.
186    */
187   public void collapse(int level) {
188     // to use a symmetric algorithm like in expand
189     level--;
190 
191     final ArrayList<TreePath> toRemove = new ArrayList<TreePath>();
192     if (level < defaultExpandedLevels) {
193       defaultExpandedLevels = level;
194       for (final TreePath treePath : collapsedSet) {
195         if (treePath.getLength() >= defaultExpandedLevels) {
196           toRemove.add(treePath);
197         }
198       }
199       collapsedSet.removeAll(toRemove);
200       expandedSet.clear();
201     } else {
202       for (final TreePath treePath : expandedSet) {
203         if (treePath.getLength() >= level) {
204           toRemove.add(treePath);
205         }
206       }
207       expandedSet.removeAll(toRemove);
208     }
209   }
210 
211   /**
212    * Collapses a nodes of the tree.
213    */
214   public void collapseAll() {
215     defaultExpandedLevels = 0;
216     expandedSet.clear();
217     collapsedSet.clear();
218   }
219 
220   /**
221    * Collapses a nodes of the tree. The root node will be expanded.
222    */
223   public void collapseAllButRoot() {
224     defaultExpandedLevels = 1;
225     expandedSet.clear();
226     collapsedSet.clear();
227   }
228 
229   /**
230    * Resets the state to the defaults. After this call, the nodes with level smaller than defaultExpandedLevels
231    * are expanded, the other ones are collapsed.
232    */
233   public void reset() {
234     expandedSet.clear();
235     collapsedSet.clear();
236   }
237 
238   /**
239    * @return A unmodifiable set of paths of the expanded nodes.
240    */
241   public Set<TreePath> getExpandedSet() {
242     return Collections.unmodifiableSet(expandedSet);
243   }
244 
245   /**
246    * @return A unmodifiable set of paths of the collapsed nodes.
247    */
248   public Set<TreePath> getCollapsedSet() {
249     return Collections.unmodifiableSet(collapsedSet);
250   }
251 }