001: package abbot.editor;
002:
003: import java.awt.*;
004: import java.util.*;
005:
006: import javax.swing.tree.*;
007:
008: import abbot.finder.*;
009: import abbot.i18n.Strings;
010: import abbot.tester.Robot;
011:
012: /** Provides a JTree-compatible node model for displaying a given hierarchy. */
013: public class ComponentNode extends DefaultMutableTreeNode {
014:
015: private Hierarchy hierarchy;
016: private Map map;
017: private boolean loaded;
018:
019: /** Constructor for the root node of a hierarchy. */
020: public ComponentNode(Hierarchy hierarchy) {
021: super (null, true);
022: this .hierarchy = hierarchy;
023: map = new WeakHashMap();
024: }
025:
026: protected ComponentNode(ComponentNode parent, Object obj) {
027: super (
028: obj,
029: (obj == null || obj instanceof Container || obj instanceof MenuContainer));
030: hierarchy = parent.hierarchy;
031: map = parent.map;
032: map.put(obj, this );
033: }
034:
035: public ComponentNode(ComponentNode parent, Component comp) {
036: this (parent, (Object) comp);
037: }
038:
039: public ComponentNode(ComponentNode parent, MenuComponent comp) {
040: this (parent, (Object) comp);
041: }
042:
043: public ComponentNode(ComponentNode parent, MenuItem comp) {
044: this (parent, (Object) comp);
045: }
046:
047: public TreeNode getChildAt(int index) {
048: load();
049: return super .getChildAt(index);
050: }
051:
052: public int getChildCount() {
053: load();
054: return super .getChildCount();
055: }
056:
057: public void reload() {
058: reload(hierarchy);
059: }
060:
061: public void reload(Hierarchy hierarchy) {
062: this .hierarchy = hierarchy;
063: map.clear();
064: loaded = false;
065: }
066:
067: private void load() {
068: if (loaded)
069: return;
070:
071: loaded = true;
072: removeAllChildren();
073: Object obj = getUserObject();
074: if (isRoot()) {
075: Iterator iter = hierarchy.getRoots().iterator();
076: while (iter.hasNext()) {
077: add(new ComponentNode(this , (Component) iter.next()));
078: }
079: } else if (obj instanceof Container) {
080: // Specially handle AWT MenuBar
081: if (obj instanceof Frame) {
082: Frame f = (Frame) obj;
083: if (f.getMenuBar() != null) {
084: add(new ComponentNode(this , f.getMenuBar()));
085: }
086: }
087: Collection children = hierarchy
088: .getComponents(getComponent());
089: Iterator iter = children.iterator();
090: while (iter.hasNext()) {
091: add(new ComponentNode(this , (Component) iter.next()));
092: }
093: }
094: // Specially handle AWT menus
095: else if (obj instanceof MenuBar) {
096: MenuBar mb = (MenuBar) obj;
097: for (int i = 0; i < mb.getMenuCount(); i++) {
098: add(new ComponentNode(this , mb.getMenu(i)));
099: }
100: } else if (obj instanceof Menu) {
101: Menu menu = (Menu) obj;
102: for (int i = 0; i < menu.getItemCount(); i++) {
103: add(new ComponentNode(this , menu.getItem(i)));
104: }
105: }
106: }
107:
108: /** Return the component that appears as a parent in the ComponentNode
109: * hierarchy.
110: */
111: Component getParent(Component c) {
112: return hierarchy.getParent(c);
113: }
114:
115: /** Returns the Component represented, or null if this is either the root
116: * or a java.awt.MenuComponent.
117: */
118: public Component getComponent() {
119: if (getUserObject() instanceof Component)
120: return (Component) getUserObject();
121: return null;
122: }
123:
124: public int hashCode() {
125: return (isRoot() ? super .hashCode() : getUserObject()
126: .hashCode());
127: }
128:
129: /** Return true if the represented components are the same. */
130: public boolean equals(Object other) {
131: return this == other
132: || ((other instanceof ComponentNode) && (getUserObject() == ((ComponentNode) other)
133: .getUserObject()));
134: }
135:
136: public String toString() {
137: if (isRoot()) {
138: return getChildCount() == 0 ? Strings.get("NoComponents")
139: : Strings.get("AllFrames");
140: }
141: return Robot.toString(getUserObject());
142: }
143:
144: /** Return the nearest node corresponding to the given component.
145: Behavior is undefined if the node is not reachable from the root
146: node. If the component is elided in the underlying hierarchy, returns
147: the nearest parent node that is not elided.
148: */
149: public ComponentNode getNode(Component comp) {
150: if (comp == null) {
151: return (ComponentNode) getRoot();
152: }
153: ComponentNode node = (ComponentNode) map.get(comp);
154: if (node == null) {
155: Component parentComp = getParent(comp);
156: ComponentNode parent = getNode(parentComp);
157: if (parent == null) {
158: return getNode(parentComp);
159: }
160: // Fall back to parent if no child matches.
161: node = parent;
162: for (int i = 0; i < parent.getChildCount(); i++) {
163: ComponentNode child = (ComponentNode) parent
164: .getChildAt(i);
165: if (child.getComponent() == comp) {
166: node = child;
167: break;
168: }
169: }
170: }
171: return node;
172: }
173:
174: /** Return the TreePath for the given Component, assuming it is in the
175: same hierarchy as this node. Returns as much of the ancestor path as
176: is available in the hierarchy.
177: */
178: public TreePath getPath(Component comp) {
179: ComponentNode node = getNode(comp);
180: return new TreePath(node.getPath());
181: }
182: }
|