View Javadoc

1   package org.catacomb.druid.swing;
2   
3   import javax.swing.tree.*;
4   
5   import java.util.Stack;
6   import java.util.ArrayList;
7   
8   
9   public class CheckTreeSelectionModel extends DefaultTreeSelectionModel {
10      private static final long serialVersionUID = 1L;
11  
12      private TreeModel model;
13  
14  
15      public CheckTreeSelectionModel(TreeModel model) {
16          this.model = model;
17          setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
18      }
19  
20  
21      // tests whether there is any unselected node in the subtree of given path
22      public boolean isPartiallySelected(TreePath path) {
23          if (isPathSelected(path, true)) {
24              return false;
25          }
26          TreePath[] selectionPaths = getSelectionPaths();
27          if (selectionPaths == null) {
28              return false;
29          }
30  
31          for (int j = 0; j < selectionPaths.length; j++) {
32              if (isDescendant(selectionPaths[j], path)) {
33                  return true;
34              }
35          }
36          return false;
37      }
38  
39  
40      // tells whether given path is selected.
41      // if dig is true, then a path is assumed to be selected, if
42      // one of its ancestor is selected.
43      public boolean isPathSelected(TreePath pathin, boolean dig) {
44          TreePath path = pathin;
45          if (!dig) {
46              return super.isPathSelected(path);
47          }
48          while (path != null && !super.isPathSelected(path)) {
49              path = path.getParentPath();
50          }
51          return path != null;
52      }
53  
54  
55      // is path1 descendant of path2
56      private boolean isDescendant(TreePath path1, TreePath path2) {
57          Object obj1[] = path1.getPath();
58          Object obj2[] = path2.getPath();
59          for (int i = 0; i < obj2.length; i++) {
60              if (obj1[i] != obj2[i]) {
61                  return false;
62              }
63          }
64          return true;
65      }
66  
67  
68      public void setSelectionPaths(TreePath[] pPaths) {
69  //      E.info("set sel paths? " + pPaths.length);
70      }
71  
72  
73      public void addSelectionPaths(TreePath[] paths) {
74          // unselect all descendants of paths[]
75          for (int i = 0; i < paths.length; i++) {
76  
77              TreePath path = paths[i];
78  
79              TreePath[] selectionPaths = getSelectionPaths();
80              if (selectionPaths == null) {
81                  break;
82              }
83              ArrayList<Object> toBeRemoved = new ArrayList<Object>();
84              for (int j = 0; j < selectionPaths.length; j++) {
85                  if (isDescendant(selectionPaths[j], path)) {
86                      toBeRemoved.add(selectionPaths[j]);
87                  }
88              }
89              super.removeSelectionPaths(toBeRemoved.toArray(new TreePath[0]));
90          }
91  
92          // if all siblings are selected then unselect them and select parent
93          // recursively
94          // otherwize just select that path.
95          for (int i = 0; i < paths.length; i++) {
96              TreePath path = paths[i];
97              TreePath temp = null;
98              while (areSiblingsSelected(path)) {
99                  temp = path;
100                 if (path.getParentPath() == null) {
101                     break;
102                 }
103                 path = path.getParentPath();
104             }
105             if (temp != null) {
106                 if (temp.getParentPath() != null) {
107                     addSelectionPath(temp.getParentPath());
108                 } else {
109                     if (!isSelectionEmpty()) {
110                         removeSelectionPaths(getSelectionPaths());
111                     }
112                     super.addSelectionPaths(new TreePath[] { temp });
113                 }
114             } else {
115                 super.addSelectionPaths(new TreePath[] { path });
116             }
117         }
118     }
119 
120 
121     // tells whether all siblings of given path are selected.
122     private boolean areSiblingsSelected(TreePath path) {
123         TreePath parent = path.getParentPath();
124         if (parent == null) {
125             return true;
126         }
127         Object node = path.getLastPathComponent();
128         Object parentNode = parent.getLastPathComponent();
129 
130         int childCount = model.getChildCount(parentNode);
131         for (int i = 0; i < childCount; i++) {
132             Object childNode = model.getChild(parentNode, i);
133             if (childNode == node) {
134                 continue;
135             }
136             if (!isPathSelected(parent.pathByAddingChild(childNode))) {
137                 return false;
138             }
139         }
140         return true;
141     }
142 
143 
144     public void removeSelectionPaths(TreePath[] paths) {
145         for (int i = 0; i < paths.length; i++) {
146             TreePath path = paths[i];
147             if (path.getPathCount() == 1) {
148                 super.removeSelectionPaths(new TreePath[] { path });
149             } else {
150                 toggleRemoveSelection(path);
151             }
152         }
153     }
154 
155 
156     // if any ancestor node of given path is selected then unselect it
157     // and selection all its descendants except given path and descendants.
158     // otherwise just unselect the given path
159     private void toggleRemoveSelection(TreePath path) {
160         Stack<Object> stack = new Stack<Object>();
161         TreePath parent = path.getParentPath();
162         while (parent != null && !isPathSelected(parent)) {
163             stack.push(parent);
164             parent = parent.getParentPath();
165         }
166         if (parent != null)
167             stack.push(parent);
168         else {
169             super.removeSelectionPaths(new TreePath[] { path });
170             return;
171         }
172 
173         while (!stack.isEmpty()) {
174             TreePath temp = (TreePath)stack.pop();
175             TreePath peekPath = stack.isEmpty() ? path : (TreePath)stack.peek();
176             Object node = temp.getLastPathComponent();
177             Object peekNode = peekPath.getLastPathComponent();
178             int childCount = model.getChildCount(node);
179             for (int i = 0; i < childCount; i++) {
180                 Object childNode = model.getChild(node, i);
181                 if (childNode != peekNode)
182                     super.addSelectionPaths(new TreePath[] { temp.pathByAddingChild(childNode) });
183             }
184         }
185         super.removeSelectionPaths(new TreePath[] { parent });
186     }
187 
188 
189     public ArrayList<TreePath> getDescendantPaths(TreePath tp) {
190         ArrayList<TreePath> tps = new ArrayList<TreePath>();
191         appendDescendantPaths(tps, tp);
192         return tps;
193     }
194 
195     private void appendDescendantPaths(ArrayList<TreePath> atp , TreePath tp) {
196         Object lc = tp.getLastPathComponent();
197         if (model.isLeaf(lc)) {
198             atp.add(tp);
199         } else {
200             for (int i = 0; i < model.getChildCount(lc); i++) {
201                 Object oc = model.getChild(lc, i);
202                 TreePath ctp = tp.pathByAddingChild(oc);
203                 appendDescendantPaths(atp, ctp);
204             }
205         }
206     }
207 }