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