1 36 37 40 41 import javax.swing.*; 42 import javax.swing.event.*; 43 import javax.swing.text.*; 44 import javax.swing.tree.*; 45 import javax.swing.undo.*; 46 import java.awt.*; 47 import java.beans.*; 48 import java.util.*; 49 50 59 public class ElementTreePanel extends JPanel implements CaretListener, DocumentListener, PropertyChangeListener, TreeSelectionListener { 60 61 protected JTree tree; 62 63 protected JTextComponent editor; 64 65 protected ElementTreeModel treeModel; 66 67 protected boolean updatingSelection; 68 69 public ElementTreePanel(JTextComponent editor) { 70 this.editor = editor; 71 72 Document document = editor.getDocument(); 73 74 treeModel = new ElementTreeModel(document); 76 tree = new JTree(treeModel) { 77 public String convertValueToText(Object value, boolean selected, 78 boolean expanded, boolean leaf, 79 int row, boolean hasFocus) { 80 if(!(value instanceof Element)) 82 return value.toString(); 83 84 Element e = (Element)value; 85 AttributeSet as = e.getAttributes().copyAttributes(); 86 String asString; 87 88 if(as != null) { 89 StringBuffer retBuffer = new StringBuffer ("["); 90 Enumeration names = as.getAttributeNames(); 91 92 while(names.hasMoreElements()) { 93 Object nextName = names.nextElement(); 94 95 if(nextName != StyleConstants.ResolveAttribute) { 96 retBuffer.append(" "); 97 retBuffer.append(nextName); 98 retBuffer.append("="); 99 retBuffer.append(as.getAttribute(nextName)); 100 } 101 } 102 retBuffer.append(" ]"); 103 asString = retBuffer.toString(); 104 } 105 else 106 asString = "[ ]"; 107 108 if(e.isLeaf()) 109 return e.getName() + " [" + e.getStartOffset() + 110 ", " + e.getEndOffset() +"] Attributes: " + asString; 111 return e.getName() + " [" + e.getStartOffset() + 112 ", " + e.getEndOffset() + "] Attributes: " + 113 asString; 114 } 115 }; 116 tree.addTreeSelectionListener(this); 117 tree.setDragEnabled(true); 118 tree.setRootVisible(false); 120 tree.setCellRenderer(new DefaultTreeCellRenderer() { 127 public Dimension getPreferredSize() { 128 Dimension retValue = super.getPreferredSize(); 129 if(retValue != null) 130 retValue.width += 15; 131 return retValue; 132 } 133 }); 134 document.addDocumentListener(this); 136 137 editor.addPropertyChangeListener(this); 140 141 editor.addCaretListener(this); 143 144 setLayout(new BorderLayout()); 146 add(new JScrollPane(tree), BorderLayout.CENTER); 147 148 JLabel label = new JLabel("Elements that make up the current document", SwingConstants.CENTER); 150 151 label.setFont(new Font("Dialog", Font.BOLD, 14)); 152 add(label, BorderLayout.NORTH); 153 154 setPreferredSize(new Dimension(400, 400)); 155 } 156 157 161 public void setEditor(JTextComponent editor) { 162 if (this.editor == editor) { 163 return; 164 } 165 166 if (this.editor != null) { 167 Document oldDoc = this.editor.getDocument(); 168 169 oldDoc.removeDocumentListener(this); 170 this.editor.removePropertyChangeListener(this); 171 this.editor.removeCaretListener(this); 172 } 173 this.editor = editor; 174 if (editor == null) { 175 treeModel = null; 176 tree.setModel(null); 177 } 178 else { 179 Document newDoc = editor.getDocument(); 180 181 newDoc.addDocumentListener(this); 182 editor.addPropertyChangeListener(this); 183 editor.addCaretListener(this); 184 treeModel = new ElementTreeModel(newDoc); 185 tree.setModel(treeModel); 186 } 187 } 188 189 191 195 public void propertyChange(PropertyChangeEvent e) { 196 if (e.getSource() == getEditor() && 197 e.getPropertyName().equals("document")) { 198 JTextComponent editor = getEditor(); 199 Document oldDoc = (Document)e.getOldValue(); 200 Document newDoc = (Document)e.getNewValue(); 201 202 oldDoc.removeDocumentListener(this); 204 newDoc.addDocumentListener(this); 205 206 treeModel = new ElementTreeModel(newDoc); 208 tree.setModel(treeModel); 209 } 210 } 211 212 213 215 221 public void insertUpdate(DocumentEvent e) { 222 updateTree(e); 223 } 224 225 232 public void removeUpdate(DocumentEvent e) { 233 updateTree(e); 234 } 235 236 241 public void changedUpdate(DocumentEvent e) { 242 updateTree(e); 243 } 244 245 247 251 public void caretUpdate(CaretEvent e) { 252 if(!updatingSelection) { 253 JTextComponent editor = getEditor(); 254 int selBegin = Math.min(e.getDot(), e.getMark()); 255 int end = Math.max(e.getDot(), e.getMark()); 256 Vector paths = new Vector(); 257 TreeModel model = getTreeModel(); 258 Object root = model.getRoot(); 259 int rootCount = model.getChildCount(root); 260 261 for(int counter = 0; counter < rootCount; counter++) { 264 int start = selBegin; 265 266 while(start <= end) { 267 TreePath path = getPathForIndex(start, root, 268 (Element)model.getChild(root, counter)); 269 Element charElement = (Element)path. 270 getLastPathComponent(); 271 272 paths.addElement(path); 273 if(start >= charElement.getEndOffset()) 274 start++; 275 else 276 start = charElement.getEndOffset(); 277 } 278 } 279 280 int numPaths = paths.size(); 282 283 if(numPaths > 0) { 284 TreePath[] pathArray = new TreePath[numPaths]; 285 286 paths.copyInto(pathArray); 287 updatingSelection = true; 288 try { 289 getTree().setSelectionPaths(pathArray); 290 getTree().scrollPathToVisible(pathArray[0]); 291 } 292 finally { 293 updatingSelection = false; 294 } 295 } 296 } 297 } 298 299 301 305 public void valueChanged(TreeSelectionEvent e) { 306 JTree tree = getTree(); 307 308 if(!updatingSelection && tree.getSelectionCount() == 1) { 309 TreePath selPath = tree.getSelectionPath(); 310 Object lastPathComponent = selPath.getLastPathComponent(); 311 312 if(!(lastPathComponent instanceof DefaultMutableTreeNode)) { 313 Element selElement = (Element)lastPathComponent; 314 315 updatingSelection = true; 316 try { 317 getEditor().select(selElement.getStartOffset(), 318 selElement.getEndOffset()); 319 } 320 finally { 321 updatingSelection = false; 322 } 323 } 324 } 325 } 326 327 329 332 protected JTree getTree() { 333 return tree; 334 } 335 336 339 protected JTextComponent getEditor() { 340 return editor; 341 } 342 343 346 public DefaultTreeModel getTreeModel() { 347 return treeModel; 348 } 349 350 354 protected void updateTree(DocumentEvent event) { 355 updatingSelection = true; 356 try { 357 TreeModel model = getTreeModel(); 358 Object root = model.getRoot(); 359 360 for(int counter = model.getChildCount(root) - 1; counter >= 0; 361 counter--) { 362 updateTree(event, (Element)model.getChild(root, counter)); 363 } 364 } 365 finally { 366 updatingSelection = false; 367 } 368 } 369 370 378 protected void updateTree(DocumentEvent event, Element element) { 379 DocumentEvent.ElementChange ec = event.getChange(element); 380 381 if (ec != null) { 382 Element[] removed = ec.getChildrenRemoved(); 383 Element[] added = ec.getChildrenAdded(); 384 int startIndex = ec.getIndex(); 385 386 if(removed != null && removed.length > 0) { 388 int[] indices = new int[removed.length]; 389 390 for(int counter = 0; counter < removed.length; counter++) { 391 indices[counter] = startIndex + counter; 392 } 393 getTreeModel().nodesWereRemoved((TreeNode)element, indices, 394 removed); 395 } 396 if(added != null && added.length > 0) { 398 int[] indices = new int[added.length]; 399 400 for(int counter = 0; counter < added.length; counter++) { 401 indices[counter] = startIndex + counter; 402 } 403 getTreeModel().nodesWereInserted((TreeNode)element, indices); 404 } 405 } 406 if(!element.isLeaf()) { 407 int startIndex = element.getElementIndex 408 (event.getOffset()); 409 int elementCount = element.getElementCount(); 410 int endIndex = Math.min(elementCount - 1, 411 element.getElementIndex 412 (event.getOffset() + event.getLength())); 413 414 if(startIndex > 0 && startIndex < elementCount && 415 element.getElement(startIndex).getStartOffset() == 416 event.getOffset()) { 417 startIndex--; 419 } 420 if(startIndex != -1 && endIndex != -1) { 421 for(int counter = startIndex; counter <= endIndex; counter++) { 422 updateTree(event, element.getElement(counter)); 423 } 424 } 425 } 426 else { 427 getTreeModel().nodeChanged((TreeNode)element); 429 } 430 } 431 432 435 protected TreePath getPathForIndex(int position, Object root, 436 Element rootElement) { 437 TreePath path = new TreePath(root); 438 Element child = rootElement.getElement 439 (rootElement.getElementIndex(position)); 440 441 path = path.pathByAddingChild(rootElement); 442 path = path.pathByAddingChild(child); 443 while(!child.isLeaf()) { 444 child = child.getElement(child.getElementIndex(position)); 445 path = path.pathByAddingChild(child); 446 } 447 return path; 448 } 449 450 451 465 public static class ElementTreeModel extends DefaultTreeModel { 466 protected Element[] rootElements; 467 468 public ElementTreeModel(Document document) { 469 super(new DefaultMutableTreeNode("root"), false); 470 rootElements = document.getRootElements(); 471 } 472 473 484 public Object getChild(Object parent, int index) { 485 if(parent == root) 486 return rootElements[index]; 487 return super.getChild(parent, index); 488 } 489 490 491 500 public int getChildCount(Object parent) { 501 if(parent == root) 502 return rootElements.length; 503 return super.getChildCount(parent); 504 } 505 506 507 517 public boolean isLeaf(Object node) { 518 if(node == root) 519 return false; 520 return super.isLeaf(node); 521 } 522 523 526 public int getIndexOfChild(Object parent, Object child) { 527 if(parent == root) { 528 for(int counter = rootElements.length - 1; counter >= 0; 529 counter--) { 530 if(rootElements[counter] == child) 531 return counter; 532 } 533 return -1; 534 } 535 return super.getIndexOfChild(parent, child); 536 } 537 538 542 public void nodeChanged(TreeNode node) { 543 if(listenerList != null && node != null) { 544 TreeNode parent = node.getParent(); 545 546 if(parent == null && node != root) { 547 parent = root; 548 } 549 if(parent != null) { 550 int anIndex = getIndexOfChild(parent, node); 551 552 if(anIndex != -1) { 553 int[] cIndexs = new int[1]; 554 555 cIndexs[0] = anIndex; 556 nodesChanged(parent, cIndexs); 557 } 558 } 559 } 560 } 561 562 565 protected TreeNode[] getPathToRoot(TreeNode aNode, int depth) { 566 TreeNode[] retNodes; 567 568 570 if(aNode == null) { 571 if(depth == 0) 572 return null; 573 else 574 retNodes = new TreeNode[depth]; 575 } 576 else { 577 depth++; 578 if(aNode == root) 579 retNodes = new TreeNode[depth]; 580 else { 581 TreeNode parent = aNode.getParent(); 582 583 if(parent == null) 584 parent = root; 585 retNodes = getPathToRoot(parent, depth); 586 } 587 retNodes[retNodes.length - depth] = aNode; 588 } 589 return retNodes; 590 } 591 } 592 } 593 | Popular Tags |