View Javadoc

1   package org.catacomb.druid.util.tree;
2   
3   import org.catacomb.interlish.structure.*;
4   import org.catacomb.report.E;
5   
6   
7   import java.util.ArrayList;
8   import java.util.HashMap;
9   import java.util.HashSet;
10  import java.util.ListIterator;
11  
12  
13  public class RelationTree implements PivotedTree {
14  
15  
16      ArrayListNode rootNode;
17  
18      HashMap<Related, RelationNode> peers;
19  
20      HashSet<String> relationTypes;
21  
22      String[][] pivotOrders;
23  
24      String[] pivotNames;
25  
26  
27      int iPivot;
28  
29      int rootPolicy = Tree.AUTO_ROOT;
30  
31      TreeChangeReporter tcReporter;
32  
33  
34  
35      public RelationTree(ArrayList<Related> coll) {
36          init(coll);
37          setDefaultPivotOrders();
38          build(0);
39      }
40  
41  
42      public RelationTree(SingleParent sp) {
43          ArrayList<Related> coll = Trawler.trawlChildren(sp);
44          init(coll);
45          setDefaultPivotOrders();
46          build(0);
47      }
48  
49  
50      public TreeNode getRoot() {
51          return rootNode;
52      }
53  
54  
55      public void setRootPolicy(int ipol) {
56          rootPolicy = ipol;
57      }
58  
59  
60      public int getRootPolicy() {
61          return rootPolicy;
62      }
63  
64  
65      public String getPivotRelation() {
66          return pivotNames[iPivot];
67      }
68  
69  
70      public void init(ArrayList<Related> coll) {
71  
72          peers = new HashMap<Related, RelationNode>();
73          relationTypes = new HashSet<String>();
74  
75  
76          ArrayList<RelationNode> nodes = addAll(coll);
77          // resolve target references to nodes and
78          // extract different relation types
79  
80          // nodes is same as valcol ArrayList valcol = peers.values();
81          resolveAll(nodes);
82  
83  
84          String[] sa = (relationTypes.toArray(new String[0]));
85          setPivotNames(sa);
86  
87          // at this stage, there is just one relationNode for each
88          // source object. Most branch nodes will need duplicating a
89          // few times according to the number of distinct tree paths
90          // they could occur on.
91      }
92  
93  
94  
95      private ArrayList<RelationNode> addAll(ArrayList<Related> coll) {
96          ArrayList<RelationNode> arl = new ArrayList<RelationNode>();
97  
98          for (Related related : coll) {
99              RelationNode rnode = new RelationNode(null, related);
100             peers.put(related, rnode);
101             arl.add(rnode);
102         }
103         return arl;
104     }
105 
106 
107 
108     private void resolveAll(ArrayList<RelationNode> coll) {
109         for (RelationNode rnode : coll) {
110             rnode.resolve(peers, relationTypes);
111         }
112     }
113 
114 
115 
116     // called whenever an item is added to the model this tree is representing.
117     // The item should be set up first, then the tree should be notified.
118     private void newItem(Related parent, Related child) {
119         RelationNode rnode = new RelationNode(parent, child);
120         peers.put(child, rnode);
121         rnode.resolve(peers, relationTypes);
122 
123         if (tcReporter != null) {
124             tcReporter.nodeAddedUnder((RelationNode)(rnode.getParent()), rnode);
125         }
126 
127     }
128 
129 
130 
131     public void newBranch(Related parent, Related child) {
132         if (child instanceof SingleParent) {
133             ArrayList<Related> coll = Trawler.trawlChildren((SingleParent)child);
134             ArrayList<RelationNode> nodes = addAll(coll);
135             resolveAll(nodes);
136 
137         } else {
138             newItem(parent, child);
139         }
140         build(iPivot); // EFF economize;
141     }
142 
143 
144     public void childRemoved(Related parent, Related child) {
145         RelationNode rnParent = peers.get(parent);
146         RelationNode rnChild = peers.get(child);
147         peers.remove(child);
148         build(iPivot); // EFF economize;
149         if (tcReporter != null) {
150             tcReporter.nodeRemoved(rnParent, rnChild);
151         }
152     }
153 
154 
155     public void setDefaultPivotOrders() {
156         String[] sa1 = (relationTypes.toArray(new String[0]));
157 
158         String[] sa2 = new String[sa1.length];
159         for (int i = 0; i < sa1.length; i++) {
160             sa2[i] = sa1[sa1.length - 1 - i];
161         }
162         String[][] sa = { sa1, sa2 };
163         setPivotOrders(sa);
164     }
165 
166 
167 
168     public void setPivotOrders(String[][] saa) {
169         pivotOrders = saa;
170     }
171 
172 
173 
174     public String[] getPivotNames() {
175         if (pivotNames == null) {
176             String[] sa = { "pivot 1", "pivot 2" };
177             setPivotNames(sa);
178         }
179         return pivotNames;
180     }
181 
182 
183     public void setPivotNames(String[] sa) {
184         pivotNames = sa;
185     }
186 
187 
188     public void repivot(String s) {
189         int ibo = 0;
190         String[] sa = getPivotNames();
191         for (int i = 0; i < sa.length; i++) {
192             if (sa[i].equals(s)) {
193                 ibo = i;
194             }
195         }
196         build(ibo);
197     }
198 
199 
200 
201     public void build(int poin) {
202         int pivotOrder = poin;
203         if (pivotOrder >= pivotOrders.length) {
204             System.out.println("WARNING - requested non-existent pivot order " + pivotOrder);
205             pivotOrder = 0;
206         }
207         iPivot = pivotOrder;
208 
209 
210         // put all nodes in top level set;
211         ArrayList<RelationNode> rest = new ArrayList<RelationNode>();
212         rest.addAll(peers.values());
213 
214         for (RelationNode rn : rest) {
215             rn.clearChildren();
216         }
217 
218         // iterate over relation types
219         String[] apo = pivotOrders[pivotOrder];
220 
221 
222         String srel = null;
223         if (apo.length > 0) {
224             srel = apo[0];
225         }
226         ArrayList<RelationNode> roots = getRoots(rest, srel);
227         if (rootNode == null) {
228             rootNode = new ArrayListNode(null, "root");
229         }
230 
231         rootNode.setChildren(roots);
232 
233 
234         // TODO at this stage, we're pivoted only on the first criterion;
235 
236         /*
237          * for (int icrit = 1; icrit < apo.length; icrit++) { treeify(roots, rest,
238          * apo[icrit]); }
239          */
240 
241         if (rest.isEmpty()) {
242 
243         } else {
244             ArrayListNode aln = new ArrayListNode(rootNode, "other");
245             aln.setChildren(rest);
246             rootNode.addChild(aln);
247         }
248     }
249 
250 
251 
252     public void treeify(ArrayList<RelationNode> roots, ArrayList<RelationNode> rest, String rel) {
253         // recurse down each root tree until we find a node with a
254         // relation rel
255         // run up that relation as far as possible and insert section
256         // check for top being already a child of parent
257         // if so insert, run down and insert branch if needed
258         // ow, insert whole new section
259 
260         for (RelationNode rnode : roots) {
261             rnode.subtreeify(null, rest, rel); // POSERR null, or root node?
262         }
263 
264     }
265 
266 
267 
268     // file everything according to rel, returns a set of root nodes all of
269     // which have children. Unfiled elements are left in rest
270     private ArrayList<RelationNode> getRoots(ArrayList<RelationNode> rest, String rel) {
271 
272         if (rel != null) {
273             // file away what we can;
274             ListIterator<?> nodeiter = rest.listIterator();
275             while (nodeiter.hasNext()) {
276                 RelationNode rnode = (RelationNode)(nodeiter.next());
277                 if (rnode.fileAway(rel)) {
278                     nodeiter.remove();
279                 }
280             }
281         }
282 
283 
284 
285         // copy childed elements to return aray, remove from rest;
286         ArrayList<RelationNode> rwc = new ArrayList<RelationNode>();
287         ListIterator<?> restiter = rest.listIterator();
288         while (restiter.hasNext()) {
289             RelationNode rnode = (RelationNode)(restiter.next());
290             if (rnode.hasChildren()) {
291                 rwc.add(rnode);
292                 restiter.remove();
293             }
294         }
295         return rwc;
296     }
297 
298 
299 
300     public Object[] getPathTo(Related child) {
301         ArrayList<Object> retal = new ArrayList<Object>();
302 
303         Object[] ret = null;
304 
305         RelationNode rnode = peers.get(child);
306 
307         if (rnode == null) {
308             E.warning("relation tree has no peer for " + child + " ?");
309 
310         } else {
311             String srel = getPivotRelation();
312 
313             rnode = rnode.getParent(srel);
314             // dont expand out the child, make sure it is visble,
315             // not its children. Also if the child is a leaf it would turn
316             // the jtree expand path into a no-op if included in the path
317 
318             while (rnode != null) {
319                 retal.add(0, rnode);
320                 rnode = rnode.getParent(srel);
321             }
322             retal.add(0, rootNode);
323             ret = retal.toArray();
324         }
325         return ret;
326     }
327 
328 
329     public void setTreeChangeReporter(TreeChangeReporter tcr) {
330         tcReporter = tcr;
331     }
332 
333 
334     public Object[] getObjectPath(String s, boolean b) {
335         E.missing();
336         return null;
337     }
338 
339 
340 
341 }