View Javadoc
1 /*** 2 * OverView.java 3 * 4 * Project: Dependency Tool 5 * 6 * WHEN WHO WHAT 7 * 06.06.2003 pko initial public release 8 * 08.01.2002 pko modification 9 * 22.01.2002 ctr modification 10 * 08.01.2002 ctr creation 11 * 12 * Copyright 2003 ELCA Informatique SA 13 * Av. de la Harpe 22-24, 1000 Lausanne 13, Switzerland 14 * www.elca.ch 15 * 16 * This library is free software; you can redistribute it and/or 17 * modify it under the terms of the GNU Lesser General Public License 18 * as published by the Free Software Foundation; either version 2.1 of 19 * the License, or (at your option) any later version. 20 * 21 * This library is distributed in the hope that it will be useful, but 22 * WITHOUT ANY WARRANTY; without even the implied warranty of 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 * Lesser General Public License for more details. 25 * 26 * You should have received a copy of the GNU Lesser General Public 27 * License along with this library; if not, write to the Free Software 28 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 29 * USA 30 */ 31 32 package ch.elca.dependency.view; 33 34 import java.awt.*; 35 import java.awt.event.ActionEvent; 36 import java.awt.event.ActionListener; 37 import java.awt.event.KeyEvent; 38 import java.io.File; 39 import java.io.FileNotFoundException; 40 import java.io.IOException; 41 import java.util.*; 42 import javax.swing.*; 43 import javax.swing.border.Border; 44 import javax.swing.border.CompoundBorder; 45 import javax.swing.border.TitledBorder; 46 import javax.swing.event.TreeSelectionEvent; 47 import javax.swing.event.TreeSelectionListener; 48 import javax.swing.tree.*; 49 50 import org.apache.log4j.Logger; 51 52 import ch.elca.dependency.core.DependencyContext; 53 import ch.elca.dependency.core.DependencyModel; 54 import ch.elca.dependency.util.IOManager; 55 import ch.elca.dependency.util.IconGrabber; 56 57 import info.clearthought.layout.TableLayout; 58 59 /*** 60 * A view class for diplaying the list and tree representations of the 61 * analyzed project. The display method of the <code>View</code> 62 * superclass is impemented in this specific view. This method is 63 * responsible for getting the needed data from the model and then 64 * show this actual data to the user.<br> All the user interaction 65 * which concerns only this view is also managed by this class.<br> 66 * Here a tree with all the packages and classes of the project is 67 * diplayed. Also some interaction with the graph view willbe added. 68 * 69 * @see ch.elca.dependency.view.View 70 * 71 * @author Christoph Trutmann 72 * @version 1.0-beta 73 */ 74 public final class OverView extends View implements TreeSelectionListener, ActionListener { 75 76 //****************************************************************************************/ 77 // static fields 78 //****************************************************************************************/ 79 80 /*** 81 * Log4j Logger. 82 */ 83 private final static Logger LOG = Logger.getLogger(OverView.class); 84 85 /*** 86 * Title used for this Frame 87 */ 88 private final static String FRAME_TITLE = "Project Structure View"; 89 90 //****************************************************************************************/ 91 // instance fields 92 //****************************************************************************************/ 93 94 /*** 95 * Abstract location of the input class structure file location. 96 */ 97 private File m_input; 98 99 /*** 100 * Tree holding the class and package overview. 101 */ 102 private JTree m_tree; 103 104 /*** 105 * Root node of the overview tree. 106 */ 107 private final DefaultMutableTreeNode m_treeRoot 108 = new DefaultMutableTreeNode("Project structure"); 109 110 /*** 111 * Signals the first directory parsed by the analyze method. 112 */ 113 private boolean m_firstDir = true; 114 115 /*** 116 * Textfield for the search expression. 117 */ 118 private JTextField m_searchField = new JTextField(); 119 120 /*** 121 * List containing all the nodes of the tree in the pre order. 122 */ 123 private ArrayList m_preOrderList; 124 125 /*** 126 * This flag is set false for each full iteration through the pre order 127 * list. If the flag is false again when the list is empty --> no match for 128 * this search string. 129 */ 130 private boolean m_foundOne; 131 132 /*** 133 * ScrollPane with the tree. 134 */ 135 private JScrollPane m_treeScrollPane; 136 137 /*** 138 * Constructor - Makes a <code>JInternalFrame</code> with the specified 139 * parameters. 140 * 141 * @param inputStructure Location of the input location of the class 142 * structure. 143 */ 144 public OverView(DependencyModel dependencyModel) { 145 super(dependencyModel, FRAME_TITLE); 146 setDefaultBounds(new Rectangle(943, 441, 266, 415)); 147 recallConfig(); 148 } 149 150 protected void internalInitData() { 151 152 // get data from the dependency context 153 // 154 DependencyContext dependencyCtx = m_dependencyModel.getDependencyContext(); 155 m_input = (File)dependencyCtx.get(DependencyContext.ROOT_FILE_KEY); 156 157 // if m_input is a file, we want to show the unpacked structure instead 158 // 159 if (m_input.isFile()) { 160 m_input = IOManager.getTempDir(); 161 } 162 } 163 164 165 protected void initView() { 166 167 // configure TableLayout 168 // 169 double border = 10; 170 double fill = TableLayout.FILL; 171 double pref = TableLayout.PREFERRED; 172 double size[][] = 173 {{border, fill, border}, // Columns 174 {border, pref, fill, border}}; // Rows 175 176 this.getContentPane().setLayout(new TableLayout(size)); 177 178 // create panel with search mechanism 179 // 180 JPanel searchPanel = new JPanel(); 181 Border etched = BorderFactory.createEtchedBorder(); 182 CompoundBorder compBorder 183 = BorderFactory.createCompoundBorder(etched, 184 BorderFactory.createEmptyBorder(0, 10, 10, 10)); 185 TitledBorder titBorder 186 = BorderFactory.createTitledBorder(compBorder, 187 " Search "); 188 titBorder.setTitleJustification(TitledBorder.LEFT); 189 titBorder.setTitlePosition(TitledBorder.DEFAULT_POSITION); 190 191 // set the border and layout of the panel 192 // 193 searchPanel.setBorder(titBorder); 194 searchPanel.setLayout(new BorderLayout()); 195 196 // textfield for the search 197 // 198 m_searchField = new JTextField(); 199 m_searchField.setPreferredSize(new Dimension(150,25)); 200 201 m_searchField.addActionListener(this); 202 203 searchPanel.add(m_searchField, BorderLayout.WEST); 204 205 // button to start the search 206 // 207 JButton searchButton = new JButton("Search"); 208 searchButton.setMnemonic(KeyEvent.VK_ENTER); 209 searchButton.setPreferredSize(new Dimension(100,25)); 210 211 searchButton.addActionListener(this); 212 213 searchButton.setDefaultCapable(true); 214 this.getRootPane().setDefaultButton(searchButton); 215 searchPanel.add(searchButton, BorderLayout.EAST); 216 217 // add the search panel to the content pane 218 // 219 this.getContentPane().add(searchPanel, "1, 1, F, F"); 220 221 // construct the overview tree 222 // 223 try { 224 constructOverviewTree(m_treeRoot); 225 } catch (Exception e) { 226 JOptionPane.showMessageDialog(this, 227 "The class structure cannot be read!\n" + e.getMessage(), 228 "OverView", JOptionPane.ERROR_MESSAGE); 229 } 230 231 m_tree = new JTree(m_treeRoot); 232 233 // only one node can be selected at the same time 234 // 235 m_tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); 236 m_tree.addTreeSelectionListener(this); 237 238 m_tree.putClientProperty("JTree.lineStyle", "Angled"); 239 m_tree.setCellRenderer(new MyRenderer()); 240 241 // Create the scroll pane and add the tree to it. 242 // 243 m_treeScrollPane = new JScrollPane(m_tree); 244 245 // add the scroll pane to the frame 246 // 247 getContentPane().add(m_treeScrollPane, "1, 2, F, F"); 248 249 // set the parameters of the internal frame 250 // 251 setBackground(searchPanel.getBackground()); 252 setVisible(true); 253 validate(); 254 } 255 256 /*** 257 * Displays the <code>OverView</code> after the data has changed. 258 * This mehtod is individually implemented in each view. 259 * 260 * @tbd improve display method 261 */ 262 public void display() { 263 264 // display: reread classes according to the current perspective, which perhaps has changed since last display... 265 266 validate(); 267 setVisible(true); 268 } 269 270 /*** 271 * Selects all the packages in the specified list for all the views 272 * implementing the <code>Observer</code> interface. 273 * 274 * @param selectList List containing all the selected packages. 275 */ 276 public void select(ArrayList selectList){ 277 278 // iterator over all the selected packages 279 ListIterator iter = selectList.listIterator(); 280 // list with all the packages converted to the tree path 281 ArrayList paths = new ArrayList(); 282 // determines whether a package is in the project 283 // if not nothing is selected 284 boolean foundOne = false; 285 286 while ( iter.hasNext() ) { 287 // full qualified package statement 288 String tmp = (String)iter.next(); 289 StringTokenizer tokenizer = new StringTokenizer(tmp, ".", false); 290 291 // list for the toxkens -> package part 292 ArrayList list = new ArrayList(); 293 while ( tokenizer.hasMoreTokens() ) { 294 String tokTmp = tokenizer.nextToken(); 295 list.add(tokTmp); 296 } 297 // number of package parts 298 int size = list.size() + 1; // + root node 299 TreeNode[] nodes = new TreeNode[size]; 300 // root node always at the beginning of the path 301 nodes[0] = m_treeRoot; 302 303 // iterator over the list with the tokens 304 ListIterator tokenIter = list.listIterator(); 305 306 // find the child node of the appropriate package token 307 int i = 1; 308 DefaultMutableTreeNode currentParent = m_treeRoot; 309 while ( tokenIter.hasNext() ) { 310 String packToken = (String)tokenIter.next(); 311 312 Enumeration childEnum = currentParent.children(); 313 while ( childEnum.hasMoreElements() ) { 314 DefaultMutableTreeNode tnTmp 315 = (DefaultMutableTreeNode)childEnum.nextElement(); 316 String info = (String)tnTmp.getUserObject(); 317 318 if (info.equals(packToken)) { 319 nodes[i] = tnTmp; 320 foundOne = true; 321 currentParent = tnTmp; 322 continue; 323 } 324 } 325 i++; 326 } 327 TreePath newPath = new TreePath(nodes); 328 paths.add(newPath); 329 } 330 331 // no match 332 if ( ! foundOne ) { 333 clearSelection(); 334 return; 335 } 336 337 // fill the tree paths in the array 338 ListIterator pathIter = paths.listIterator(); 339 TreePath[] treePaths = new TreePath[paths.size()]; 340 int i = 0; 341 while ( pathIter.hasNext() ) { 342 treePaths[i] = (TreePath)pathIter.next(); 343 i++; 344 } 345 346 // add the new selection to the tree 347 // 348 try { 349 m_tree.getSelectionModel().addSelectionPaths(treePaths); 350 if (treePaths.length >= 1) { 351 m_tree.scrollPathToVisible(treePaths[0]); 352 } 353 } catch ( Exception e ) { 354 // 355 // ignore if not existing 356 // 357 } 358 } 359 360 /*** 361 * Clears all the selections in all the views. 362 */ 363 public void clearSelection(){ 364 try { 365 m_tree.clearSelection(); 366 } catch (Exception e){ 367 // 368 // deliberately left empty 369 // 370 } 371 } 372 373 /*** 374 * Helper method for creating the overview tree. 375 */ 376 private void constructOverviewTree(DefaultMutableTreeNode top) 377 throws IOException, FileNotFoundException{ 378 379 // start constructing the overview tree in the root of the class structure 380 // 381 analyze(m_input, top); 382 } 383 384 /*** 385 * Helper method for reading the project structure in to the tree. 386 */ 387 private void analyze(File file, DefaultMutableTreeNode parent) 388 throws FileNotFoundException, IOException { 389 390 String fileName = file.getName(); 391 392 // it is a directory 393 // 394 if ( file.isDirectory() ) { 395 DefaultMutableTreeNode nodeTmp; 396 397 // don't add the first directory 398 // 399 if ( m_firstDir ) { 400 m_firstDir = false; 401 nodeTmp = parent; 402 } else { 403 nodeTmp = new DefaultMutableTreeNode(fileName); 404 parent.add(nodeTmp); 405 } 406 407 File[] fileArr = file.listFiles(); 408 int elems = fileArr.length, i=0; 409 410 // do not show empty directories 411 // 412 if ( elems == 0 && nodeTmp.isNodeChild(parent) ) { 413 LOG.debug("remove " + nodeTmp); 414 parent.remove(nodeTmp); 415 } 416 417 // recursive calls for each abstract file in the current directory 418 // 419 boolean hasClassFile = false; 420 boolean hasDir = false; 421 while ( (elems > 0 && i<elems) ) { 422 File tmp = fileArr[i]; 423 if ( isClassFile(tmp) ) { 424 hasClassFile = true; 425 } 426 if ( tmp.isDirectory() ) { 427 hasDir = true; 428 } 429 analyze(tmp, nodeTmp); 430 i++; 431 } 432 if ( ! hasClassFile && ! hasDir ) { 433 parent.remove(nodeTmp); 434 } 435 } 436 437 // it is a file 438 // 439 else { 440 441 // test if the file is a class file and not an inner class 442 // 443 if ( isClassFile(file) && (fileName.lastIndexOf('$') == -1) ) { 444 445 // remove the file extension .class 446 // 447 fileName = fileName.substring(0, fileName.lastIndexOf(".")); 448 449 DefaultMutableTreeNode classNodeTmp = new DefaultMutableTreeNode(fileName); 450 parent.add(classNodeTmp); 451 452 } else if ( isJarFile(file) ) { 453 analyze(IOManager.getTempDir(), parent); 454 } 455 } 456 } 457 458 459 /*** 460 * Helper method for testing whether the specified abstract file is a class 461 * file. 462 * 463 * @param file Abstract file object pointing to the location where the 464 * physical location of the file to inqure is. 465 * @return True if it is a java .class file.<br> 466 * If the file has no file extension, false is returned. 467 * 468 * @tbd provide a generic isFiletype(File f, String suffix) method that recognizes 469 * filetypes 470 */ 471 private boolean isClassFile(File file){ 472 return file.getName().endsWith(".class"); 473 } 474 475 /*** 476 * Helper method for testing whether a given file is a jar file. 477 * 478 * @tbd provide a generic isFiletype(File f, String suffix) method that recognizes 479 * filetypes 480 */ 481 private boolean isJarFile(File file) { 482 return file.getName().endsWith(".jar"); 483 } 484 485 /*** 486 * Listener for the tree. 487 * 488 * @param e TreeSelectionEvent thrown by the 489 * <code>TreeSelectionListener</code>. 490 */ 491 public void valueChanged(TreeSelectionEvent e) { 492 DefaultMutableTreeNode nodeTmp = (DefaultMutableTreeNode)m_tree.getLastSelectedPathComponent(); 493 494 // nothing is selected 495 if ( nodeTmp == null ) { 496 return; 497 } 498 499 // make full qualified package string 500 Object[] path = e.getPath().getPath(); 501 int count = e.getPath().getPathCount(); 502 503 // selected node is a class 504 if ( nodeTmp.isLeaf() ) { 505 count--; // don't add class name 506 } 507 508 // only the root with the title 509 if ( count <= 1 ) { 510 return; 511 } 512 StringBuffer fullQualified = null; 513 for ( int i=1 ; i<count ; i++) { 514 String tmp = (String)((DefaultMutableTreeNode)path[i]) 515 .getUserObject(); 516 if ( i == 1 ) { 517 fullQualified = new StringBuffer(tmp); 518 } 519 else { 520 fullQualified.append("."); 521 fullQualified.append(tmp); 522 } 523 } 524 String name = fullQualified.toString(); 525 526 // make the selection consistent 527 ArrayList selectList = new ArrayList(); 528 selectList.add(name); 529 m_dependencyModel.selectPackages(selectList); 530 } 531 532 /*** 533 * Actions from the search button. 534 */ 535 public void actionPerformed(ActionEvent e) { 536 search(m_searchField.getText().trim()); 537 } 538 539 /*** 540 * Helper method for the search action.<br> 541 * The first match is marked and the search is stopped. 542 * 543 * @param searchStr String to search for. 544 */ 545 private void search(String searchStr) { 546 547 // can't search empty string 548 // 549 if ( searchStr.equals("") ) { 550 return; 551 } 552 553 DefaultMutableTreeNode startNode = null; 554 DefaultMutableTreeNode currentNode = null; 555 TreePath currentPath = null; 556 557 // take a selected node for analysis 558 // if none is selected, take the root 559 // 560 if ((currentPath = m_tree.getSelectionPath()) == null) { 561 startNode = m_treeRoot; 562 } else { 563 startNode = (DefaultMutableTreeNode)currentPath.getLastPathComponent(); 564 } 565 566 // determine next node 567 // 568 569 // search the node 570 // 571 for (currentNode = startNode.getNextNode(); 572 currentNode != startNode; 573 currentNode = currentNode.getNextNode()) { 574 575 if (currentNode == null) { 576 if (startNode == m_treeRoot) { 577 break; 578 } 579 currentNode = m_treeRoot; 580 } 581 582 // node containig the search string found 583 // 584 if (isNodeFound(currentNode, searchStr)) { 585 selectNodeInTree(currentNode); 586 return; 587 } 588 } 589 590 // now check whether this wasn't the only node containig the string 591 // 592 if (isNodeFound(startNode, searchStr)) { 593 selectNodeInTree(startNode); 594 return; 595 } 596 597 // the whole tree is traversed and nothing is found 598 // 599 JOptionPane.showMessageDialog(this, 600 "There was no match for the search string '" + searchStr + "'!", 601 "No match", JOptionPane.WARNING_MESSAGE); 602 } 603 604 private boolean isNodeFound(DefaultMutableTreeNode currentNode, String searchString) { 605 return ((String)currentNode.getUserObject()).toLowerCase(). 606 indexOf(searchString.toLowerCase()) != -1; 607 } 608 609 private void selectNodeInTree(DefaultMutableTreeNode currentNode) { 610 TreePath currentPath = new TreePath(currentNode.getPath()); 611 612 // this is necessary to have the node selected, not only a package 613 // 614 m_tree.setSelectionPath(currentPath); 615 m_tree.scrollPathToVisible(currentPath); 616 m_tree.setSelectionPath(currentPath); 617 m_tree.scrollPathToVisible(currentPath); 618 return; 619 } 620 621 /*** 622 * Class for rendering the tree Particularly for setting the icons. 623 */ 624 private class MyRenderer extends DefaultTreeCellRenderer { 625 626 private ImageIcon m_packageIcon = IconGrabber.getIcon("package.gif"); 627 private ImageIcon m_classIcon = IconGrabber.getIcon("class.gif"); 628 629 /*** 630 * Configures the renderer based on the passed in components. 631 * The value is set from messaging the tree with 632 * <code>convertValueToText</code>, which ultimately invokes 633 * <code>toString</code> on <code>value</code>. 634 * The foreground color is set based on the selection and the icon 635 * is set based on on leaf and expanded. 636 */ 637 public Component getTreeCellRendererComponent(JTree tree, 638 Object value, 639 boolean sel, 640 boolean expanded, 641 boolean leaf, 642 int row, 643 boolean hasFocus) { 644 645 super.getTreeCellRendererComponent(tree, value, sel, 646 expanded, leaf, row, 647 hasFocus); 648 // class icon for classes 649 // 650 if ( leaf ) { 651 setIcon(m_classIcon); 652 } 653 // package icon for packages 654 // 655 else { 656 setIcon(m_packageIcon); 657 } 658 659 return this; 660 } 661 } 662 }

This page was automatically generated by Maven