1 package net.sf.tacos.components.tree;
2
3 import java.io.Serializable;
4 import java.util.ArrayList;
5 import java.util.Collection;
6 import java.util.Collections;
7 import java.util.Comparator;
8 import java.util.HashMap;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.Set;
12 import java.util.Stack;
13 import net.sf.tacos.model.IKeyProvider;
14 import net.sf.tacos.model.ITreeContentProvider;
15 import net.sf.tacos.model.IdentityKeyProvider;
16 import org.apache.commons.lang.StringEscapeUtils;
17 import org.apache.commons.logging.Log;
18 import org.apache.commons.logging.LogFactory;
19 import org.apache.tapestry.BaseComponent;
20 import org.apache.tapestry.IActionListener;
21 import org.apache.tapestry.IDirect;
22 import org.apache.tapestry.IMarkupWriter;
23 import org.apache.tapestry.IRequestCycle;
24 import org.apache.tapestry.IScript;
25 import org.apache.tapestry.PageRenderSupport;
26 import org.apache.tapestry.TapestryUtils;
27 import org.apache.tapestry.bean.EvenOdd;
28 import org.apache.tapestry.components.Any;
29 import org.apache.tapestry.engine.DirectServiceParameter;
30 import org.apache.tapestry.engine.IEngineService;
31 import org.apache.tapestry.listener.ListenerInvoker;
32
33
34
35
36
37
38 public abstract class Tree extends BaseComponent implements
39
40
41 private static final Log log = LogFactory.getLog(Tree.class);
42
43 private static final IKeyProvider identityKeyProvider = new IdentityKeyProvider();
44
45 private TreeIterator treeIterator;
46
47 private Stack parts;
48
49
50
51
52
53
54 public IKeyProvider getIdentityKeyProvider()
55 {
56 return identityKeyProvider;
57 }
58
59
60
61
62
63
64 public TreeIterator getTreeIterator()
65 {
66 return treeIterator;
67 }
68
69
70
71
72 protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
73 {
74 boolean dynamic = cycle.getResponseBuilder().isDynamic();
75
76 if (!cycle.isRewinding()
77 && isDelayedLoad()
78 && !dynamic
79 renderDynamicLoad(writer, cycle);
80 return;
81 }
82 treeIterator = new TreeIter();
83 parts = new Stack();
84 try {
85 super.renderComponent(writer, cycle);
86 } finally {
87 try {
88 while(!parts.isEmpty()) {
89 String partId = parts.pop().toString();
90
91
92
93
94
95 }
96 } catch (Throwable t) {
97 t.printStackTrace();
98 }
99 treeIterator = null;
100 parts = null;
101 }
102 }
103
104 private void renderDynamicLoad(IMarkupWriter writer, IRequestCycle cycle) {
105
106
107 Any anyContainer = (Any)getComponent("treeDiv");
108 writer.begin(anyContainer.getElement());
109 super.renderInformalParameters(writer, cycle);
110 writer.end();
111
112 String treeId = getClientId();
113
114
115
116
117
118 DirectServiceParameter dsp = new DirectServiceParameter(this);
119
120 Map parms = new HashMap();
121 parms.put("treeId", treeId);
122 parms.put("url", StringEscapeUtils.escapeJavaScript(
123 getDirectService().getLink(true, dsp).getAbsoluteURL()));
124 if (getLoadElement() != null)
125 parms.put("loadElement", getLoadElement());
126
127 PageRenderSupport pageRenderSupport = TapestryUtils.getPageRenderSupport(cycle, this);
128 getScript().execute(this, cycle, pageRenderSupport, parms);
129 }
130
131
132
133
134
135
136 public void expansion(IRequestCycle cycle)
137 {
138 Object[] params = cycle.getListenerParameters();
139 Serializable key = (Serializable)params[0];
140 boolean expanded = ((Boolean)params[1]).booleanValue();
141
142 getManager().setExpandedKey(key, expanded);
143 setState(getState());
144 }
145
146
147
148
149
150
151
152
153
154 public void contentExpansion(IRequestCycle cycle)
155 {
156
157 expansion(cycle);
158
159
160 if (getLinkListener() == null) {
161 log.warn("contentExpansion() called but no linkListener was specified on the tree. "
162 + "Use the linkListener parameter if you want your page/component to be invoked "
163 + "as well.");
164 return;
165 }
166
167 getListenerInvoker().invokeListener(getLinkListener(), this, cycle);
168 }
169
170
171
172
173
174
175 public boolean isExpanded(Object element)
176 {
177 return getManager().isExpanded(element);
178 }
179
180
181
182
183 private final class TreeIter extends TreeIterator {
184
185
186
187
188
189 private TreeIter()
190 {
191 super(sorted(getContentProvider().getElements()));
192 }
193
194
195
196
197
198 protected Collection getChildren(Object node)
199 {
200 if (!isExpanded(node)) { return Collections.EMPTY_LIST; }
201 Collection coll = getContentProvider().getChildren(node);
202 return sorted(coll);
203 }
204
205 }
206
207
208
209
210
211
212
213 private Collection sorted(Collection elements)
214 {
215 Comparator comp = getSorter();
216 if (comp == null) { return elements; }
217 List l = new ArrayList(elements);
218 Collections.sort(l, comp);
219 return l;
220 }
221
222
223
224
225 public ITreeManager getManager()
226 {
227 return new TreeManager(getState(), getContentProvider(),
228 getKeyProvider());
229 }
230
231
232
233
234 public void beforeRenderBody(IMarkupWriter writer, IRequestCycle cycle,
235 Serializable partId, boolean isRendering)
236 {
237
238 if (treeIterator.getDepth() <= treeIterator.getPreviousDepth()
239 && !parts.isEmpty()) {
240
241 int pops = 1;
242 if (treeIterator.getDepth() < treeIterator.getPreviousDepth()) {
243 pops = treeIterator.getPreviousDepth()
244 - treeIterator.getDepth();
245 pops++;
246 }
247 while(pops > 0 && !parts.isEmpty()) {
248 Serializable id = (Serializable)parts.pop();
249 if (isRendering) {
250
251
252
253
254 {
255 IMarkupWriter pwriter = findParentPart();
256 if (pwriter != null) pwriter.end();
257 else
258 writer.end();
259 }
260 }
261 pops--;
262 }
263 }
264
265 if (isRendering) {
266 writer.begin("div");
267 writer.attribute("id", partId.toString());
268 if (isRowStyleInOuterDiv() && getRowStyle() != null)
269 {
270 writer.attribute("class", getRowStyle().getNext());
271 }
272 else if (getPartialBlockClass() != null)
273 {
274 writer.attribute("class", getPartialBlockClass());
275 }
276 parts.push(partId.toString());
277 }
278 }
279
280
281
282
283 public void incrementNonRenderBlock()
284 {
285 if (getRowStyle() != null) getRowStyle().getNext();
286 beforeRenderBody(null, null, getKeyProvider().getKey(getValue()), false);
287 }
288
289
290
291
292 public IMarkupWriter getPartWriter(Serializable partId)
293 {
294 String partStr = partId.toString();
295
296 IMarkupWriter ret = null;
297
298
299
300 if (treeIterator.getDepth() < treeIterator.getPreviousDepth()
301 && !parts.isEmpty()
302 && ((parts.size() - 1) > (treeIterator.getPreviousDepth() - treeIterator
303 .getDepth()))) {
304 ret = findParentPart();
305 } else if (treeIterator.getDepth() > treeIterator.getPreviousDepth()
306 && !parts.isEmpty()) {
307 ret = findParentPart();
308 } else if (treeIterator.getDepth() == treeIterator.getPreviousDepth()
309 && parts.size() > 1) {
310 ret = findParentPart();
311 }
312
313 return ret;
314 }
315
316
317
318
319
320
321
322 private IMarkupWriter findParentPart()
323 {
324
325
326
327 IMarkupWriter ret = null;
328 Serializable[] partIds = (Serializable[])parts
329 .toArray(new Serializable[parts.size()]);
330
331
332
333
334
335 return ret;
336 }
337
338
339
340
341
342 /*
343 public PartialRenderBlock getPartialTreeBlock()
344 {
345 return this;
346 }*/
347
348 public boolean getCurrentHasChildren() {
349 return getContentProvider().hasChildren(getValue());
350 }
351
352 public Serializable getCurrentKey() {
353 return getKeyProvider().getKey(getValue());
354 }
355
356 public boolean getCurrentNotExpanded() {
357 return !isExpanded(getValue());
358 }
359
360 public String getCurrentOffset() {
361 int off = (getContentProvider().hasChildren(getValue())) ? 0 : 1;
362 return "" + ( off + getTreeIterator().getDepth() ) * getOffset();
363 }
364
365
366
367
368 public boolean isStateful()
369 {
370 return true;
371 }
372
373
374
375
376 public void trigger(IRequestCycle cycle)
377 {
378
379 }
380
381
382 public abstract IScript getScript();
383
384 public abstract IEngineService getDirectService();
385
386 public abstract Object getValue();
387
388 public abstract Set getState();
389
390 public abstract void setState(Set state);
391
392 public abstract ITreeContentProvider getContentProvider();
393
394 public abstract IKeyProvider getKeyProvider();
395
396 public abstract Comparator getSorter();
397
398 public abstract EvenOdd getRowStyle();
399
400 public abstract int getOffset();
401
402 public abstract boolean isRowStyleInOuterDiv();
403
404 public abstract String getPartialBlockClass();
405
406 public abstract ListenerInvoker getListenerInvoker();
407
408 public abstract IActionListener getLinkListener();
409
410 public abstract boolean isDelayedLoad();
411
412 public abstract String getLoadElement();
413 }