001: package jdepend.swingui;
002:
003: import java.text.NumberFormat;
004: import java.util.*;
005:
006: import jdepend.framework.*;
007:
008: /**
009: * The <code>PackageNode</code> class defines the default behavior for tree
010: * nodes representing Java packages.
011: *
012: * @author <b>Mike Clark</b>
013: * @author Clarkware Consulting, Inc.
014: */
015:
016: public abstract class PackageNode {
017:
018: private PackageNode parent;
019:
020: private JavaPackage jPackage;
021:
022: private ArrayList children;
023:
024: private static NumberFormat formatter;
025: static {
026: formatter = NumberFormat.getInstance();
027: formatter.setMaximumFractionDigits(2);
028: }
029:
030: /**
031: * Constructs a <code>PackageNode</code> with the specified package and
032: * its collection of dependent packages.
033: *
034: * @param parent Parent package node.
035: * @param jPackage Java package.
036: */
037: public PackageNode(PackageNode parent, JavaPackage jPackage) {
038: this .parent = parent;
039: this .jPackage = jPackage;
040: children = null;
041: }
042:
043: /**
044: * Returns the Java package represented in this node.
045: *
046: * @return Java package.
047: */
048: public JavaPackage getPackage() {
049: return jPackage;
050: }
051:
052: /**
053: * Returns the parent of this package node.
054: *
055: * @return Parent package node.
056: */
057: public PackageNode getParent() {
058: return parent;
059: }
060:
061: /**
062: * Indicates whether this node is a leaf node.
063: *
064: * @return <code>true</code> if this node is a leaf; <code>false</code>
065: * otherwise.
066: */
067: public boolean isLeaf() {
068: if (getCoupledPackages().size() > 0) {
069: return false;
070: }
071:
072: return true;
073: }
074:
075: /**
076: * Creates and returns a <code>PackageNode</code> with the specified
077: * parent node and Java package.
078: *
079: * @param parent Parent package node.
080: * @param jPackage Java package.
081: * @return A non-null <code>PackageNode</code.
082: */
083: protected abstract PackageNode makeNode(PackageNode parent,
084: JavaPackage jPackage);
085:
086: /**
087: * Returns the collection of Java packages coupled to the package
088: * represented in this node.
089: *
090: * @return Collection of coupled packages.
091: */
092: protected abstract Collection getCoupledPackages();
093:
094: /**
095: * Indicates whether the specified package should be displayed as a child of
096: * this node.
097: *
098: * @param jPackage Package to test.
099: * @return <code>true</code> to display the package; <code>false</code>
100: * otherwise.
101: */
102: public boolean isChild(JavaPackage jPackage) {
103: return true;
104: }
105:
106: /**
107: * Returns the child package nodes of this node.
108: *
109: * @return Collection of child package nodes.
110: */
111: public ArrayList getChildren() {
112:
113: if (children == null) {
114:
115: children = new ArrayList();
116: ArrayList packages = new ArrayList(getCoupledPackages());
117: Collections.sort(packages, new PackageComparator(
118: PackageComparator.byName()));
119: Iterator i = packages.iterator();
120: while (i.hasNext()) {
121: JavaPackage jPackage = (JavaPackage) i.next();
122: if (isChild(jPackage)) {
123: PackageNode childNode = makeNode(this , jPackage);
124: children.add(childNode);
125: }
126: }
127: }
128:
129: return children;
130: }
131:
132: /**
133: * Returns the string representation of this node's metrics.
134: *
135: * @return Metrics string.
136: */
137: public String toMetricsString() {
138: StringBuffer label = new StringBuffer();
139: label.append(getPackage().getName());
140: label.append(" (");
141: label.append("CC: " + getPackage().getConcreteClassCount()
142: + " ");
143: label.append("AC: " + getPackage().getAbstractClassCount()
144: + " ");
145: label.append("Ca: " + getPackage().afferentCoupling() + " ");
146: label.append("Ce: " + getPackage().efferentCoupling() + " ");
147: label
148: .append("A: " + format(getPackage().abstractness())
149: + " ");
150: label.append("I: " + format(getPackage().instability()) + " ");
151: label.append("D: " + format(getPackage().distance()) + " ");
152: label.append("V: " + getPackage().getVolatility());
153: if (getPackage().containsCycle()) {
154: label.append(" Cyclic");
155: }
156:
157: label.append(")");
158:
159: return label.toString();
160: }
161:
162: /**
163: * Returns the string representation of this node in it's current tree
164: * context.
165: *
166: * @return Node label.
167: */
168: public String toString() {
169:
170: if (getParent().getParent() == null) {
171: return toMetricsString();
172: }
173:
174: return getPackage().getName();
175: }
176:
177: /*
178: * Returns the specified number in a displayable format. @param number
179: * Number to format. @return Formatted number.
180: */
181: private static String format(float f) {
182: return formatter.format(f);
183: }
184: }
|