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