View Javadoc
1 /*** 2 * PackageDepView.java 3 * 4 * Project: Dependency Tool 5 * 6 * WHEN WHO WHAT 7 * 06.06.2003 pko initial public release 8 * 13.06.2002 ctr creation 9 * 10 * Copyright 2003 ELCA Informatique SA 11 * Av. de la Harpe 22-24, 1000 Lausanne 13, Switzerland 12 * www.elca.ch 13 * 14 * This library is free software; you can redistribute it and/or 15 * modify it under the terms of the GNU Lesser General Public License 16 * as published by the Free Software Foundation; either version 2.1 of 17 * the License, or (at your option) any later version. 18 * 19 * This library is distributed in the hope that it will be useful, but 20 * WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 * Lesser General Public License for more details. 23 * 24 * You should have received a copy of the GNU Lesser General Public 25 * License along with this library; if not, write to the Free Software 26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 27 * USA 28 */ 29 30 package ch.elca.dependency.view; 31 32 import att.grappa.*; 33 import ch.elca.dependency.core.DependencyModel; 34 import ch.elca.dependency.util.IconGrabber; 35 import java.awt.*; 36 import info.clearthought.layout.TableLayout; 37 import java.awt.event.*; 38 import java.util.*; 39 import javax.swing.*; 40 import javax.swing.event.*; 41 import javax.swing.tree.*; 42 import org.apache.log4j.Logger; 43 44 /*** 45 * Tree with package dependencies. 46 * 47 * @see ch.elca.dependency.view.View 48 * 49 * @author Christoph Trutmann 50 * @version 1.0-beta 51 */ 52 public final class PackageDepView extends View { 53 54 //****************************************************************************************/ 55 // static fields 56 //****************************************************************************************/ 57 58 /*** 59 * Log4j Logger. 60 */ 61 private static final Logger LOG = Logger.getLogger(PackageDepView.class); 62 63 /*** 64 * Title used for this Frame. 65 */ 66 private final static String FRAME_TITLE = "Package Dependency View"; 67 68 //****************************************************************************************/ 69 // instance fields 70 //****************************************************************************************/ 71 72 /*** 73 * <code>ScrollPane</code> holding the tree. Supports add and 74 * remove for changing the tree. 75 */ 76 private JScrollPane m_treeView = null; 77 78 /*** 79 * Tree holding the package 'uses' dependencies. 80 */ 81 private JTree m_usesTree = null; 82 83 /*** 84 * Root of the 'uses' tree. 85 */ 86 private MyTreeNode m_usesTreeRoot = null; 87 88 /*** 89 * Tree holding the package 'is used' dependencies. 90 */ 91 private JTree m_isUsedTree = null; 92 93 /*** 94 * Root of the 'is used' tree. 95 */ 96 private MyTreeNode m_isUsedTreeRoot = null; 97 98 /*** 99 * Flag specifying whether the 'uses' or the 'is used' 100 * dependencies are shown. 101 */ 102 private boolean m_uses = true; 103 104 /*** 105 * Map containing the package dependencies. This is used for 106 * checking if a package is intern or extern of the project. 107 */ 108 private HashMap m_packDepend = null; 109 110 //****************************************************************************************/ 111 // create a PackageDepView 112 //****************************************************************************************/ 113 114 public PackageDepView(DependencyModel dependencyModel) { 115 super(dependencyModel, FRAME_TITLE); 116 setDefaultBounds(new Rectangle(665, 439, 271, 416)); 117 recallConfig(); 118 } 119 120 protected void internalInitData() { 121 m_packDepend = m_dependencyModel.getPackDepend(); 122 } 123 124 protected void initView(){ 125 126 // create menu bar 127 // 128 final JMenuBar menuBar = new JMenuBar(); 129 setJMenuBar(menuBar); 130 131 // build the menu for the dependency direction 132 // 133 JMenu dirMenu = new JMenu("Dependency Direction"); 134 dirMenu.setMnemonic(KeyEvent.VK_D); 135 menuBar.add(dirMenu); 136 137 // button group for the checkboxes 138 // 139 ButtonGroup group = new ButtonGroup(); 140 141 // build the menu item for performing the level algo 142 // 143 JRadioButtonMenuItem usesRadioItem = new JRadioButtonMenuItem("Uses"); 144 usesRadioItem.setSelected(true); 145 usesRadioItem.setMnemonic(KeyEvent.VK_U); 146 group.add(usesRadioItem); 147 usesRadioItem.addActionListener(new ActionListener() { 148 public void actionPerformed(ActionEvent e) { 149 LOG.info("Change tree to 'uses'..."); 150 m_uses = true; 151 changeTreeDepend(); 152 } 153 }); 154 dirMenu.add(usesRadioItem); 155 156 // build the menu item for performing the overview algo 157 // 158 JRadioButtonMenuItem isUsedRadioItem 159 = new JRadioButtonMenuItem("Is used"); 160 isUsedRadioItem.setMnemonic(KeyEvent.VK_I); 161 group.add(isUsedRadioItem); 162 isUsedRadioItem.addActionListener(new ActionListener() { 163 public void actionPerformed(ActionEvent e){ 164 LOG.info("Change tree to 'is uses'..."); 165 m_uses = false; 166 changeTreeDepend(); 167 } 168 }); 169 dirMenu.add(isUsedRadioItem); 170 171 // build the menu for selecting something 172 // 173 JMenu selectMenu = new JMenu("Select"); 174 selectMenu.setMnemonic(KeyEvent.VK_S); 175 menuBar.add(selectMenu); 176 177 // build the menu item for selecting a package 178 // 179 JMenuItem packItem = new JMenuItem("Select package", KeyEvent.VK_P); 180 packItem.addActionListener(new ActionListener() { 181 public void actionPerformed(ActionEvent e) { 182 LOG.info("Select a new package for the views."); 183 selectNewPackage(); 184 } 185 }); 186 selectMenu.add(packItem); 187 188 // configure TableLayout 189 // 190 double border = 10; 191 double fill = TableLayout.FILL; 192 double size[][] = 193 {{border, fill, border}, // Columns 194 {border, fill, border}}; // Rows 195 196 this.getContentPane().setLayout(new TableLayout(size)); 197 198 // create root nodes for the two trees 199 // 200 m_usesTreeRoot = new MyTreeNode("'uses' package dependencies"); 201 m_isUsedTreeRoot = new MyTreeNode("'is used' package dependencies"); 202 203 // construct the dependency tree for 'uses' dependencies 204 constructRootNodes(m_usesTreeRoot); 205 // construct the dependency tree for the 'is used' dependencies 206 m_uses = false; // set the flag for constructing the nodes 207 constructRootNodes(m_isUsedTreeRoot); 208 m_uses = true; // reset the flag for consistency 209 210 // construct tree for 'uses' dependencies 211 m_usesTree = constructTree(m_usesTreeRoot, "uses"); 212 // construct tree fot 'is used' dependencies 213 m_isUsedTree = constructTree(m_isUsedTreeRoot, "is used"); 214 215 //Create the scroll pane and add the tree to it. 216 m_treeView = new JScrollPane(m_usesTree); 217 218 // add the scroll pane to the frame 219 getContentPane().add(m_treeView, "1, 1, F, F"); 220 221 // set the parameters of the internal frame 222 setBackground(menuBar.getBackground()); 223 224 setVisible(true); 225 validate(); 226 227 } 228 229 230 /*** 231 * Helper method for constructing the two trees. 232 * 233 * @param root Root node of this tree. 234 * @return Tree with the appropriate parameters. 235 */ 236 private JTree constructTree(MyTreeNode root, String mode){ 237 JTree tree = new JTree(root); 238 // only one node can be selected at the same time 239 tree.getSelectionModel() 240 .setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); 241 tree.addTreeSelectionListener(new MyTreeSelectionListener()); 242 tree.addTreeExpansionListener(new MyTreeExpansionListener(mode, this)); 243 // determine the style of the table 244 tree.putClientProperty("JTree.lineStyle", "Angled"); 245 tree.setCellRenderer(new MyRenderer()); 246 247 return tree; 248 } 249 250 /*** 251 * Displays the <code>OverView</code> after the data has changed. 252 * This mehtod is individually implemented in each view. 253 */ 254 public void display() { 255 256 // display: reread classes according to the current perspective, which perhaps has changed since last display... 257 258 validate(); 259 setVisible(true); 260 } 261 262 263 /*** 264 * Selects all the packages in the specified list for all the views 265 * implementing the <code>Observer</code> interface. 266 * 267 * @param selectList List containing all the selected packages. 268 */ 269 public void select(ArrayList selectList) { 270 271 // clear old selection 272 // 273 clearSelection(); 274 275 // select package in both trees!! 276 // 277 for ( int i=0 ; i<2 ; i++ ) { 278 279 // iterator over all the selected packages 280 // 281 ListIterator iter = selectList.listIterator(); 282 283 // tree paths 284 // 285 ArrayList paths = new ArrayList(); 286 TreeNode root; 287 JTree tree; 288 if ( i == 0 ) { 289 root = m_usesTreeRoot; 290 tree = m_usesTree; 291 } 292 else { 293 root = m_isUsedTreeRoot; 294 tree = m_isUsedTree; 295 } 296 297 // define the path for each of the selected packages 298 // 299 while ( iter.hasNext() ) { 300 String tmp = (String)iter.next(); 301 302 // root and the selected package 303 // 304 TreeNode[] nodes = new TreeNode[2]; 305 nodes[0] = root; 306 307 // check each child if it is selected 308 // 309 Enumeration childEnum = root.children(); 310 while ( childEnum.hasMoreElements() ) { 311 MyTreeNode childTmp = (MyTreeNode)childEnum.nextElement(); 312 String childName = (String)childTmp.getUserObject(); 313 314 if ( childName.equals(tmp) ) { 315 nodes[1] = childTmp; 316 317 try { 318 DefaultMutableTreeNode expand 319 = (DefaultMutableTreeNode) 320 childTmp.getFirstChild(); // open the leaf 321 TreeNode[] nodesClone = (TreeNode[])nodes.clone(); 322 TreePath extPath = new TreePath(nodesClone) 323 .pathByAddingChild(expand); 324 325 // expand first child level of selected node 326 // 327 tree.getSelectionModel().addSelectionPath(extPath); 328 329 // but do not mark it 330 // 331 tree.getSelectionModel().removeSelectionPath(extPath); 332 333 // there is no child left -> ignore 334 // 335 } catch (NoSuchElementException nsee) { 336 } 337 } 338 } 339 if ( nodes[1] == null ) { 340 return; 341 } 342 TreePath newPath = new TreePath(nodes); 343 paths.add(newPath); 344 } 345 346 // fill the tree paths in the array 347 ListIterator pathIter = paths.listIterator(); 348 TreePath[] treePaths = new TreePath[paths.size()]; 349 int y = 0; 350 while ( pathIter.hasNext() ) { 351 treePaths[y] = (TreePath)pathIter.next(); 352 y++; 353 } 354 355 // add the new selection to the tree 356 tree.getSelectionModel().addSelectionPaths(treePaths); 357 358 // scroll to the first selected node 359 // 360 if (treePaths.length >= 1) { 361 tree.scrollPathToVisible(treePaths[0]); 362 } 363 } 364 365 // update the tree view 366 m_treeView.validate(); 367 m_treeView.updateUI(); 368 } 369 370 371 /*** 372 * Clears all the selections in all the views. 373 */ 374 public void clearSelection(){ 375 // collapse all the first child elements and clear the selection 376 for ( int i=0 ; i<2 ; i++ ) { 377 JTree tree; 378 TreeNode root; 379 if ( i == 0 ) { 380 tree = m_usesTree; 381 root = m_usesTreeRoot; 382 } 383 else { 384 tree = m_isUsedTree; 385 root = m_isUsedTreeRoot; 386 } 387 388 // clear selection 389 tree.clearSelection(); 390 391 // collapse first children 392 if ( root.getChildCount() >= 0 ) { 393 TreePath parent = new TreePath(root); 394 395 Enumeration childEnum = root.children(); 396 while ( childEnum.hasMoreElements() ) { 397 TreeNode nodeTmp = (TreeNode)childEnum.nextElement(); 398 TreePath path = parent.pathByAddingChild(nodeTmp); 399 400 tree.collapsePath(path); 401 } 402 } 403 } 404 } 405 406 407 /*** 408 * Helper method for creating the root nodes of the uses tree. 409 * 410 * @param top Root node of the dependency tree. 411 */ 412 private void constructRootNodes(MyTreeNode top){ 413 // get the package dependencies 414 HashMap packDepend = m_dependencyModel.getPackDepend(); 415 Object[] rootArr = packDepend.keySet().toArray(); 416 Arrays.sort(rootArr); 417 418 for ( int i=0 ; i<rootArr.length ; i++ ) { 419 String nameTmp = (String)rootArr[i]; 420 421 MyTreeNode newNode = new MyTreeNode(nameTmp); 422 top.add(newNode); 423 424 // distinct whether it is 'uses' or 'is used' 425 if ( m_uses ) { 426 addUsesChildren(newNode); 427 } else { 428 addIsUsedAncestors(newNode); 429 } 430 } 431 } 432 433 434 /*** 435 * Add the next children of the specified package. In the manner of the 436 * 'uses' dependency. 437 * 438 * @param node The node to add the children. 439 */ 440 private void addUsesChildren(MyTreeNode node){ 441 442 // don't add children if this node is not external already 443 // 444 if (!node.isLeaf()) { 445 return; 446 } 447 448 String nodeInfo = (String)node.getUserObject(); 449 450 HashMap dependMap = m_dependencyModel.getPackDepend(); 451 ArrayList childList = (ArrayList)dependMap.get(nodeInfo); 452 // there are no dependencies 453 if ( childList == null) { return; } 454 455 // sort the list in an ascending order 456 Collections.sort(childList); 457 458 ListIterator children = childList.listIterator(); 459 460 while ( children.hasNext() ) { 461 String nameTmp = (String)children.next(); 462 463 if ( ! nodeInfo.equals(nameTmp) ) { 464 MyTreeNode newNode 465 = new MyTreeNode(nameTmp); 466 467 // check if the package is extern 468 if ( ! m_packDepend.containsKey(nameTmp) ) { 469 newNode.iconType = MyTreeNode.EXTERN_ICON_TYPE; 470 } 471 472 try { 473 node.add(newNode); 474 // node cannot be added because of a cycle 475 } catch ( IllegalStateException ise ) {} 476 } 477 } 478 } 479 480 481 /*** 482 * Add the ancestors of the the specified package. In the manner of the 483 * 'is used' dependency. 484 * 485 * @param node The node to add the ancestors. 486 * 487 * @tbd grappa.... tobedone till thurs, !just a temporary solution! 488 */ 489 private void addIsUsedAncestors(MyTreeNode node){ 490 491 // don't add children if this node is not external already 492 // 493 if (!node.isLeaf()) { 494 return; 495 } 496 497 String nodeInfo = (String)node.getUserObject(); 498 Graph graph = m_dependencyModel.getFilteredGraph(); 499 500 // 501 // the node was either deleted, or aggregated... 502 // 503 504 // deleted ? -> just skip... 505 // aggregated ? -> find aggregate node... 506 507 Node nodeTmp = graph.findNodeByName(nodeInfo); 508 509 if (nodeTmp == null) { 510 return; 511 } 512 513 // fill the nodes in a list and sort it 514 // 515 ArrayList nodeList = new ArrayList(); 516 Enumeration inEnum = nodeTmp.inEdgeElements(); 517 while ( inEnum.hasMoreElements() ) { 518 Node ancestor = ((Edge)inEnum.nextElement()).getTail(); 519 String name = ancestor.getName(); 520 nodeList.add(name); 521 } 522 523 // sort the list with the nodes 524 // 525 Collections.sort(nodeList); 526 ListIterator nodeIter = nodeList.listIterator(); 527 while ( nodeIter.hasNext() ) { 528 String name = (String)nodeIter.next(); 529 530 if ( ! nodeInfo.equals(name) ) { 531 MyTreeNode newNode 532 = new MyTreeNode(name); 533 534 // check if the package is extern 535 // 536 if ( ! m_packDepend.containsKey(name) ) { 537 newNode.iconType = MyTreeNode.EXTERN_ICON_TYPE; 538 } 539 540 try { 541 node.add(newNode); 542 // node cannot be added because of a cycle 543 } catch ( IllegalStateException ise ) {} 544 } 545 } 546 } 547 548 /*** 549 * Changes the mode of the dependency of the package dependency tree. 550 */ 551 private void changeTreeDepend(){ 552 if ( m_uses ) { 553 m_treeView.getViewport().remove(m_isUsedTree); 554 m_treeView.getViewport().add(m_usesTree); 555 } 556 else { 557 m_treeView.getViewport().remove(m_usesTree); 558 m_treeView.getViewport().add(m_isUsedTree); 559 } 560 m_treeView.validate(); 561 m_treeView.updateUI(); 562 } 563 564 /*** 565 * Helper method for selecting a new package. 566 */ 567 private void selectNewPackage(){ 568 // determine the right tree to invoke 569 JTree tree; 570 if ( m_uses ) { 571 tree = m_usesTree; 572 } 573 else { 574 tree = m_isUsedTree; 575 } 576 // get selected componet 577 MyTreeNode nodeTmp 578 = (MyTreeNode)tree.getLastSelectedPathComponent(); 579 580 // nothing is selected 581 if ( nodeTmp == null ) { 582 return; 583 } 584 585 // extern packages can't be displayed 586 if ( nodeTmp.iconType.equals(MyTreeNode.EXTERN_ICON_TYPE) ) { 587 JOptionPane.showMessageDialog(this, 588 "Package of this class cannot be selected.\n" + 589 "It is outside of the project.\n", 590 "Extern package", JOptionPane.WARNING_MESSAGE); 591 return; 592 } 593 594 // get the name of the package 595 String name = (String)nodeTmp.getUserObject(); 596 597 // make the selection consistent 598 ArrayList selectList = new ArrayList(); 599 selectList.add(name); 600 m_dependencyModel.selectPackages(selectList); 601 } 602 603 /*** 604 * Helper class for handling the selection events of the two trees. 605 */ 606 class MyTreeSelectionListener implements TreeSelectionListener { 607 608 /*** 609 * Listener for the tree. 610 * 611 * @param e TreeSelectionEvent thrown by the 612 * <code>TreeSelectionListener</code>. 613 */ 614 public void valueChanged(TreeSelectionEvent e) { 615 // only do something if the 'select package' button is invoked 616 } 617 } 618 619 /*** 620 * Helper class for handling the expansion events of the two trees. 621 */ 622 class MyTreeExpansionListener implements TreeExpansionListener { 623 624 /*** 625 * Specifies whether it is a 'uses' or a 'is used' dependency tree. 626 */ 627 private String m_mode; 628 629 /*** 630 * Owner. 631 */ 632 private JInternalFrame m_frame; 633 634 /*** 635 * Constructor - Initialize the appropriate tree for application. 636 */ 637 public MyTreeExpansionListener(String mode, JInternalFrame frame){ 638 m_mode = mode; 639 m_frame = frame; 640 } 641 642 // Required by TreeExpansionListener interface. 643 public void treeExpanded(TreeExpansionEvent e) { 644 645 // add all the children of the expanded node. 646 MyTreeNode nodeTmp = (MyTreeNode)e.getPath().getLastPathComponent(); 647 648 TreePath path = e.getPath(); 649 int count = path.getPathCount(); 650 Object[] pathComps = path.getPath(); 651 652 // add the children of the nodes when expanded 653 Enumeration childEnum = nodeTmp.children(); 654 while ( childEnum.hasMoreElements() ) { 655 nodeTmp = (MyTreeNode)childEnum.nextElement(); 656 657 String name = (String)nodeTmp.getUserObject(); 658 659 for (int i=count-1 ; i>=0 ; i--) { 660 String tmp 661 = (String)((MyTreeNode)pathComps[i]) 662 .getUserObject(); 663 664 if ( tmp.equals(name) ) { 665 // mark the node 666 TreeNode[] nodes = nodeTmp.getPath(); 667 TreePath treePath = new TreePath(nodes); 668 669 if ( m_uses ) { 670 m_usesTree.getSelectionModel() 671 .addSelectionPath(treePath); 672 } 673 else if ( ! m_uses ) { 674 m_isUsedTree.getSelectionModel() 675 .addSelectionPath(treePath); 676 } 677 678 // change icon of the node with the icon 679 nodeTmp.iconType = MyTreeNode.CYCLE_ICON_TYPE; 680 nodeTmp.setAllowsChildren(false); 681 } 682 } 683 if ( m_mode.equals("uses") ) { 684 addUsesChildren(nodeTmp); 685 } 686 else { 687 addIsUsedAncestors(nodeTmp); 688 } 689 } 690 } 691 692 693 // Required by TreeExpansionListener interface. 694 public void treeCollapsed(TreeExpansionEvent e) { 695 LOG.info("Tree collapsed!"); 696 LOG.info("TreeExpansionPath " + e.getPath()); 697 } 698 } 699 700 701 /*** 702 * Class for rendering the trees. Particularly for setting the icons. 703 */ 704 private class MyRenderer extends DefaultTreeCellRenderer { 705 706 private ImageIcon m_packageIcon = IconGrabber.getIcon("package.gif"); 707 private ImageIcon m_extPackIcon = IconGrabber.getIcon("extPack.gif"); 708 private ImageIcon m_cycleIcon = IconGrabber.getIcon("sun.gif"); 709 710 /*** 711 * Configures the renderer based on the passed in components. 712 * The value is set from messaging the tree with 713 * <code>convertValueToText</code>, which ultimately invokes 714 * <code>toString</code> on <code>value</code>. 715 * The foreground color is set based on the selection and the icon 716 * is set based on on leaf and expanded. 717 */ 718 public Component getTreeCellRendererComponent(JTree tree, 719 Object value, 720 boolean sel, 721 boolean expanded, 722 boolean leaf, 723 int row, 724 boolean hasFocus) { 725 726 super.getTreeCellRendererComponent(tree, value, sel, 727 expanded, leaf, row, 728 hasFocus); 729 730 // current tree node 731 // 732 MyTreeNode treeNode = (MyTreeNode)value; 733 734 // default icon 735 // 736 if ( treeNode.iconType.equals("") ) { 737 setIcon(m_packageIcon); 738 } 739 // cycle icon 740 // 741 else if ( treeNode.iconType.equals("cycle") ) { 742 setIcon(m_cycleIcon); 743 } 744 // external package icon 745 // 746 else if ( treeNode.iconType.equals("ext") ) { 747 setIcon(m_extPackIcon); 748 } 749 return this; 750 } 751 } 752 }

This page was automatically generated by Maven