001 // Copyright 2004, 2005 The Apache Software Foundation
002 //
003 // Licensed under the Apache License, Version 2.0 (the "License");
004 // you may not use this file except in compliance with the License.
005 // You may obtain a copy of the License at
006 //
007 // http://www.apache.org/licenses/LICENSE-2.0
008 //
009 // Unless required by applicable law or agreed to in writing, software
010 // distributed under the License is distributed on an "AS IS" BASIS,
011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012 // See the License for the specific language governing permissions and
013 // limitations under the License.
014
015 package org.apache.tapestry.contrib.tree.components;
016
017 import org.apache.commons.logging.Log;
018 import org.apache.commons.logging.LogFactory;
019 import org.apache.tapestry.BaseComponent;
020 import org.apache.tapestry.IAsset;
021 import org.apache.tapestry.IMarkupWriter;
022 import org.apache.tapestry.IRender;
023 import org.apache.tapestry.IRequestCycle;
024 import org.apache.tapestry.contrib.tree.model.ITreeModelSource;
025 import org.apache.tapestry.contrib.tree.model.ITreeRowSource;
026 import org.apache.tapestry.contrib.tree.model.ITreeStateListener;
027 import org.apache.tapestry.contrib.tree.model.ITreeStateModel;
028 import org.apache.tapestry.contrib.tree.model.TreeRowObject;
029 import org.apache.tapestry.contrib.tree.model.TreeStateEvent;
030 import org.apache.tapestry.contrib.tree.simple.SimpleNodeRenderFactory;
031 import org.apache.tapestry.engine.IPageLoader;
032 import org.apache.tapestry.event.PageDetachListener;
033 import org.apache.tapestry.event.PageEvent;
034 import org.apache.tapestry.spec.ComponentSpecification;
035 import org.apache.tapestry.util.ComponentAddress;
036
037 /**
038 * @author tsveltin?
039 */
040 public abstract class TreeNodeView extends BaseComponent implements PageDetachListener
041 {
042 private static final Log LOG = LogFactory.getLog(TreeNodeView.class);
043
044 private Boolean m_objNodeState;
045
046 private Boolean m_objShowNodeImages;
047
048 private Boolean m_objMakeNodeDirect;
049
050 private INodeRenderFactory m_objNodeRenderFactory;
051
052 private IAsset m_objOpenNodeImage;
053
054 private IAsset m_objCloseNodeImage;
055
056 private int m_CurrentForeachConnectImageValue = TreeRowObject.LINE_CONN_IMG;
057
058 public abstract INodeRenderFactory getNodeRenderFactoryParameter();
059
060 public abstract Boolean getShowNodeImages();
061
062 public TreeNodeView()
063 {
064 super();
065 initialize();
066 }
067
068 private void initialize()
069 {
070 m_objNodeState = null;
071 m_objShowNodeImages = null;
072 m_objNodeRenderFactory = null;
073 m_objMakeNodeDirect = null;
074 m_CurrentForeachConnectImageValue = TreeRowObject.LINE_CONN_IMG;
075 }
076
077 public IRender getCurrentRenderer()
078 {
079 INodeRenderFactory objRenderFactory = getNodeRenderFactory();
080 ITreeRowSource objTreeRowSource = getTreeRowSource();
081 return objRenderFactory.getRender(
082 objTreeRowSource.getTreeRow().getTreeNode(),
083 getTreeModelSource(),
084 getPage().getRequestCycle());
085 }
086
087 public Object[] getNodeContext()
088 {
089 ITreeModelSource objModelSource = getTreeModelSource();
090 ComponentAddress objModelSourceAddress = new ComponentAddress(objModelSource);
091 ITreeRowSource objTreeRowSource = getTreeRowSource();
092 TreeRowObject objTreeRowObject = objTreeRowSource.getTreeRow();
093 Object objValueUID = objTreeRowObject.getTreeNodeUID();
094 if (LOG.isDebugEnabled())
095 {
096 LOG.debug("getNodeContext objValueUID = " + objValueUID);
097 }
098
099 return new Object[]
100 { objValueUID, new Boolean(isNodeOpen()), objModelSourceAddress };
101 }
102
103 /**
104 * Called when a node in the tree is clicked by the user. If the node is expanded, it will be
105 * collapsed, and vice-versa, that is, the tree state model is retrieved, and it is told to
106 * collapse or expand the node.
107 *
108 * @param cycle
109 * The Tapestry request cycle object.
110 */
111 public void nodeExpandCollaps(IRequestCycle cycle)
112 {
113 Object context[] = cycle.getListenerParameters();
114 Object objValueUID = null;
115 if (context != null && context.length > 0)
116 {
117 objValueUID = context[0];
118 }
119 ComponentAddress objModelSourceAddress = (ComponentAddress) context[2];
120 ITreeModelSource objTreeModelSource = (ITreeModelSource) objModelSourceAddress
121 .findComponent(cycle);
122 // ITreeModelSource objTreeModelSource = getTreeModelSource();
123 ITreeStateModel objStateModel = objTreeModelSource.getTreeModel().getTreeStateModel();
124 boolean bState = objStateModel.isUniqueKeyExpanded(objValueUID);
125
126 if (bState)
127 {
128 objStateModel.collapse(objValueUID);
129 fireNodeCollapsed(objValueUID, objTreeModelSource);
130 }
131 else
132 {
133 objStateModel.expandPath(objValueUID);
134 fireNodeExpanded(objValueUID, objTreeModelSource);
135 }
136 }
137
138 /**
139 * Called when a node in the tree is selected by the user. the tree state model is retrieved,
140 * and it is told to select the node.
141 *
142 * @param cycle
143 * The Tapestry request cycle object.
144 */
145 public void nodeSelect(IRequestCycle cycle)
146 {
147 Object context[] = cycle.getListenerParameters();
148 Object objValueUID = null;
149 if (context != null && context.length > 0)
150 {
151 objValueUID = context[0];
152 }
153 ComponentAddress objModelSourceAddress = (ComponentAddress) context[2];
154 ITreeModelSource objTreeModelSource = (ITreeModelSource) objModelSourceAddress
155 .findComponent(cycle);
156 // ITreeModelSource objTreeModelSource = getTreeModelSource();
157 ITreeStateModel objStateModel = objTreeModelSource.getTreeModel().getTreeStateModel();
158 Object objSelectedNodeInState = objStateModel.getSelectedNode();
159
160 if (objValueUID.equals(objSelectedNodeInState))
161 {
162 // do nothing, the selected node in UI is the same as the selected in
163 // state model. The user should use refresh of back button.
164 return;
165 }
166
167 objStateModel.setSelectedNode(objValueUID);
168 fireNodeSelected(objValueUID, objTreeModelSource);
169 }
170
171 private void fireNodeSelected(Object objValueUID, ITreeModelSource objTreeModelSource)
172 {
173 deliverEvent(TreeStateEvent.SELECTED_NODE_CHANGED, objValueUID, objTreeModelSource);
174 }
175
176 private void fireNodeCollapsed(Object objValueUID, ITreeModelSource objTreeModelSource)
177 {
178 deliverEvent(TreeStateEvent.NODE_COLLAPSED, objValueUID, objTreeModelSource);
179 }
180
181 private void fireNodeExpanded(Object objValueUID, ITreeModelSource objTreeModelSource)
182 {
183 deliverEvent(TreeStateEvent.NODE_EXPANDED, objValueUID, objTreeModelSource);
184 }
185
186 private void deliverEvent(int nEventUID, Object objValueUID, ITreeModelSource objTreeModelSource)
187 {
188 ITreeStateListener objListener = objTreeModelSource.getTreeStateListener();
189 if (objListener != null)
190 {
191 TreeStateEvent objEvent = new TreeStateEvent(nEventUID, objValueUID, objTreeModelSource
192 .getTreeModel().getTreeStateModel());
193 objListener.treeStateChanged(objEvent);
194 }
195
196 }
197
198 public void pageDetached(PageEvent arg0)
199 {
200 initialize();
201 }
202
203 public void finishLoad(IRequestCycle objCycle, IPageLoader arg0, ComponentSpecification arg1)
204 {
205 super.finishLoad(objCycle, arg0, arg1);
206 getPage().addPageDetachListener(this);
207
208 m_objOpenNodeImage = getAsset("_openNodeImage");
209 m_objCloseNodeImage = getAsset("_closeNodeImage");
210 }
211
212 public boolean isNodeOpen()
213 {
214 if (m_objNodeState == null)
215 {
216 ITreeRowSource objTreeRowSource = getTreeRowSource();
217 TreeRowObject objTreeRowObject = objTreeRowSource.getTreeRow();
218 Object objValueUID = objTreeRowObject.getTreeNodeUID();
219 ITreeModelSource objTreeModelSource = getTreeModelSource();
220 ITreeStateModel objStateModel = objTreeModelSource.getTreeModel().getTreeStateModel();
221 boolean bState = objStateModel.isUniqueKeyExpanded(objValueUID);
222 m_objNodeState = new Boolean(bState);
223 }
224 return m_objNodeState.booleanValue();
225 }
226
227 /**
228 * Returns the openNodeImage.
229 *
230 * @return IAsset
231 */
232 public IAsset getNodeImage()
233 {
234 IAsset objResult = null;
235 ITreeRowSource objRowSource = getTreeRowSource();
236 boolean bLeaf = objRowSource.getTreeRow().getLeaf();
237 int nRowType = objRowSource.getTreeRow().getTreeRowPossiotionType();
238 if (!bLeaf)
239 {
240 if (isNodeOpen())
241 {
242 switch (nRowType)
243 {
244 case TreeRowObject.FIRST_LAST_ROW:
245 {
246 objResult = getAsset("_topLastOpenNodeImage");
247 break;
248 }
249
250 case TreeRowObject.FIRST_ROW:
251 {
252 objResult = getAsset("_topOpenNodeImage");
253 break;
254 }
255
256 case TreeRowObject.MIDDLE_ROW:
257 {
258 objResult = getAsset("_middleOpenNodeImage");
259 break;
260 }
261
262 case TreeRowObject.LAST_ROW:
263 {
264 objResult = getAsset("_bottomOpenNodeImage");
265 break;
266 }
267
268 default:
269 {
270 objResult = getAsset("_openNodeImage");
271 break;
272 }
273 }
274 }
275 else
276 {
277 switch (nRowType)
278 {
279 case TreeRowObject.FIRST_LAST_ROW:
280 {
281 objResult = getAsset("_topLastCloseNodeImage");
282 break;
283 }
284
285 case TreeRowObject.FIRST_ROW:
286 {
287 objResult = getAsset("_topCloseNodeImage");
288 break;
289 }
290
291 case TreeRowObject.MIDDLE_ROW:
292 {
293 objResult = getAsset("_middleCloseNodeImage");
294 break;
295 }
296
297 case TreeRowObject.LAST_ROW:
298 {
299 objResult = getAsset("_bottomCloseNodeImage");
300 break;
301 }
302
303 default:
304 {
305 objResult = getAsset("_closeNodeImage");
306 break;
307 }
308 }
309 }
310 }
311 else
312 {
313 switch (nRowType)
314 {
315 case TreeRowObject.FIRST_LAST_ROW:
316 {
317 objResult = getAsset("_topLineImage");
318 break;
319 }
320
321 case TreeRowObject.FIRST_ROW:
322 {
323 objResult = getAsset("_topLineImage");
324 break;
325 }
326
327 case TreeRowObject.MIDDLE_ROW:
328 {
329 objResult = getAsset("_middleCrossLineImage");
330 break;
331 }
332
333 case TreeRowObject.LAST_ROW:
334 {
335 objResult = getAsset("_bottomLineImage");
336 break;
337 }
338
339 default:
340 {
341 objResult = getAsset("_bottomLineImage");
342 break;
343 }
344 }
345
346 }
347 return objResult;
348 }
349
350 public IAsset getNodeImageOld()
351 {
352 if (isNodeOpen())
353 {
354 if (m_objOpenNodeImage == null)
355 {
356 m_objOpenNodeImage = getAsset("_openNodeImage");
357 }
358 return m_objOpenNodeImage;
359 }
360
361 if (m_objCloseNodeImage == null)
362 {
363 m_objCloseNodeImage = getAsset("_closeNodeImage");
364 }
365 return m_objCloseNodeImage;
366 }
367
368 /**
369 * Returns the closeNodeImage.
370 *
371 * @return IAsset
372 */
373 public IAsset getCloseNodeImage()
374 {
375 return m_objCloseNodeImage;
376 }
377
378 /**
379 * Returns the openNodeImage.
380 *
381 * @return IAsset
382 */
383 public IAsset getOpenNodeImage()
384 {
385 return m_objOpenNodeImage;
386 }
387
388 /**
389 * Sets the closeNodeImage.
390 *
391 * @param closeNodeImage
392 * The closeNodeImage to set
393 */
394 public void setCloseNodeImage(IAsset closeNodeImage)
395 {
396 m_objCloseNodeImage = closeNodeImage;
397 }
398
399 /**
400 * Sets the openNodeImage.
401 *
402 * @param openNodeImage
403 * The openNodeImage to set
404 */
405 public void setOpenNodeImage(IAsset openNodeImage)
406 {
407 m_objOpenNodeImage = openNodeImage;
408 }
409
410 /**
411 * @see org.apache.tapestry.AbstractComponent#renderComponent(IMarkupWriter, IRequestCycle)
412 */
413 protected void renderComponent(IMarkupWriter arg0, IRequestCycle arg1)
414 {
415 super.renderComponent(arg0, arg1);
416 m_objNodeState = null;
417 }
418
419 /**
420 * Returns the ShowNodeImages.
421 *
422 * @return Boolean
423 */
424 public Boolean isShowNodeImages()
425 {
426 if (m_objShowNodeImages == null)
427 {
428 if (isParameterBound("nodeRenderFactory"))
429 {
430 m_objShowNodeImages = getShowNodeImages();
431 }
432 else
433 {
434 m_objShowNodeImages = Boolean.TRUE;
435 }
436
437 }
438 return m_objShowNodeImages;
439 }
440
441 public boolean getShowImages()
442 {
443 boolean bResult = isShowNodeImages().booleanValue();
444 return bResult;
445 }
446
447 public boolean getShowWithoutImages()
448 {
449 boolean bResult = !isShowNodeImages().booleanValue();
450 return bResult;
451 }
452
453 public String getOffsetStyle()
454 {
455 // return "width: " + getTreeDataView().getTreeDeep() * 15;
456 ITreeRowSource objTreeRowSource = getTreeRowSource();
457 TreeRowObject objTreeRowObject = objTreeRowSource.getTreeRow();
458 int nTreeRowDepth = 0;
459 if (objTreeRowObject != null)
460 {
461 nTreeRowDepth = objTreeRowObject.getTreeRowDepth();
462 if (nTreeRowDepth != 0)
463 nTreeRowDepth = nTreeRowDepth - 1;
464 }
465 return "padding-left: " + nTreeRowDepth * 19 + "px";
466 }
467
468 public INodeRenderFactory getNodeRenderFactory()
469 {
470 if (m_objNodeRenderFactory == null)
471 {
472 if (isParameterBound("nodeRenderFactory"))
473 m_objNodeRenderFactory = getNodeRenderFactoryParameter();
474 else
475 m_objNodeRenderFactory = new SimpleNodeRenderFactory();
476 }
477 return m_objNodeRenderFactory;
478 }
479
480 public abstract boolean getMakeNodeDirect();
481
482 public boolean getMakeNodeNoDirect()
483 {
484 return !getMakeNodeDirect();
485 }
486
487 public String getCleanSelectedID()
488 {
489 return getSelectedNodeID();
490 }
491
492 public String getSelectedID()
493 {
494 ITreeRowSource objTreeRowSource = getTreeRowSource();
495 ITreeModelSource objTreeModelSource = getTreeModelSource();
496 TreeRowObject objTreeRowObject = objTreeRowSource.getTreeRow();
497 Object objNodeValueUID = objTreeRowObject.getTreeNodeUID();
498 Object objSelectedNode = objTreeModelSource.getTreeModel().getTreeStateModel()
499 .getSelectedNode();
500 if (objNodeValueUID.equals(objSelectedNode))
501 {
502 return getSelectedNodeID();
503 }
504 return "";
505 }
506
507 private String getSelectedNodeID()
508 {
509 // return getTreeDataView().getTreeView().getSelectedNodeID();
510 return "tree";
511 }
512
513 public String getNodeStyleClass()
514 {
515 ITreeRowSource objTreeRowSource = getTreeRowSource();
516 ITreeModelSource objTreeModelSource = getTreeModelSource();
517 TreeRowObject objTreeRowObject = objTreeRowSource.getTreeRow();
518 boolean bResult = false;
519 if (objTreeRowObject != null)
520 {
521 Object objNodeValueUID = objTreeRowObject.getTreeNodeUID();
522 Object objSelectedNode = objTreeModelSource.getTreeModel().getTreeStateModel()
523 .getSelectedNode();
524 bResult = objNodeValueUID.equals(objSelectedNode);
525 }
526 if (bResult)
527 {
528 return "selectedNodeViewClass";
529 }
530
531 return "notSelectedNodeViewClass";
532 }
533
534 public ITreeRowSource getTreeRowSource()
535 {
536 ITreeRowSource objSource = (ITreeRowSource) getPage().getRequestCycle().getAttribute(
537 ITreeRowSource.TREE_ROW_SOURCE_ATTRIBUTE);
538 return objSource;
539 }
540
541 public ITreeModelSource getTreeModelSource()
542 {
543 ITreeModelSource objSource = (ITreeModelSource) getPage().getRequestCycle().getAttribute(
544 ITreeModelSource.TREE_MODEL_SOURCE_ATTRIBUTE);
545 return objSource;
546 }
547
548 public boolean getShowConnectImage()
549 {
550 ITreeRowSource objRowSource = getTreeRowSource();
551 int nRowType = objRowSource.getTreeRow().getTreeRowPossiotionType();
552 if (TreeRowObject.MIDDLE_ROW == nRowType)
553 return true;
554 return false;
555 }
556
557 public int[] getForeachConnectImageList()
558 {
559 ITreeRowSource objTreeRowSource = getTreeRowSource();
560 TreeRowObject objTreeRowObject = objTreeRowSource.getTreeRow();
561 return objTreeRowObject.getLineConnImages();
562 }
563
564 public boolean getDisableLink()
565 {
566 ITreeRowSource objRowSource = getTreeRowSource();
567 boolean bLeaf = objRowSource.getTreeRow().getLeaf();
568 return bLeaf;
569 }
570
571 /**
572 * Returns the openNodeImage.
573 *
574 * @return IAsset nevalidno neshto
575 */
576 public IAsset getConnectImage()
577 {
578 IAsset objResult = null;
579 int nConnectImageType = getCurrentForeachConnectImageValue();
580 switch (nConnectImageType)
581 {
582 case TreeRowObject.EMPTY_CONN_IMG:
583 {
584 objResult = getAsset("_whiteSpaceImage");
585 break;
586 }
587
588 case TreeRowObject.LINE_CONN_IMG:
589 {
590 objResult = getAsset("_middleLineImage");
591 break;
592 }
593
594 default:
595 {
596 objResult = getAsset("_whiteSpaceImage");
597 break;
598 }
599 }
600 return objResult;
601 }
602
603 /**
604 * @return Returns the m_CurrentForeachConnectImageValue.
605 */
606 public int getCurrentForeachConnectImageValue()
607 {
608 return m_CurrentForeachConnectImageValue;
609 }
610
611 /**
612 * @param currentForeachConnectImageValue
613 * The m_CurrentForeachConnectImageValue to set.
614 */
615 public void setCurrentForeachConnectImageValue(int currentForeachConnectImageValue)
616 {
617 m_CurrentForeachConnectImageValue = currentForeachConnectImageValue;
618 }
619 }