1 16 package org.apache.myfaces.custom.tree; 17 18 import org.apache.myfaces.custom.tree.model.TreeModel; 19 import org.apache.myfaces.custom.tree.model.TreePath; 20 21 import javax.faces.component.html.HtmlCommandLink; 22 import javax.faces.context.FacesContext; 23 import java.util.Iterator ; 24 import java.util.List ; 25 26 27 42 public class HtmlTreeNode 43 extends HtmlCommandLink 44 { 45 46 private static final String DEFAULT_RENDERER_TYPE = "org.apache.myfaces.HtmlTreeNode"; 47 48 public static final String COMPONENT_TYPE = "org.apache.myfaces.HtmlTreeNode"; 49 public static final String EXPAND_COLLAPSE_FACET = "expandCollapse"; 50 51 public static final int OPEN = 0; 52 public static final int OPEN_FIRST = 1; 53 public static final int OPEN_LAST = 2; 54 public static final int OPEN_SINGLE = 3; 55 public static final int CLOSED = 10; 56 public static final int CLOSED_FIRST = 11; 57 public static final int CLOSED_LAST = 12; 58 public static final int CLOSED_SINGLE = 13; 59 public static final int CHILD = 20; 60 public static final int CHILD_FIRST = 21; 61 public static final int CHILD_LAST = 22; 62 public static final int LINE = 30; 63 public static final int EMPTY = 40; 64 private static final int OFFSET = 10; 65 private static final int MOD_FIRST = 1; 66 private static final int MOD_LAST = 2; 67 68 private transient TreePath path; 69 private int[] translatedPath; 70 private transient Object userObject; 71 private boolean expanded = false; 72 private boolean selected = false; 73 private int[] layout; 74 75 76 public HtmlTreeNode() 77 { 78 setRendererType(DEFAULT_RENDERER_TYPE); 79 } 80 81 82 public int getLevel() 83 { 84 return layout.length - 1; 85 } 86 87 88 public int getMaxChildLevel() 89 { 90 if (getChildCount() == 0) 91 { 92 return getLevel(); 93 } 94 95 int max = getLevel(); 96 for (Iterator iterator = getChildren().iterator(); iterator.hasNext();) 97 { 98 HtmlTreeNode child = (HtmlTreeNode) iterator.next(); 99 max = Math.max(max, child.getMaxChildLevel()); 100 } 101 return max; 102 } 103 104 105 public TreePath getPath() 106 { 107 if (path == null) 108 { 109 if (translatedPath == null) 110 { 111 throw new IllegalStateException ("No path and no translated path available"); 112 } 113 path = translatePath(translatedPath, getTreeModel(FacesContext.getCurrentInstance())); 114 } 115 return path; 116 } 117 118 119 public void setPath(TreePath path) 120 { 121 this.path = path; 122 } 123 124 125 int[] getTranslatedPath() 126 { 127 if (translatedPath != null) 128 { 129 return translatedPath; 130 } 131 ; 132 return translatePath(getPath(), getTreeModel(FacesContext.getCurrentInstance())); 133 } 134 135 136 public Object getUserObject() 137 { 138 if (userObject == null) 139 { 140 userObject = getPath().getLastPathComponent(); 141 } 142 return userObject; 143 } 144 145 146 public void setUserObject(Object userObject) 147 { 148 this.userObject = userObject; 149 setValue(userObject.toString()); 150 } 151 152 153 public boolean isExpanded() 154 { 155 return expanded; 156 } 157 158 159 void childrenAdded(int[] children, FacesContext context) 160 { 161 if (getChildCount() == 0 && children.length > 0) 162 { 163 layout[layout.length - 1] -= OFFSET; 165 } 166 167 if (!expanded) 168 { 169 return; 171 } 172 173 TreeModel model = getTreeModel(context); 174 int childCount = model.getChildCount(getUserObject()); 175 int pathUpdateIndex = getTranslatedPath().length; 176 177 for (int i = 0; i < children.length; i++) 178 { 179 int index = children[i]; 180 translateChildrenPath(pathUpdateIndex, index, 1); 181 Object userObject = model.getChild(getUserObject(), index); 182 addNode(model, userObject, index, childCount, context); 183 } 184 } 185 186 187 void childrenChanged(int[] children, FacesContext context) 188 { 189 if (!expanded) 190 { 191 return; 193 } 194 195 TreeModel model = getTreeModel(context); 196 197 for (int i = 0; i < children.length; i++) 198 { 199 int index = children[i]; 200 Object userObject = model.getChild(getUserObject(), index); 201 HtmlTreeNode node = (HtmlTreeNode) getChildren().get(index); 202 node.setUserObject(userObject); 203 } 205 } 206 207 208 private void addNode(TreeModel model, Object userObject, int index, int childCount, FacesContext context) 209 { 210 HtmlTreeNode node = createNode(model, userObject, childCount, index, context); 211 List children = getChildren(); 212 213 if (!children.isEmpty()) 214 { 215 if (index == 0) 216 { 217 HtmlTreeNode first = (HtmlTreeNode) getChildren().get(0); 218 int[] layout = first.getLayout(); 219 if (layout[layout.length - 1] % OFFSET == MOD_FIRST) 220 { 221 layout[layout.length - 1]--; 223 } 224 } else if (index == childCount - 1) 225 { 226 HtmlTreeNode last = (HtmlTreeNode) getChildren().get(childCount - 2); 227 int[] layout = last.getLayout(); 228 if (layout[layout.length - 1] % OFFSET == MOD_LAST) 229 { 230 layout[layout.length - 1] -= 2; 232 } 233 } 234 } 235 236 children.add(index, node); 237 } 238 239 240 void childrenRemoved(int[] children) 241 { 242 if (!expanded) 243 { 244 return; 246 } 247 List childNodes = getChildren(); 248 int pathUpdateIndex = getTranslatedPath().length; 249 250 for (int i = children.length - 1; i >= 0; i--) 251 { 252 translateChildrenPath(pathUpdateIndex, children[i], -1); 253 HtmlTreeNode child = (HtmlTreeNode) childNodes.get(children[i]); 254 255 if (child.isSelected()) { 256 child.setSelected(false); 257 if (children[i] < childNodes.size() - 1) { 258 ((HtmlTreeNode) childNodes.get(children[i] + 1)).setSelected(true); 259 } else { 260 if (children[i] > 0) { 261 ((HtmlTreeNode) childNodes.get(children[i] - 1)).setSelected(true); 262 } else { 263 setSelected(true); 264 } 265 } 266 } 267 childNodes.remove(children[i]); 268 } 269 } 270 271 272 280 private void translateChildrenPath(int pathUpdateIndex, int startIndex, int offset) { 281 List children = getChildren(); 282 int childrenSize = children.size(); 283 284 for (int i = startIndex; i < childrenSize; i++) { 285 HtmlTreeNode node = (HtmlTreeNode) children.get(i); 286 node.updateTranslatedPath(pathUpdateIndex, offset); 287 } 288 } 289 290 291 private void updateTranslatedPath(int pathUpdateIndex, int offset) 292 { 293 translatedPath[pathUpdateIndex] += offset; 294 path = null; 296 userObject = null; 297 298 if (isExpanded()) { 299 translateChildrenPath(pathUpdateIndex, 0, offset); 301 } 302 } 303 304 305 public void setExpanded(boolean expanded) 306 { 307 if (this.expanded == expanded) 308 { 309 return; 311 } 312 this.expanded = expanded; 313 314 if (expanded) 315 { 316 FacesContext context = FacesContext.getCurrentInstance(); 317 TreeModel model = getTreeModel(context); 318 int childCount = model.getChildCount(getUserObject()); 319 320 for (int i = 0; i < childCount; i++) 321 { 322 Object child = model.getChild(getUserObject(), i); 323 HtmlTreeNode node = createNode(model, child, childCount, i, context); 324 getChildren().add(node); 325 } 326 layout[layout.length - 1] -= OFFSET; 327 } else 328 { 329 if (clearSelection()) 330 { 331 setSelected(true); 332 } 333 getChildren().clear(); 334 layout[layout.length - 1] += OFFSET; 335 } 336 337 } 338 339 340 private HtmlTreeNode createNode(TreeModel model, Object child, int childCount, int index, FacesContext context) 341 { 342 HtmlTreeNode node = (HtmlTreeNode) context.getApplication().createComponent(HtmlTreeNode.COMPONENT_TYPE); 343 String id = getTree().createUniqueId(context); 344 node.setId(id); 345 346 node.setPath(getPath().pathByAddingChild(child)); 347 node.setUserObject(child); 348 int state = CHILD; 349 int childChildCount = model.getChildCount(child); 350 351 if (childChildCount == 0) 352 { 353 354 if (childCount > 1) 355 { 356 if (index == 0) 357 { 358 state = CHILD; 359 } else if (index == childCount - 1) 360 { 361 state = CHILD_LAST; 362 } 363 } else 364 { 365 state = CHILD_LAST; 366 } 367 } else 368 { 369 if (childCount > 1) 370 { 371 if (index == 0) 372 { 373 state = CLOSED; 374 } else if (index == childCount - 1) 375 { 376 state = CLOSED_LAST; 377 } else 378 { 379 state = CLOSED; 380 } 381 } else 382 { 383 state = CLOSED_LAST; 384 } 385 386 } 387 node.setLayout(layout, state); 388 389 return node; 390 } 391 392 393 public void toggleExpanded() 394 { 395 setExpanded(!expanded); 396 } 397 398 399 public boolean isSelected() 400 { 401 return selected; 402 } 403 404 405 public void setSelected(boolean selected) 406 { 407 if (selected) 408 { 409 getTree().getRootNode().clearSelection(); 410 } 411 this.selected = selected; 412 getTree().selectionChanged(this); 413 } 414 415 416 public void toggleSelected() 417 { 418 setSelected(!selected); 419 } 420 421 422 private boolean clearSelection() 423 { 424 if (isSelected()) 425 { 426 selected = false; 427 return true; 428 } 429 for (Iterator iterator = getChildren().iterator(); iterator.hasNext();) 430 { 431 HtmlTreeNode node = (HtmlTreeNode) iterator.next(); 432 if (node.clearSelection()) 433 { 434 return true; 435 } 436 } 437 return false; 438 } 439 440 441 public int[] getLayout() 442 { 443 return layout; 444 } 445 446 447 public void setLayout(int[] layout) 448 { 449 this.layout = layout; 450 } 451 452 453 public void setLayout(int[] parentLayout, int layout) 454 { 455 this.layout = new int[parentLayout.length + 1]; 456 this.layout[parentLayout.length] = layout; 457 458 for (int i = 0; i < parentLayout.length; i++) 459 { 460 int state = parentLayout[i]; 461 if (state == OPEN || state == OPEN_FIRST || state == CLOSED || state == CLOSED_FIRST || state == CHILD || state == CHILD_FIRST || state == LINE) 462 { 463 this.layout[i] = LINE; 464 } else 465 { 466 this.layout[i] = EMPTY; 467 } 468 } 469 } 470 471 472 public HtmlTreeImageCommandLink getExpandCollapseCommand(FacesContext context) 473 { 474 HtmlTreeImageCommandLink command = (HtmlTreeImageCommandLink) getFacet(EXPAND_COLLAPSE_FACET); 475 476 if (command == null) 477 { 478 command = (HtmlTreeImageCommandLink) context.getApplication().createComponent(HtmlTreeImageCommandLink.COMPONENT_TYPE); 479 String id = getTree().createUniqueId(context); 480 command.setId(id); 481 getFacets().put(EXPAND_COLLAPSE_FACET, command); 482 } 483 return command; 484 } 485 486 487 public Object saveState(FacesContext context) 488 { 489 Object values[] = new Object [5]; 490 values[0] = super.saveState(context); 491 values[1] = Boolean.valueOf(expanded); 492 values[2] = layout; 493 values[3] = translatePath(getPath(), getTreeModel(context)); 494 values[4] = Boolean.valueOf(selected); 495 return ((Object ) (values)); 496 } 497 498 499 public void restoreState(FacesContext context, Object state) 500 { 501 Object values[] = (Object []) state; 502 super.restoreState(context, values[0]); 503 expanded = ((Boolean ) values[1]).booleanValue(); 504 layout = (int[]) values[2]; 505 translatedPath = (int[]) values[3]; 506 selected = ((Boolean ) values[4]).booleanValue(); 507 } 508 509 510 protected static int[] translatePath(TreePath treePath, TreeModel model) 511 { 512 Object [] path = treePath.getPath(); 513 int[] translated = new int[path.length - 1]; 514 515 Object parent = path[0]; 516 517 for (int i = 1; i < path.length; i++) 518 { 519 Object element = path[i]; 520 translated[i - 1] = model.getIndexOfChild(parent, element); 521 parent = element; 522 } 523 return translated; 524 } 525 526 527 protected static TreePath translatePath(int[] path, TreeModel model) 528 { 529 Object [] translated = new Object [path.length + 1]; 530 Object parent = model.getRoot(); 531 532 translated[0] = parent; 533 534 for (int i = 0; i < path.length; i++) 535 { 536 int index = path[i]; 537 translated[i + 1] = model.getChild(parent, index); 538 parent = translated[i + 1]; 539 } 540 return new TreePath(translated); 541 } 542 543 544 protected TreeModel getTreeModel(FacesContext context) 545 { 546 return getTree().getModel(context); 547 } 548 549 550 protected HtmlTree getTree() 551 { 552 if (getParent() instanceof HtmlTree) 553 { 554 return (HtmlTree) getParent(); 555 } 556 return ((HtmlTreeNode) getParent()).getTree(); 557 } 558 559 560 public boolean isLeaf(FacesContext context) 561 { 562 return getTreeModel(context).isLeaf(getUserObject()); 563 } 564 565 566 public void expandPath(int[] translatedPath, int current) 567 { 568 if (current >= translatedPath.length) 569 { 570 return; 571 } 572 573 HtmlTreeNode child = (HtmlTreeNode) getChildren().get(translatedPath[current]); 574 575 if (!child.isExpanded()) 576 { 577 child.setExpanded(true); 578 } 579 580 child.expandPath(translatedPath, current + 1); 581 } 582 583 584 public void restoreItemState(HtmlTreeNode node) 585 { 586 setExpanded(node.isExpanded()); 587 selected = node.isSelected(); 588 List children = getChildren(); 589 List otherChildren = node.getChildren(); 590 for (int i = 0; i < children.size(); i++) 591 { 592 HtmlTreeNode child = (HtmlTreeNode) children.get(i); 593 child.restoreItemState((HtmlTreeNode) otherChildren.get(i)); 594 } 595 } 596 } 597 | Popular Tags |