001package arcommon.ui.component; 002 003import java.awt.event.ActionEvent; 004import java.awt.event.ActionListener; 005import java.awt.event.KeyListener; 006import java.awt.event.MouseListener; 007import java.util.ArrayList; 008import java.util.Collection; 009import java.util.HashMap; 010import java.util.Iterator; 011import java.util.List; 012import java.util.Map; 013import java.util.NoSuchElementException; 014 015import javax.swing.JComponent; 016import javax.swing.JTree; 017import javax.swing.SwingUtilities; 018import javax.swing.event.TreeSelectionEvent; 019import javax.swing.event.TreeSelectionListener; 020import javax.swing.plaf.metal.MetalTreeUI; 021import javax.swing.tree.DefaultMutableTreeNode; 022import javax.swing.tree.DefaultTreeSelectionModel; 023import javax.swing.tree.TreePath; 024 025import arcommon.DateUtil; 026import arcommon.MyTimer; 027import arcommon.ui.other.GUIUtil; 028 029/** 030 * A {@link javax.swing.JTree} that is wrapped in a {@link javax.swing.JScrollPane}. 031 */ 032public class MyJTree extends AbstractDelegatingJScrollPane { 033 034 private class TreeSelectionModel extends DefaultTreeSelectionModel { 035 public void addSelectionPaths(TreePath[] paths) { 036 super.addSelectionPaths(paths); 037 } 038 039 public void removeSelectionPaths(TreePath[] paths) { 040 super.removeSelectionPaths(paths); 041 } 042 043 public void setSelectionPathsHack(TreePath[] pPaths) { 044 super.setSelectionPaths(pPaths); 045 } 046 047 public void setSelectionPaths(TreePath[] pPaths) { 048 // HACK!!!! Doesn't set SelectionPaths. It just toggles those who came in the pPaths!! 049 ArrayList<TreePath> newPath = new ArrayList<TreePath>(); 050 TreePath[] oldPath = tree.getSelectionPaths(); 051 for (int i = 0; oldPath != null && i < oldPath.length; i++) { 052 newPath.add(oldPath[i]); 053 } 054 for (int i = 0; i < pPaths.length; i++) { 055 int index = newPath.indexOf(pPaths[i]); 056 if (index == -1) { 057 newPath.add(pPaths[i]); 058 } else { 059 newPath.remove(pPaths[i]); 060 } 061 } 062 TreePath[] result = new TreePath[newPath.size()]; 063 for (int i = 0; i < newPath.size(); i++) { 064 result[i] = newPath.get(i); 065 } 066 super.setSelectionPaths(result); 067 } 068 069 private static final long serialVersionUID = 5532569881521634626L; 070 } 071 072 private JTree tree; 073 private Object treeSynchronizeObject; 074 private DefaultMutableTreeNode topNode; 075 private TreeSelectionModel treeSelectionModel; 076 private boolean multiSelect; 077 private ActionListener selectLastActionListener; 078 private boolean removeFirstLetterNavigation; 079 080 public MyJTree() { 081 this(false); 082 } 083 084 public MyJTree(boolean pmultiSelect) { 085 topNode = new DefaultMutableTreeNode(); 086 087 tree = new JTree(topNode) { 088 private static final long serialVersionUID = 6713466064903508999L; 089 090 public void addKeyListener(KeyListener keyListener) { 091 if (removeFirstLetterNavigation && isFirstLetterNavigationKeyListener(keyListener)) { 092 return ; 093 } 094 super.addKeyListener(keyListener); 095 } 096 }; 097 098 initActionMap(); 099 100 setViewportView(tree); 101 102 tree.setRootVisible(false); 103 104 tree.setUI(new MetalTreeUI() { 105 // This is probably a hack, but it is unknown of what 106 protected MouseListener createMouseListener() { 107 return null; 108 } 109 }); 110 111 treeSynchronizeObject = new Object(); 112 113 setMultiSelection(pmultiSelect); 114 } 115 116 public void setToggleSelection(boolean toggleSelect) { 117 if (toggleSelect) { 118 treeSelectionModel = new TreeSelectionModel(); 119 tree.setSelectionModel(treeSelectionModel); 120 } else { 121 setMultiSelection(multiSelect); 122 } 123 } 124 125 public void setMultiSelection(boolean pmultiSelect) { 126 multiSelect = pmultiSelect; 127 DefaultTreeSelectionModel defaultTreeSelectionModel = new DefaultTreeSelectionModel(); 128 if (multiSelect) { 129 defaultTreeSelectionModel.setSelectionMode(DefaultTreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); 130 } else { 131 defaultTreeSelectionModel.setSelectionMode(DefaultTreeSelectionModel.SINGLE_TREE_SELECTION); 132 } 133 treeSelectionModel = null; 134 tree.setSelectionModel(defaultTreeSelectionModel); 135 } 136 137 public void setNodes(DefaultMutableTreeNode pnode) { 138 synchronized (treeSynchronizeObject) { 139 Object[] selectedObjects = getSelectedUserObjects(); 140 141 update(topNode, pnode); 142 143 expandNode(topNode); 144 145 if (selectedObjects != null) { 146 setSelectedUserObjects(selectedObjects); 147 } 148 149 forceUpdate(); 150 } 151 } 152 153 public void addNodes(DefaultMutableTreeNode pnodes) { 154 if (pnodes == null) { 155 return ; 156 } 157 158 synchronized (treeSynchronizeObject) { 159 addNodesLocal(topNode, pnodes); 160 161 forceUpdate(); 162 } 163 } 164 165 public void removeNodes(DefaultMutableTreeNode pnodes) { 166 if (pnodes == null) { 167 return ; 168 } 169 170 synchronized (treeSynchronizeObject) { 171 removeNodesLocal(topNode, pnodes); 172 173 forceUpdate(); 174 } 175 } 176 177 private ActionListener updateActionListener; 178 private int count = 0; 179 private long lastUpdate = System.currentTimeMillis(); 180 private int numberOfUpdatesInProgress = 0; 181 182 public void forceUpdate() { 183 long now = System.currentTimeMillis(); 184 if (now > lastUpdate + DateUtil.SECOND_IN_MILLISECONDS * 10) { 185 count = 0; 186 lastUpdate = now; 187 } 188 189 if (count++ > 10 || updateActionListener != null) { 190 if (updateActionListener == null) { 191 lastUpdate = now; 192 updateActionListener = new ActionListener() { 193 public void actionPerformed(ActionEvent e) { 194 if (count > 20) { 195 count = 15; 196 } else { 197 count -= 5; 198 if (count <= 0) { 199 ActionListener tempActionListener = updateActionListener; 200 updateActionListener = null; 201 if (tempActionListener != null) { 202 MyTimer.removeActionListener(tempActionListener); 203 } 204 } 205 } 206 forceUpdateLocal(); 207 } 208 209 public String toString() { 210 return super.toString() + " " + MyJTree.this.toString() + " " + MyJTree.this.getParent().toString(); 211 } 212 }; 213 MyTimer.addActionListener(10, updateActionListener); 214 } 215 return ; 216 } 217 218 forceUpdateLocal(); 219 } 220 221 private void forceUpdateLocal() { 222 if (numberOfUpdatesInProgress > 0) { 223 return ; 224 } 225 226 numberOfUpdatesInProgress++; 227 Runnable runnable = new Runnable() { 228 public void run() { 229 tree.updateUI(); 230 231 numberOfUpdatesInProgress--; 232 } 233 }; 234 SwingUtilities.invokeLater(runnable); 235 } 236 237 public void dispose() { 238 if (updateActionListener != null) { 239 MyTimer.removeActionListener(updateActionListener); 240 updateActionListener = null; 241 } 242 } 243 244 public DefaultMutableTreeNode getTopNode() { 245 return topNode; 246 } 247 248 private void update(DefaultMutableTreeNode oldParentNode, DefaultMutableTreeNode newParentNode) { 249/* int offset = 0; 250 int number = 0; 251 if (newParentNode != null) { 252 Map<Object, Integer> userObjectToIndex = new HashMap<Object, Integer>(); 253 for (int i = 0; i < oldParentNode.getChildCount(); i++) { 254 DefaultMutableTreeNode tempNode = (DefaultMutableTreeNode)oldParentNode.getChildAt(i); 255 userObjectToIndex.put(tempNode.getUserObject(), Integer.valueOf(i)); 256 } 257 258 for (int i = 0; i < newParentNode.getChildCount(); i++) { 259 DefaultMutableTreeNode newNode = (DefaultMutableTreeNode)newParentNode.getChildAt(i); 260 if (offset + i < oldParentNode.getChildCount()) { 261 DefaultMutableTreeNode oldNode = (DefaultMutableTreeNode)oldParentNode.getChildAt(offset + i); 262 if (newNode.getUserObject() == oldNode.getUserObject()) { // This should NOT be "equals()" 263 update(oldNode, newNode); 264 continue; 265 } 266 267 if (newNode.getUserObject().equals(oldNode.getUserObject())) { // This should be "equals()" 268 oldNode.setUserObject(newNode.getUserObject()); // Copy the UserObject from the newNode to the oldNode. 269 update(oldNode, newNode); 270 continue; 271 } 272 } 273 274 Integer index = userObjectToIndex.get(newNode.getUserObject()); 275 int oldNodeIndex = (index == null) ? -1 : index.intValue(); 276 277 if (oldNodeIndex != -1) { 278 if (oldNodeIndex < i) { 279// throw new RuntimeException("oldNodeIndex < i " + oldNodeIndex + " < " + i); 280 System.out.println("oldNodeIndex < i " + oldNodeIndex + " < " + i + " " + newNode.getUserObject()); 281 return ; 282 } 283 284 DefaultMutableTreeNode tempNode = (DefaultMutableTreeNode)oldParentNode.getChildAt(oldNodeIndex); 285 oldParentNode.insert(tempNode, offset + i); // Note: The node is moved inside old. 286 tempNode.setUserObject(newNode.getUserObject()); // Copy the UserObject from the newNode to the tempNode. 287 update(tempNode, newNode); 288 continue; 289 } 290 291 oldParentNode.insert(newNode, offset + i); // Note: The node is moved from new to old! 292 i--; 293 offset++; 294 } 295 296 number = newParentNode.getChildCount(); 297 } 298 299 for (int i = number + offset; i < oldParentNode.getChildCount(); i++) { 300 oldParentNode.remove(i); 301 i--; 302 }*/ 303 304 int newNodeCount = 0; 305 if (newParentNode != null) { 306 Map<Object, DefaultMutableTreeNode> userObjectToDefaultMutableTreeNode = new HashMap<Object, DefaultMutableTreeNode>(); 307 for (int i = 0; i < oldParentNode.getChildCount(); i++) { 308 DefaultMutableTreeNode tempNode = (DefaultMutableTreeNode)oldParentNode.getChildAt(i); 309 userObjectToDefaultMutableTreeNode.put(tempNode.getUserObject(), tempNode); 310 } 311 312 DefaultMutableTreeNode[] newNodes = new DefaultMutableTreeNode[newParentNode.getChildCount()]; 313 for (int i = 0; i < newParentNode.getChildCount(); i++) { 314 DefaultMutableTreeNode newNode = (DefaultMutableTreeNode)newParentNode.getChildAt(i); 315 316 DefaultMutableTreeNode oldNode = userObjectToDefaultMutableTreeNode.get(newNode.getUserObject()); 317 if (oldNode != null) { 318 newNodes[i] = oldNode; 319 // The UserObject in the oldNode and in the newNode are equals, but they are not necessarily "==" => move the UserObject from new to old to make them "==". 320 oldNode.setUserObject(newNode.getUserObject()); // Copy the UserObject from the newNode to the tempNode. 321 update(oldNode, newNode); 322 } else { 323 newNodes[i] = newNode; 324 } 325 } 326 327 for (int i = 0; i < newNodes.length; i++) { 328 DefaultMutableTreeNode newNode = newNodes[i]; 329 oldParentNode.insert(newNode, i); // Note: The node is moved from new to old! 330 } 331 332 newNodeCount = newNodes.length; 333 } 334 335 for (int i = newNodeCount; i < oldParentNode.getChildCount(); i++) { 336 oldParentNode.remove(i); 337 i--; 338 } 339 } 340 341 private void addNodesLocal(DefaultMutableTreeNode oldParentNode, DefaultMutableTreeNode newParentNode) { 342 if (newParentNode == null) { 343 return ; 344 } 345 346 for (int i = 0; i < newParentNode.getChildCount(); i++) { 347 DefaultMutableTreeNode newNode = (DefaultMutableTreeNode)newParentNode.getChildAt(i); 348 int oldNodeIndex = findNodeIndex(oldParentNode, newNode); 349 if (oldNodeIndex != -1) { 350 continue; 351 } 352 oldParentNode.add(newNode); // Note the side effect: The node is moved from new to old! 353 i--; 354 } 355 } 356 357 private void removeNodesLocal(DefaultMutableTreeNode oldParentNode, DefaultMutableTreeNode newParentNode) { 358 if (newParentNode.getChildCount() != oldParentNode.getChildCount()) { 359 // Removes nodes based on the assumption that the newParentNode exists in oldParentNode 360 oldParentNode.remove(newParentNode); 361 } else { 362 // Removes nodes based on indices 363 for (int i = 0; i < newParentNode.getChildCount(); i++) { 364 DefaultMutableTreeNode newNode = (DefaultMutableTreeNode)newParentNode.getChildAt(i); 365 int oldNodeIndex = findNodeIndex(newParentNode, newNode); 366 if (oldNodeIndex == -1) { 367 continue; 368 } 369 oldParentNode.remove(i); 370 } 371 } 372 } 373 374 private int findNodeIndex(DefaultMutableTreeNode parentNode, DefaultMutableTreeNode node) { 375 if (parentNode == null) { 376 return -1; 377 } 378 for (int i = 0; i < parentNode.getChildCount(); i++) { 379 DefaultMutableTreeNode tempNode = (DefaultMutableTreeNode)parentNode.getChildAt(i); 380 if (tempNode.getUserObject() == node.getUserObject()) { // This should NOT be "equals()" 381 return i; 382 } 383 } 384 return -1; 385 } 386 387 private DefaultMutableTreeNode findObjectInHierarchy(DefaultMutableTreeNode parentNode, Object userObject) { 388 if (parentNode == null) { 389 return null; 390 } 391 for (int i = 0; i < parentNode.getChildCount(); i++) { 392 DefaultMutableTreeNode tempNode = (DefaultMutableTreeNode)parentNode.getChildAt(i); 393 if (tempNode.getUserObject().equals(userObject)) { // This should be "equals()" 394 return tempNode; 395 } 396 397 DefaultMutableTreeNode foundNode = findObjectInHierarchy(tempNode, userObject); 398 if (foundNode != null) { 399 return foundNode; 400 } 401 } 402 return null; 403 } 404 405 private TreePath[] selectionPathsOverride; 406 407 public TreePath[] getSelectedTreePath() { 408 if (selectionPathsOverride != null) { 409 return selectionPathsOverride; 410 } 411 TreePath[] selectionPaths; 412 synchronized (treeSynchronizeObject) { 413 selectionPaths = tree.getSelectionPaths(); 414 } 415 return selectionPaths; 416 } 417 418 public DefaultMutableTreeNode[] getSelectedNodes() { 419 TreePath[] selectionPaths = getSelectedTreePath(); 420 if (selectionPaths == null) { 421 return null; 422 } 423 if (selectionPaths.length == 0) { 424 return null; 425 } 426 List<DefaultMutableTreeNode> result = new ArrayList<DefaultMutableTreeNode>(); 427 for (int i = 0; i < selectionPaths.length; i++) { 428 if (selectionPaths[i] != null) { 429 result.add((DefaultMutableTreeNode)selectionPaths[i].getLastPathComponent()); 430 } 431 } 432 return result.toArray(new DefaultMutableTreeNode[result.size()]); 433 } 434 435 public Object getSelectedUserObject() { 436 Object[] selectedObjects = getSelectedUserObjects(); 437 if (selectedObjects == null || selectedObjects.length == 0) { 438 return null; 439 } 440 return selectedObjects[0]; 441 } 442 443 public Object[] getSelectedUserObjects() { 444 DefaultMutableTreeNode[] selectedNodes = getSelectedNodes(); 445 if (selectedNodes == null) { 446 return null; 447 } 448 if (selectedNodes.length == 0) { 449 return null; 450 } 451 Object[] result = new Object[selectedNodes.length]; 452 for (int i = 0; i < selectedNodes.length; i++) { 453 result[i] = selectedNodes[i].getUserObject(); 454 } 455 return result; 456 } 457 458 public void setSelectedUserObject(Object selectedObject) { 459 setSelectedUserObject(selectedObject, false); 460 } 461 462 public void setSelectedUserObject(Object selectedObject, boolean notify) { 463 if (selectedObject == null) { 464 setSelectedPaths(new TreePath[0], notify); 465 return ; 466 } 467 TreePath[] selectedPath = new TreePath[1]; 468 DefaultMutableTreeNode selectedNode = findObjectInHierarchy(topNode, selectedObject); 469 if (selectedNode == null) { 470 setSelectedPaths(new TreePath[0], notify); 471 return ; 472 } 473 selectedPath[0] = new TreePath(selectedNode.getPath()); 474 setSelectedPaths(selectedPath, notify); 475 } 476 477 public void setSelectedUserObjects(Collection<?> selectedObjects) { 478 setSelectedUserObjects(selectedObjects, false); 479 } 480 481 public void setSelectedUserObjects(Collection<?> selectedObjects, boolean notify) { 482 TreePath[] selectedPath = new TreePath[selectedObjects.size()]; 483 Iterator<?> i = selectedObjects.iterator(); 484 int index = 0; 485 while (i.hasNext()) { 486 Object selectedObject = i.next(); 487 DefaultMutableTreeNode selectedNode = findObjectInHierarchy(topNode, selectedObject); 488 if (selectedNode == null) { 489 continue; 490 } 491 selectedPath[index++] = new TreePath(selectedNode.getPath()); 492 } 493 setSelectedPaths(selectedPath, notify); 494 } 495 496 public void setSelectedUserObjects(Object[] selectedObjects) { 497 setSelectedUserObjects(selectedObjects, false); 498 } 499 500 public void setSelectedUserObjects(Object[] selectedObjects, boolean notify) { 501 TreePath[] selectedPath = new TreePath[selectedObjects.length]; 502 for (int i = 0; i < selectedObjects.length; i++) { 503 DefaultMutableTreeNode selectedNode = findObjectInHierarchy(topNode, selectedObjects[i]); 504 if (selectedNode == null) { 505 continue; 506 } 507 selectedPath[i] = new TreePath(selectedNode.getPath()); 508 } 509 setSelectedPaths(selectedPath, notify); 510 } 511 512 public void setSelectedNode(DefaultMutableTreeNode selectedNode) { 513 setSelectedNode(selectedNode, false); 514 } 515 516 public void setSelectedNode(DefaultMutableTreeNode selectedNode, boolean notify) { 517 if (selectedNode == null) { 518 return ; 519 } 520 DefaultMutableTreeNode[] defaultMutableTreeNode = new DefaultMutableTreeNode[1]; 521 defaultMutableTreeNode[0] = selectedNode; 522 setSelectedNodes(defaultMutableTreeNode, notify); 523 } 524 525 public void setSelectedNodes(DefaultMutableTreeNode[] selectedNode) { 526 setSelectedNodes(selectedNode, false); 527 } 528 529 public void setSelectedNodes(DefaultMutableTreeNode[] selectedNode, boolean notify) { 530 TreePath[] selectedPath = new TreePath[selectedNode.length]; 531 for (int i = 0; i < selectedNode.length; i++) { 532 selectedPath[i] = new TreePath(selectedNode[i].getPath()); 533 } 534 setSelectedPaths(selectedPath, notify); 535 } 536 537 public void setSelectedPaths(TreePath[] selectedPath) { 538 setSelectedPaths(selectedPath, false); 539 } 540 541 public void setSelectedPaths(TreePath[] selectedPath, boolean notify) { 542 final TreePath[] oldSelectedPathFinal = getSelectedTreePath(); 543 selectionPathsOverride = selectedPath; // Must be placed after oldSelectedPathFinal = getSelectedTreePath(), because otherwise oldSelectedPathFinal will be = selectionPathsOverride. 544 final TreePath[] selectedPathFinal = selectedPath; 545 final boolean notifyFinal = notify; 546 Runnable runnable = new Runnable() { 547 public void run() { 548 TreeSelectionListener[] treeSelectionListeners = null; 549 synchronized (treeSynchronizeObject) { 550 treeSelectionListeners = tree.getTreeSelectionListeners(); 551 for (int i = 0; i < treeSelectionListeners.length; i++) { 552 tree.removeTreeSelectionListener(treeSelectionListeners[i]); 553 } 554 if (treeSelectionModel != null) { 555 treeSelectionModel.setSelectionPathsHack(selectedPathFinal); // HACK 556 } else { 557 tree.setSelectionPaths(selectedPathFinal); // => NullPointerException?? 558 } 559 560 if (selectedPathFinal != null && selectedPathFinal.length > 0 && (oldSelectedPathFinal == null || oldSelectedPathFinal.length == 0 || (selectedPathFinal[0] != null && !selectedPathFinal[0].equals(oldSelectedPathFinal[0])))) { 561 scrollToVisible(selectedPathFinal[0]); 562 } 563 564 if (treeSelectionListeners != null) { 565 for (int i = 0; i < treeSelectionListeners.length; i++) { 566 tree.addTreeSelectionListener(treeSelectionListeners[i]); 567 } 568 } 569 } 570 571 if (notifyFinal) { // The call to tree.setSelectionPath(null) will not cause an event, therefore it is made manually. 572 fireSelectionListener(); 573 } 574 575 if (selectedPathFinal == selectionPathsOverride) { 576 selectionPathsOverride = null; 577 } 578 } 579 }; 580 SwingUtilities.invokeLater(runnable); 581 } 582 583 public void scrollSelectedToCenterVisibleInvokeLater() { 584 Runnable runnable = new Runnable() { 585 public void run() { 586 scrollSelectedToCenterVisible(); 587 } 588 }; 589 SwingUtilities.invokeLater(runnable); 590 } 591 592 public void scrollSelectedToCenterVisible() { 593 DefaultMutableTreeNode[] selectedNodes = getSelectedNodes(); 594 if (selectedNodes != null && selectedNodes.length > 0) { 595 TreePath selectedPath = new TreePath(selectedNodes[0].getPath()); 596 scrollToCenterVisible(selectedPath); 597 } 598 } 599 600 public void scrollToCenterVisible(TreePath selectedPath) { 601 int height = getHeight(); 602 int rowHeight = tree.getRowHeight(); 603 if (rowHeight == 0) { 604 rowHeight = 18; 605 } 606 607 int centerRowOffset = height / 5 / rowHeight; 608 int rowForPath = tree.getRowForPath(selectedPath); 609 tree.scrollRowToVisible(rowForPath - centerRowOffset); 610 tree.scrollRowToVisible(rowForPath + centerRowOffset); 611 } 612 613 public void scrollSelectedToVisibleInvokeLater() { 614 Runnable runnable = new Runnable() { 615 public void run() { 616 scrollSelectedToVisible(); 617 } 618 }; 619 SwingUtilities.invokeLater(runnable); 620 } 621 622 public void scrollSelectedToVisible() { 623 DefaultMutableTreeNode[] selectedNodes = getSelectedNodes(); 624 if (selectedNodes != null && selectedNodes.length > 0) { 625 TreePath selectedPath = new TreePath(selectedNodes[0].getPath()); 626 scrollToVisible(selectedPath); 627 } 628 } 629 630 public void scrollToVisible(TreePath selectedPath) { 631 tree.scrollPathToVisible(selectedPath); 632 } 633 634 public void fireSelectionListener() { 635 fireSelectionListener(null); 636 } 637 638 public void fireSelectionListener(TreeSelectionEvent e) { 639 TreeSelectionListener[] tempTreeSelectionListeners = tree.getTreeSelectionListeners(); 640 for (int i = 0; i < tempTreeSelectionListeners.length; i++) { 641 tempTreeSelectionListeners[i].valueChanged(e); 642 } 643 } 644 645 public void selectFirstElement() { 646 selectFirstElement(false); 647 } 648 649 public void selectFirstElement(boolean notify) { 650 if (getSelectedUserObject() != null) { 651 return ; 652 } 653 if (topNode.getChildCount() > 0) { 654 DefaultMutableTreeNode node = (DefaultMutableTreeNode)topNode.getChildAt(0); 655 setSelectedUserObject(node.getUserObject(), notify); 656 } else { 657 setSelectedUserObject(null, notify); 658 } 659 } 660 661 public void selectNextSibling() { 662 TreePath[] selectedTreePath = getSelectedTreePath(); 663 if (selectedTreePath == null) { 664 return ; 665 } 666 TreePath treePath = selectedTreePath[0]; 667 DefaultMutableTreeNode node = (DefaultMutableTreeNode)treePath.getLastPathComponent(); 668 while (node != null) { 669 DefaultMutableTreeNode parent = (DefaultMutableTreeNode)node.getParent(); 670 if (parent == null) { 671 return ; 672 } 673 DefaultMutableTreeNode childAfter = (DefaultMutableTreeNode)parent.getChildAfter(node); 674 if (childAfter != null) { 675 setSelectedNode(childAfter); 676 return ; 677 } 678 node = parent; 679 } 680 } 681 682 public void selectLastElement() { 683 if (getSelectedUserObject() != null) { 684 return ; 685 } 686 if (selectLastActionListener == null) { 687 selectLastActionListener = new ActionListener() { 688 public void actionPerformed(final ActionEvent e) { 689 final ActionListener actionListener = this; 690 Runnable runnable = new Runnable() { 691 public void run() { 692 eventSelectLastElementActionPerformed(e, actionListener); 693 } 694 }; 695 SwingUtilities.invokeLater(runnable); 696 } 697 }; 698 } 699 MyTimer.addActionListener(1, selectLastActionListener); 700 } 701 702 private void eventSelectLastElementActionPerformed(ActionEvent e, ActionListener actionListener) { 703 if (!selectLastElementLocal()) { 704 return ; 705 } 706 MyTimer.removeActionListener(actionListener); 707 if (actionListener == selectLastActionListener) { 708 selectLastActionListener = null; 709 } 710 } 711 712 private boolean selectLastElementLocal() { 713 try { 714 DefaultMutableTreeNode node = topNode.getLastLeaf(); 715 setSelectedUserObject(node.getUserObject(), true); 716 return scrollToTheBottom(); 717 } catch (NoSuchElementException e) { 718 setSelectedUserObject(null, true); 719 } 720 return true; 721 } 722 723 public void addTreeSelectionListener(TreeSelectionListener treeSelectionListener) { 724 synchronized (treeSynchronizeObject) { 725 tree.addTreeSelectionListener(treeSelectionListener); 726 } 727 } 728 729 public void removeTreeSelectionListener(TreeSelectionListener treeSelectionListener) { 730 synchronized (treeSynchronizeObject) { 731 tree.removeTreeSelectionListener(treeSelectionListener); 732 } 733 } 734 735 public TreeSelectionListener[] getTreeSelectionListeners() { 736 synchronized (treeSynchronizeObject) { 737 return tree.getTreeSelectionListeners(); 738 } 739 } 740 741 public void expandSelected() { 742 DefaultMutableTreeNode[] selectedNodes = getSelectedNodes(); 743 if (selectedNodes == null) { 744 return ; 745 } 746 for (int i = 0; i < selectedNodes.length; i++) { 747 expandTree(selectedNodes[i]); 748 } 749 } 750 751 public void expandAll() { 752 GUIUtil.expandTree(tree, topNode); 753 } 754 755 public void expandTree(DefaultMutableTreeNode parentDefaultMutableTreeNode) { 756 GUIUtil.expandTree(tree, parentDefaultMutableTreeNode); 757 } 758 759 public void expandNode(DefaultMutableTreeNode defaultMutableTreeNode) { 760 GUIUtil.expandTreeNode(tree, defaultMutableTreeNode); 761 } 762 763 public void collapseAll() { 764 GUIUtil.collapseTree(tree); 765 } 766 767 private static boolean isFirstLetterNavigationKeyListener(KeyListener keyListener) { // HACK 768 return keyListener.getClass().getName().startsWith("javax.swing.plaf.basic.BasicTreeUI$Handler"); 769 } 770 771 public void removeFirstLetterNavigation() { // HACK 772 removeFirstLetterNavigation = true; 773 KeyListener[] keyListeners = tree.getKeyListeners(); 774 for (int i = 0; i < keyListeners.length; i++) { 775 if (isFirstLetterNavigationKeyListener(keyListeners[i])) { 776 tree.removeKeyListener(keyListeners[i]); 777 } 778 } 779 } 780 781 @Override 782 protected JComponent getDelegatingJComponent() { 783 return tree; 784 } 785 786 private static final long serialVersionUID = -1212159756993599368L; 787}