1 13 package com.tonbeller.wcf.tree; 14 15 import java.util.Comparator ; 16 import java.util.HashSet ; 17 import java.util.Iterator ; 18 import java.util.Set ; 19 import java.util.TreeSet ; 20 21 import org.w3c.dom.Document ; 22 import org.w3c.dom.Element ; 23 24 import com.tonbeller.wcf.changeorder.ChangeOrderMgr; 25 import com.tonbeller.wcf.changeorder.ChangeOrderModel; 26 import com.tonbeller.wcf.component.Component; 27 import com.tonbeller.wcf.component.NestableComponentSupport; 28 import com.tonbeller.wcf.component.RenderListener; 29 import com.tonbeller.wcf.controller.Dispatcher; 30 import com.tonbeller.wcf.controller.DispatcherSupport; 31 import com.tonbeller.wcf.controller.RequestContext; 32 import com.tonbeller.wcf.controller.RequestListener; 33 import com.tonbeller.wcf.convert.BooleanConverter; 34 import com.tonbeller.wcf.convert.CheckBoxConverter; 35 import com.tonbeller.wcf.convert.RadioButtonConverter; 36 import com.tonbeller.wcf.scroller.Scroller; 37 import com.tonbeller.wcf.selection.SelectionMgr; 38 import com.tonbeller.wcf.selection.SelectionModel; 39 import com.tonbeller.wcf.utils.DomUtils; 40 41 46 public class TreeComponent extends NestableComponentSupport { 47 48 String treeElementName = "xtree-component"; 49 NodeRenderer nodeRenderer = new DefaultNodeRenderer(); 50 SelectionMgr selectionMgr; 51 ChangeOrderMgr changeOrderMgr; 52 ChangeOrderModel changeOrderModel; 53 String border = null; 54 String renderId = null; 55 String width = null; 56 String error = null; 57 58 Set expanded = new HashSet (); 59 Dispatcher dispatcher = new DispatcherSupport(); 60 61 BooleanConverter radioConv = new RadioButtonConverter(); 62 BooleanConverter checkConv = new CheckBoxConverter(); 63 64 TreeModel model; 66 TreeBounding bounding = NO_BOUNDING; 67 private static final TreeBounding NO_BOUNDING = new TreeBounding() { 68 public boolean isBounded(Object parent) { 69 return false; 70 } 71 public void unbound(Object parent) { 72 } 73 }; 74 75 RequestContext context; 77 Document factory; 78 int nodeCounter; 79 80 DeleteNodeModel deleteNodeModel; 81 82 TreeModelChangeListener changeListener = new TreeModelChangeListener() { 83 public void treeModelChanged(TreeModelChangeEvent event) { 84 if (event.isIdentityChanged()) { 85 selectionMgr.getSelectionModel().clear(); 86 expanded.clear(); 87 dispatcher.clear(); 88 } 89 } 90 }; 91 92 95 public TreeComponent(String id, Component parent) { 96 this(id, parent, null); 97 } 98 99 102 public TreeComponent(String id, Component parent, TreeModel model) { 103 super(id, parent); 104 selectionMgr = new SelectionMgr(getDispatcher(), this); 105 changeOrderMgr = new ChangeOrderMgr(getDispatcher(), this); 106 super.getDispatcher().addRequestListener(null, null, dispatcher); 107 108 setModel(model); 109 } 110 111 114 public void setComparator(Comparator comp) { 115 expanded = new TreeSet (comp); 116 } 117 118 123 public void setModel(TreeModel newModel) { 124 bounding = NO_BOUNDING; 125 if (model != null) 126 model.removeTreeModelChangeListener(changeListener); 127 this.model = newModel; 128 if (model != null) 129 model.addTreeModelChangeListener(changeListener); 130 if (model instanceof ChangeOrderModel) 131 changeOrderMgr.setModel((ChangeOrderModel) model); 132 else 133 changeOrderMgr.setModel(null); 134 expanded.clear(); 135 selectionMgr.getSelectionModel().clear(); 136 dispatcher.clear(); 137 } 138 139 public Element render(RequestContext context, Document factory) throws Exception { 140 return render(context, factory, true); 141 } 142 143 149 private Element render(RequestContext context, Document factory, boolean clearDispatcher) 150 throws Exception { 151 this.factory = factory; 152 this.context = context; 153 if (clearDispatcher) 154 dispatcher.clear(); 155 156 Element treeElem = factory.createElement(treeElementName); 157 renderTree(treeElem); 158 return treeElem; 159 } 160 161 Element renderTree(Element treeElem) { 162 selectionMgr.startRendering(context); 163 changeOrderMgr.startRendering(context); 164 if (nodeRenderer instanceof RenderListener) 165 ((RenderListener) nodeRenderer).startRendering(context); 166 nodeCounter = 0; 167 Object [] roots = model.getRoots(); 168 for (int i = 0; i < roots.length; i++) { 169 Element nodeElem = renderNode(null, roots, i, 0); 170 if (nodeElem != null) 171 treeElem.appendChild(nodeElem); 172 } 173 if (nodeRenderer instanceof RenderListener) 174 ((RenderListener) nodeRenderer).stopRendering(); 175 changeOrderMgr.stopRendering(); 176 selectionMgr.stopRendering(); 177 if (border != null) 178 treeElem.setAttribute("border", border); 179 if (renderId != null) 180 treeElem.setAttribute("renderId", renderId); 181 if (width != null) 182 treeElem.setAttribute("width", width); 183 if (error != null) 184 treeElem.setAttribute("error", error); 185 return treeElem; 186 } 187 188 192 Element renderNode(Object parent, Object [] nodes, int nodeIndex, int level) { 193 Object node = nodes[nodeIndex]; 194 if (deleteNodeModel != null && deleteNodeModel.getDeleted().contains(node)) 195 return null; 196 197 Element nodeElem = nodeRenderer.renderNode(context, factory, node); 198 ++nodeCounter; 199 renderEvenOddAttr(nodeElem); 201 String id = DomUtils.randomId(); 202 nodeElem.setAttribute("id", id); 203 nodeElem.setAttribute("level", "" + level); 204 renderExpandedAttr(node, nodeElem, id); 205 if (expanded.contains(node)) { 207 Object [] children = model.getChildren(node); 209 for (int i = 0; i < children.length; i++) { 210 Element childElem = renderNode(node, children, i, level + 1); 211 if (childElem != null) 212 nodeElem.appendChild(childElem); 213 } 214 } 215 selectionMgr.renderButton(nodeElem, node); 217 changeOrderMgr.renderButton(nodeElem, parent, node, nodeIndex, nodes.length); 218 renderDeleteButton(nodeElem, node); 219 return nodeElem; 220 } 221 222 void renderDeleteButton(Element elem, final Object node) { 223 if (deleteNodeModel == null || !deleteNodeModel.isDeletable(node)) 224 return; 225 Element button = DomUtils.appendElement(elem, "delete-button"); 226 String id = DomUtils.randomId(); 227 button.setAttribute("id", id); 228 RequestListener deleter = new RequestListener() { 229 public void request(RequestContext context) throws Exception { 230 Scroller.enableScroller(context); 231 NodeIterator it = new NodeIterator(getModel(), node, false); 233 while (it.hasNext()) { 234 Object n = it.next(); 235 deleteNodeModel.delete(n); 236 getSelectionModel().remove(n); 237 expanded.remove(n); 238 } 239 } 240 }; 241 dispatcher.addRequestListener(id, null, deleter); 242 } 243 244 void renderExpandedAttr(Object node, Element nodeElem, String id) { 245 if (bounding.isBounded(node)) { 246 nodeElem.setAttribute("state", "bounded"); 247 dispatcher.addRequestListener(id + ".unbound", null, new UnboundHandler(node)); 248 } else if (expanded.contains(node)) { 249 nodeElem.setAttribute("state", "expanded"); 250 dispatcher.addRequestListener(id + ".collapse", null, new CollapseHandler(node)); 251 } else if (model.hasChildren(node)) { 252 nodeElem.setAttribute("state", "collapsed"); 253 dispatcher.addRequestListener(id + ".expand", null, new ExpandHandler(node)); 254 } else { 255 nodeElem.setAttribute("state", "leaf"); 256 } 257 } 258 259 void renderEvenOddAttr(Element nodeElem) { 260 if (nodeCounter % 2 == 0) 261 nodeElem.setAttribute("style", "even"); 262 else 263 nodeElem.setAttribute("style", "odd"); 264 } 265 266 class CollapseHandler implements RequestListener { 267 Object node; 268 public CollapseHandler(Object node) { 269 this.node = node; 270 } 271 public void request(RequestContext context) throws Exception { 272 Scroller.enableScroller(context); 273 expanded.remove(node); 274 validate(context); 275 } 276 } 277 278 class ExpandHandler implements RequestListener { 279 Object node; 280 public ExpandHandler(Object node) { 281 this.node = node; 282 } 283 public void request(RequestContext context) throws Exception { 284 Scroller.enableScroller(context); 285 expanded.add(node); 286 validate(context); 287 } 288 } 289 290 class UnboundHandler implements RequestListener { 291 Object node; 292 public UnboundHandler(Object node) { 293 this.node = node; 294 } 295 public void request(RequestContext context) throws Exception { 296 Scroller.enableScroller(context); 297 bounding.unbound(node); 298 validate(context); 299 } 300 } 301 302 305 public SelectionModel getSelectionModel() { 306 return selectionMgr.getSelectionModel(); 307 } 308 309 312 public void setSelectionModel(SelectionModel selectionModel) { 313 selectionMgr.setSelectionModel(selectionModel); 314 } 315 316 319 public void collapse(Object node) { 320 expanded.remove(node); 321 } 322 323 326 public void expand(Object node) { 327 expanded.add(node); 328 } 329 330 333 public void collapseAll() { 334 expanded.clear(); 335 } 336 337 341 public void expandSelected() { 342 expandSelected(false); 343 } 344 345 349 public void expandSelected(boolean expandSelected) { 350 expanded.clear(); 351 for (Iterator it = selectionMgr.getSelectionModel().getSelection().iterator(); it.hasNext();) { 352 Object node = it.next(); 353 if (expandSelected && model.hasChildren(node)) 354 expanded.add(node); 355 node = model.getParent(node); 356 while (node != null) { 357 expanded.add(node); 358 node = model.getParent(node); 359 } 360 } 361 } 362 363 366 public void selectVisible() { 367 SelectionModel sm = selectionMgr.getSelectionModel(); 368 sm.clear(); 369 Object [] roots = model.getRoots(); 370 for (int i = 0; i < roots.length; i++) 371 recurseSelectVisible(sm, roots[i]); 372 } 373 374 private void recurseSelectVisible(SelectionModel sm, Object node) { 375 if (sm.isSelectable(node)) 376 sm.add(node); 377 if (expanded.contains(node)) { 378 Object [] children = model.getChildren(node); 379 for (int i = 0; i < children.length; i++) 380 recurseSelectVisible(sm, children[i]); 381 } 382 } 383 384 388 public TreeModel getModel() { 389 return model; 390 } 391 392 396 public NodeRenderer getNodeRenderer() { 397 return nodeRenderer; 398 } 399 400 404 public String getTreeElementName() { 405 return treeElementName; 406 } 407 408 418 public void setNodeRenderer(NodeRenderer nodeRenderer) { 419 if (this.nodeRenderer instanceof RequestListener) 420 super.getDispatcher().removeRequestListener((RequestListener) this.nodeRenderer); 421 this.nodeRenderer = nodeRenderer; 422 if (this.nodeRenderer instanceof RequestListener) 423 super.getDispatcher().addRequestListener(null, null, (RequestListener) this.nodeRenderer); 424 } 425 426 430 public void setTreeElementName(String treeElementName) { 431 this.treeElementName = treeElementName; 432 } 433 434 438 public ChangeOrderModel getChangeOrderModel() { 439 return changeOrderMgr.getModel(); 440 } 441 442 446 public void setChangeOrderModel(ChangeOrderModel changeOrderModel) { 447 changeOrderMgr.setModel(changeOrderModel); 448 } 449 450 454 public void setCutPasteMode(boolean b) { 455 changeOrderMgr.setCutPasteMode(b); 456 } 457 458 463 public String getBorder() { 464 return border; 465 } 466 467 472 public void setBorder(String border) { 473 this.border = border; 474 } 475 476 481 public void setRenderId(String renderId) { 482 this.renderId = renderId; 483 } 484 485 490 public String getRenderId() { 491 return renderId; 492 } 493 494 public String getWidth() { 495 return width; 496 } 497 498 public void setWidth(String string) { 499 width = string; 500 } 501 502 public DeleteNodeModel getDeleteNodeModel() { 503 return deleteNodeModel; 504 } 505 506 public void setDeleteNodeModel(DeleteNodeModel model) { 507 deleteNodeModel = model; 508 } 509 510 public String getError() { 511 return error; 512 } 513 514 public void setError(String string) { 515 error = string; 516 } 517 518 public TreeBounding getBounding() { 519 return bounding; 520 } 521 522 public void setBounding(TreeBounding bounding) { 523 if (bounding == null) 524 bounding = NO_BOUNDING; 525 this.bounding = bounding; 526 } 527 } 528 | Popular Tags |