001: package tijmp.ui;
002:
003: import java.awt.GridBagConstraints;
004: import java.awt.GridBagLayout;
005: import java.awt.Insets;
006: import java.util.Arrays;
007: import java.util.Comparator;
008: import javax.swing.JPanel;
009: import javax.swing.JScrollPane;
010: import javax.swing.JTree;
011: import javax.swing.tree.DefaultMutableTreeNode;
012: import javax.swing.tree.DefaultTreeModel;
013: import javax.swing.tree.TreeModel;
014:
015: /** A panel that shows strings in a tree.
016: */
017: public class StringTree extends JPanel {
018: public StringTree(Object[] objects) {
019: Arrays.sort(objects, new CharArrayComparator());
020: JTree jt = new JTree(getModel(objects));
021: JScrollPane sp = new JScrollPane(jt);
022:
023: GridBagLayout gb = new GridBagLayout();
024: GridBagConstraints c = new GridBagConstraints();
025: setLayout(gb);
026: c.insets = new Insets(2, 2, 2, 2);
027:
028: c.gridx = 0;
029: c.gridy = 0;
030: c.weightx = 1;
031: c.weighty = 1;
032: c.fill = GridBagConstraints.BOTH;
033: add(sp, c);
034: }
035:
036: private static final class CharArrayComparator implements
037: Comparator<Object> {
038: public int compare(Object o1, Object o2) {
039: char[] c1 = (char[]) o1;
040: char[] c2 = (char[]) o2;
041: String s1 = new String(c1);
042: String s2 = new String(c2);
043: return s1.compareTo(s2);
044: }
045: }
046:
047: private TreeModel getModel(Object[] objects) {
048: DefaultMutableTreeNode root = new DefaultMutableTreeNode(
049: new SimpleNode(""));
050: DefaultMutableTreeNode last = root;
051: for (Object o : objects) {
052: char[] ca = (char[]) o;
053: String s = new String(ca);
054: StringNode sn = (StringNode) last.getUserObject();
055: if (sn.getString().equals(s)) {
056: last.setUserObject(sn.incrementCount());
057: } else {
058: if (s.length() == 1) {
059: last = new DefaultMutableTreeNode(new SimpleNode(s));
060: root.add(last);
061: } else if (s.length() == 2) {
062: last = handle2(s, sn, last, root);
063: } else {
064: last = handleLong(s, sn, last, root);
065: }
066: }
067: updateChildCounts(last, 0);
068: }
069: return new DefaultTreeModel(root);
070: }
071:
072: private void updateChildCounts(DefaultMutableTreeNode n, int count) {
073: while (n != null) {
074: StringNode sn = (StringNode) n.getUserObject();
075: sn.incrementChildrenCount(count);
076: count = 1;
077: n = (DefaultMutableTreeNode) n.getParent();
078: }
079: }
080:
081: private DefaultMutableTreeNode handleLong(String s, StringNode sn,
082: DefaultMutableTreeNode last, DefaultMutableTreeNode root) {
083: String p1 = s.substring(0, 1);
084: String p2 = s.substring(0, 2);
085: if (sn.getString().length() > 2) {
086: last = (DefaultMutableTreeNode) last.getParent();
087: sn = (StringNode) last.getUserObject();
088: }
089: DefaultMutableTreeNode dm2 = last;
090: DefaultMutableTreeNode dm1 = last;
091: StringNode sn1 = (StringNode) dm1.getUserObject();
092: if (sn1.getString().length() > 1) {
093: dm1 = (DefaultMutableTreeNode) last.getParent();
094: }
095: if (sn.getString().startsWith(p2)) {
096: // nothing
097: } else if (sn.getString().startsWith(p1)) {
098: dm2 = new DefaultMutableTreeNode(new FakeNode(p2));
099: dm1.add(dm2);
100: } else {
101: dm1 = new DefaultMutableTreeNode(new FakeNode(p1));
102: root.add(dm1);
103: dm2 = new DefaultMutableTreeNode(new FakeNode(p2));
104: dm1.add(dm2);
105: }
106:
107: DefaultMutableTreeNode dms = new DefaultMutableTreeNode(
108: new SimpleNode(s));
109: dm2.add(dms);
110: last = dms;
111: return last;
112: }
113:
114: private DefaultMutableTreeNode handle2(String s, StringNode sn,
115: DefaultMutableTreeNode last, DefaultMutableTreeNode root) {
116: String p = s.substring(0, 1);
117: DefaultMutableTreeNode dm = last;
118: if (sn.getString().equals(p)) {
119: dm = last;
120: } else {
121: dm = (DefaultMutableTreeNode) last.getParent();
122: String sp = sn.getString();
123: if (sp.length() > 2)
124: dm = (DefaultMutableTreeNode) dm.getParent();
125: if (!sp.startsWith(p)) {
126: dm = new DefaultMutableTreeNode(new FakeNode(p));
127: root.add(dm);
128: }
129: }
130: DefaultMutableTreeNode dms = new DefaultMutableTreeNode(
131: new SimpleNode(s));
132: dm.add(dms);
133: last = dms;
134: return last;
135: }
136:
137: private static interface StringNode {
138: String getString();
139:
140: StringNode incrementCount();
141:
142: void incrementChildrenCount(int n);
143: }
144:
145: private abstract static class BaseNode implements StringNode {
146: private String s;
147: private int childCount;
148:
149: public BaseNode(String s) {
150: this .s = s;
151: }
152:
153: public String getString() {
154: return s;
155: }
156:
157: public void incrementChildrenCount(int n) {
158: childCount += n;
159: }
160:
161: public String getChildCountString() {
162: if (childCount == 0)
163: return "";
164: return ", " + childCount;
165: }
166: }
167:
168: private static class FakeNode extends BaseNode {
169: public FakeNode(String s) {
170: super (s);
171: }
172:
173: public String toString() {
174: return getString() + ": 0" + getChildCountString();
175: }
176:
177: public StringNode incrementCount() {
178: String err = "can not incrementCount on a fake node";
179: throw new IllegalStateException(err);
180: }
181: }
182:
183: private static class SimpleNode extends BaseNode {
184: public SimpleNode(String s) {
185: super (s);
186: }
187:
188: public String toString() {
189: return getString() + ": 1" + getChildCountString();
190: }
191:
192: public StringNode incrementCount() {
193: return new MultiNode(getString(), 2);
194: }
195: }
196:
197: private static class MultiNode extends BaseNode {
198: private int count;
199:
200: public MultiNode(String s, int count) {
201: super (s);
202: this .count = count;
203: }
204:
205: public StringNode incrementCount() {
206: count++;
207: return this ;
208: }
209:
210: public String toString() {
211: return getString() + ": " + count + getChildCountString();
212: }
213: }
214: }
|