1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63: import ;
64: import ;
65: import ;
66: import ;
67: import ;
68:
69: import ;
70: import ;
71: import ;
72: import ;
73: import ;
74: import ;
75: import ;
76: import ;
77: import ;
78: import ;
79: import ;
80: import ;
81: import ;
82: import ;
83: import ;
84: import ;
85: import ;
86: import ;
87: import ;
88: import ;
89: import ;
90: import ;
91: import ;
92: import ;
93: import ;
94: import ;
95: import ;
96: import ;
97: import ;
98: import ;
99: import ;
100: import ;
101: import ;
102: import ;
103: import ;
104: import ;
105: import ;
106: import ;
107: import ;
108: import ;
109:
110:
119: public class BasicTreeUI extends TreeUI
120: {
121:
122: protected transient Icon collapsedIcon;
123:
124:
125: protected transient Icon expandedIcon;
126:
127:
128: protected int leftChildIndent;
129:
130:
133: protected int rightChildIndent;
134:
135:
139: protected int totalChildIndent;
140:
141:
142: protected int lastSelectedRow;
143:
144:
145: protected JTree tree;
146:
147:
148: protected transient TreeCellRenderer currentCellRenderer;
149:
150:
154: protected boolean createdRenderer;
155:
156:
157: protected transient TreeCellEditor cellEditor;
158:
159:
163: protected boolean createdCellEditor;
164:
165:
169: protected boolean stopEditingInCompleteEditing;
170:
171:
172: protected CellRendererPane rendererPane;
173:
174:
175: protected Dimension preferredSize;
176:
177:
178: protected Dimension preferredMinSize;
179:
180:
181: protected boolean validCachedPreferredSize;
182:
183:
184: protected AbstractLayoutCache treeState;
185:
186:
187: protected Hashtable drawingCache;
188:
189:
194: protected boolean largeModel;
195:
196:
197: protected AbstractLayoutCache.NodeDimensions nodeDimensions;
198:
199:
200: protected TreeModel treeModel;
201:
202:
203: protected TreeSelectionModel treeSelectionModel;
204:
205:
210: protected int depthOffset;
211:
212:
215: protected Component editingComponent;
216:
217:
218: protected TreePath editingPath;
219:
220:
224: protected int editingRow;
225:
226:
227: protected boolean editorHasDifferentSize;
228:
229:
230: Timer editorTimer = new EditorUpdateTimer();
231:
232:
233: Object newVal;
234:
235:
236: TreeAction action;
237:
238:
239: boolean isEditing;
240:
241:
242: TreePath currentVisiblePath;
243:
244:
245: int gap = 4;
246:
247:
248: int rowHeight = 20;
249:
250:
251: private PropertyChangeListener propertyChangeListener;
252: private FocusListener focusListener;
253: private TreeSelectionListener treeSelectionListener;
254: private MouseListener mouseListener;
255: private KeyListener keyListener;
256: private PropertyChangeListener selectionModelPropertyChangeListener;
257: private ComponentListener componentListener;
258: CellEditorListener cellEditorListener;
259: private TreeExpansionListener treeExpansionListener;
260: private TreeModelListener treeModelListener;
261:
262:
265: public BasicTreeUI()
266: {
267: validCachedPreferredSize = false;
268: drawingCache = new Hashtable();
269: nodeDimensions = createNodeDimensions();
270: configureLayoutCache();
271:
272: propertyChangeListener = createPropertyChangeListener();
273: focusListener = createFocusListener();
274: treeSelectionListener = createTreeSelectionListener();
275: mouseListener = createMouseListener();
276: keyListener = createKeyListener();
277: selectionModelPropertyChangeListener = createSelectionModelPropertyChangeListener();
278: componentListener = createComponentListener();
279: cellEditorListener = createCellEditorListener();
280: treeExpansionListener = createTreeExpansionListener();
281: treeModelListener = createTreeModelListener();
282:
283: editingRow = -1;
284: lastSelectedRow = -1;
285: }
286:
287:
294: public static ComponentUI createUI(JComponent c)
295: {
296: return new BasicTreeUI();
297: }
298:
299:
304: protected Color getHashColor()
305: {
306: return UIManager.getColor("Tree.hash");
307: }
308:
309:
315: protected void setHashColor(Color color)
316: {
317:
318: UIManager.put("Tree.hash", color);
319: }
320:
321:
327: public void setLeftChildIndent(int newAmount)
328: {
329: leftChildIndent = newAmount;
330: }
331:
332:
337: public int getLeftChildIndent()
338: {
339: return leftChildIndent;
340: }
341:
342:
348: public void setRightChildIndent(int newAmount)
349: {
350: rightChildIndent = newAmount;
351: }
352:
353:
358: public int getRightChildIndent()
359: {
360: return rightChildIndent;
361: }
362:
363:
369: public void setExpandedIcon(Icon newG)
370: {
371: expandedIcon = newG;
372: }
373:
374:
379: public Icon getExpandedIcon()
380: {
381: return expandedIcon;
382: }
383:
384:
390: public void setCollapsedIcon(Icon newG)
391: {
392: collapsedIcon = newG;
393: }
394:
395:
400: public Icon getCollapsedIcon()
401: {
402: return collapsedIcon;
403: }
404:
405:
411: protected void setLargeModel(boolean largeModel)
412: {
413: if (largeModel != this.largeModel)
414: {
415: tree.removeComponentListener(componentListener);
416: this.largeModel = largeModel;
417: tree.addComponentListener(componentListener);
418: }
419: }
420:
421:
426: protected boolean isLargeModel()
427: {
428: return largeModel;
429: }
430:
431:
437: protected void setRowHeight(int rowHeight)
438: {
439: if (rowHeight == 0)
440: rowHeight = this.rowHeight;
441: treeState.setRowHeight(rowHeight);
442: }
443:
444:
449: protected int getRowHeight()
450: {
451: return treeState.getRowHeight();
452: }
453:
454:
461: protected void setCellRenderer(TreeCellRenderer tcr)
462: {
463: currentCellRenderer = tcr;
464: updateRenderer();
465: }
466:
467:
473: protected TreeCellRenderer getCellRenderer()
474: {
475: if (currentCellRenderer != null)
476: return currentCellRenderer;
477:
478: return createDefaultCellRenderer();
479: }
480:
481:
487: protected void setModel(TreeModel model)
488: {
489: tree.setModel(model);
490: treeModel = tree.getModel();
491: }
492:
493:
498: protected TreeModel getModel()
499: {
500: return treeModel;
501: }
502:
503:
509: protected void setRootVisible(boolean newValue)
510: {
511: tree.setRootVisible(newValue);
512: }
513:
514:
519: protected boolean isRootVisible()
520: {
521: return tree.isRootVisible();
522: }
523:
524:
530: protected void setShowsRootHandles(boolean newValue)
531: {
532: tree.setShowsRootHandles(newValue);
533: }
534:
535:
540: protected boolean getShowsRootHandles()
541: {
542: return tree.getShowsRootHandles();
543: }
544:
545:
551: protected void setCellEditor(TreeCellEditor editor)
552: {
553: cellEditor = editor;
554: createdCellEditor = true;
555: }
556:
557:
562: protected TreeCellEditor getCellEditor()
563: {
564: return cellEditor;
565: }
566:
567:
573: protected void setEditable(boolean newValue)
574: {
575: tree.setEditable(newValue);
576: }
577:
578:
583: protected boolean isEditable()
584: {
585: return tree.isEditable();
586: }
587:
588:
595: protected void setSelectionModel(TreeSelectionModel newLSM)
596: {
597: if (newLSM != null)
598: {
599: treeSelectionModel = newLSM;
600: tree.setSelectionModel(treeSelectionModel);
601: }
602: }
603:
604:
609: protected TreeSelectionModel getSelectionModel()
610: {
611: return treeSelectionModel;
612: }
613:
614:
626: public Rectangle getPathBounds(JTree tree, TreePath path)
627: {
628: Rectangle bounds = null;
629: int row = -1;
630: Object cell = null;
631: if (path != null)
632: {
633: row = getRowForPath(tree, path);
634: cell = path.getLastPathComponent();
635: bounds = new Rectangle(0, row * getRowHeight(), 0, 0);
636: }
637: return nodeDimensions.getNodeDimensions(cell, row,
638: getLevel(cell),
639: tree.isExpanded(path),
640: bounds);
641: }
642:
643:
652: public TreePath getPathForRow(JTree tree, int row)
653: {
654: if (treeModel != null && currentVisiblePath != null)
655: {
656: Object[] nodes = currentVisiblePath.getPath();
657: if (row < nodes.length)
658: return new TreePath(getPathToRoot(nodes[row], 0));
659: }
660: return null;
661: }
662:
663:
675: public int getRowForPath(JTree tree, TreePath path)
676: {
677: int row = 0;
678: Object dest = path.getLastPathComponent();
679: int rowCount = getRowCount(tree);
680: if (currentVisiblePath != null)
681: {
682: Object[] nodes = currentVisiblePath.getPath();
683: while (row < rowCount)
684: {
685: if (dest.equals(nodes[row]))
686: return row;
687: row++;
688: }
689: }
690: return -1;
691: }
692:
693:
700: public int getRowCount(JTree tree)
701: {
702: if (currentVisiblePath != null)
703: return currentVisiblePath.getPathCount();
704: return 0;
705: }
706:
707:
721: public TreePath getClosestPathForLocation(JTree tree, int x, int y)
722: {
723: int row = Math.round(y / getRowHeight());
724: TreePath path = getPathForRow(tree, row);
725:
726:
727: while (row > 0 && path == null)
728: {
729: --row;
730: path = getPathForRow(tree, row);
731: }
732:
733: return path;
734: }
735:
736:
744: public boolean isEditing(JTree tree)
745: {
746: return isEditing;
747: }
748:
749:
758: public boolean stopEditing(JTree tree)
759: {
760: if (isEditing(tree))
761: completeEditing(true, false, false);
762: return !isEditing(tree);
763: }
764:
765:
771: public void cancelEditing(JTree tree)
772: {
773: if (isEditing(tree))
774: completeEditing(false, true, false);
775: }
776:
777:
786: public void startEditingAtPath(JTree tree, TreePath path)
787: {
788: startEditing(path, null);
789: }
790:
791:
798: public TreePath getEditingPath(JTree tree)
799: {
800: return editingPath;
801: }
802:
803:
807: protected void prepareForUIInstall()
808: {
809:
810: }
811:
812:
816: protected void completeUIInstall()
817: {
818:
819: }
820:
821:
825: protected void completeUIUninstall()
826: {
827:
828: }
829:
830:
833: protected void installComponents()
834: {
835: currentCellRenderer = createDefaultCellRenderer();
836: rendererPane = createCellRendererPane();
837: createdRenderer = true;
838: setCellRenderer(currentCellRenderer);
839: }
840:
841:
847: protected AbstractLayoutCache.NodeDimensions createNodeDimensions()
848: {
849: return new NodeDimensionsHandler();
850: }
851:
852:
858: protected PropertyChangeListener createPropertyChangeListener()
859: {
860: return new PropertyChangeHandler();
861: }
862:
863:
869: protected MouseListener createMouseListener()
870: {
871: return new MouseHandler();
872: }
873:
874:
880: protected FocusListener createFocusListener()
881: {
882: return new FocusHandler();
883: }
884:
885:
890: protected KeyListener createKeyListener()
891: {
892: return new KeyHandler();
893: }
894:
895:
902: protected PropertyChangeListener createSelectionModelPropertyChangeListener()
903: {
904: return new SelectionModelPropertyChangeHandler();
905: }
906:
907:
913: protected TreeSelectionListener createTreeSelectionListener()
914: {
915: return new TreeSelectionHandler();
916: }
917:
918:
923: protected CellEditorListener createCellEditorListener()
924: {
925: return new CellEditorHandler();
926: }
927:
928:
935: protected ComponentListener createComponentListener()
936: {
937: return new ComponentHandler();
938: }
939:
940:
946: protected TreeExpansionListener createTreeExpansionListener()
947: {
948: return new TreeExpansionHandler();
949: }
950:
951:
957: protected AbstractLayoutCache createLayoutCache()
958: {
959: return new FixedHeightLayoutCache();
960: }
961:
962:
967: protected CellRendererPane createCellRendererPane()
968: {
969: return new CellRendererPane();
970: }
971:
972:
977: protected TreeCellEditor createDefaultCellEditor()
978: {
979: if (currentCellRenderer != null)
980: return new DefaultTreeCellEditor(tree,
981: (DefaultTreeCellRenderer) currentCellRenderer,
982: cellEditor);
983: return new DefaultTreeCellEditor(tree,
984: (DefaultTreeCellRenderer) createDefaultCellRenderer(),
985: cellEditor);
986: }
987:
988:
995: protected TreeCellRenderer createDefaultCellRenderer()
996: {
997: return new DefaultTreeCellRenderer();
998: }
999:
1000:
1005: protected TreeModelListener createTreeModelListener()
1006: {
1007: return new TreeModelHandler();
1008: }
1009:
1010:
1013: protected void uninstallListeners()
1014: {
1015: tree.removePropertyChangeListener(propertyChangeListener);
1016: tree.removeFocusListener(focusListener);
1017: tree.removeTreeSelectionListener(treeSelectionListener);
1018: tree.removeMouseListener(mouseListener);
1019: tree.removeKeyListener(keyListener);
1020: tree.removePropertyChangeListener(selectionModelPropertyChangeListener);
1021: tree.removeComponentListener(componentListener);
1022: tree.removeTreeExpansionListener(treeExpansionListener);
1023:
1024: TreeCellEditor tce = tree.getCellEditor();
1025: if (tce != null)
1026: tce.removeCellEditorListener(cellEditorListener);
1027: if (treeModel != null)
1028: treeModel.removeTreeModelListener(treeModelListener);
1029: }
1030:
1031:
1034: protected void uninstallKeyboardActions()
1035: {
1036: action = null;
1037: tree.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).setParent(null);
1038: tree.getActionMap().setParent(null);
1039: }
1040:
1041:
1044: protected void uninstallComponents()
1045: {
1046: currentCellRenderer = null;
1047: rendererPane = null;
1048: createdRenderer = false;
1049: setCellRenderer(currentCellRenderer);
1050: }
1051:
1052:
1058: protected int getVerticalLegBuffer()
1059: {
1060: return getRowHeight() / 2;
1061: }
1062:
1063:
1070: protected int getHorizontalLegBuffer()
1071: {
1072: return rightChildIndent / 2;
1073: }
1074:
1075:
1079: protected void updateLayoutCacheExpandedNodes()
1080: {
1081: if (treeModel != null)
1082: updateExpandedDescendants(new TreePath(treeModel.getRoot()));
1083: }
1084:
1085:
1093: protected void updateExpandedDescendants(TreePath path)
1094: {
1095: Enumeration expanded = tree.getExpandedDescendants(path);
1096: while (expanded.hasMoreElements())
1097: treeState.setExpandedState(((TreePath) expanded.nextElement()), true);
1098: }
1099:
1100:
1107: protected TreePath getLastChildPath(TreePath parent)
1108: {
1109: return ((TreePath) parent.getLastPathComponent());
1110: }
1111:
1112:
1115: protected void updateDepthOffset()
1116: {
1117: depthOffset += getVerticalLegBuffer();
1118: }
1119:
1120:
1125: protected void updateCellEditor()
1126: {
1127: if (tree.isEditable() && cellEditor == null)
1128: setCellEditor(createDefaultCellEditor());
1129: createdCellEditor = true;
1130: }
1131:
1132:
1135: protected void updateRenderer()
1136: {
1137: if (tree != null)
1138: {
1139: if(tree.getCellRenderer() == null)
1140: {
1141: if(currentCellRenderer == null)
1142: currentCellRenderer = createDefaultCellRenderer();
1143: tree.setCellRenderer(currentCellRenderer);
1144: }
1145: }
1146: }
1147:
1148:
1152: protected void configureLayoutCache()
1153: {
1154: treeState = createLayoutCache();
1155: }
1156:
1157:
1161: protected void updateSize()
1162: {
1163: preferredSize = null;
1164: updateCachedPreferredSize();
1165: tree.treeDidChange();
1166: }
1167:
1168:
1172: protected void updateCachedPreferredSize()
1173: {
1174: int maxWidth = 0;
1175: boolean isLeaf = false;
1176: if (currentVisiblePath != null)
1177: {
1178: Object[] path = currentVisiblePath.getPath();
1179: for (int i = 0; i < path.length; i++)
1180: {
1181: TreePath curr = new TreePath(getPathToRoot(path[i], 0));
1182: Rectangle bounds = getPathBounds(tree, curr);
1183: if (treeModel != null)
1184: isLeaf = treeModel.isLeaf(path[i]);
1185: if (!isLeaf && hasControlIcons())
1186: bounds.width += getCurrentControlIcon(curr).getIconWidth();
1187: maxWidth = Math.max(maxWidth, bounds.x + bounds.width);
1188: }
1189: preferredSize = new Dimension(maxWidth, (getRowHeight() * path.length));
1190: }
1191: else preferredSize = new Dimension(0, 0);
1192: validCachedPreferredSize = true;
1193: }
1194:
1195:
1201: protected void pathWasExpanded(TreePath path)
1202: {
1203: validCachedPreferredSize = false;
1204: tree.revalidate();
1205: tree.repaint();
1206: }
1207:
1208:
1211: protected void pathWasCollapsed(TreePath path)
1212: {
1213: validCachedPreferredSize = false;
1214: tree.revalidate();
1215: tree.repaint();
1216: }
1217:
1218:
1221: protected void installDefaults()
1222: {
1223: LookAndFeel.installColorsAndFont(tree, "Tree.background",
1224: "Tree.foreground", "Tree.font");
1225: tree.setOpaque(true);
1226:
1227: rightChildIndent = UIManager.getInt("Tree.rightChildIndent");
1228: leftChildIndent = UIManager.getInt("Tree.leftChildIndent");
1229: setRowHeight(UIManager.getInt("Tree.rowHeight"));
1230: tree.setRowHeight(getRowHeight());
1231: tree.requestFocusInWindow(false);
1232: tree.setScrollsOnExpand(UIManager.getBoolean("Tree.scrollsOnExpand"));
1233: setExpandedIcon(UIManager.getIcon("Tree.expandedIcon"));
1234: setCollapsedIcon(UIManager.getIcon("Tree.collapsedIcon"));
1235: }
1236:
1237:
1240: protected void installKeyboardActions()
1241: {
1242: InputMap focusInputMap = (InputMap) UIManager.get("Tree.focusInputMap");
1243: InputMapUIResource parentInputMap = new InputMapUIResource();
1244: ActionMap parentActionMap = new ActionMapUIResource();
1245: action = new TreeAction();
1246: Object keys[] = focusInputMap.allKeys();
1247:
1248: for (int i = 0; i < keys.length; i++)
1249: {
1250: parentInputMap.put(
1251: KeyStroke.getKeyStroke(
1252: ((KeyStroke) keys[i]).getKeyCode(),
1253: convertModifiers(((KeyStroke) keys[i]).getModifiers())),
1254: (String) focusInputMap.get((KeyStroke) keys[i]));
1255:
1256: parentInputMap.put(
1257: KeyStroke.getKeyStroke(
1258: ((KeyStroke) keys[i]).getKeyCode(),
1259: ((KeyStroke) keys[i]).getModifiers()),
1260: (String) focusInputMap.get((KeyStroke) keys[i]));
1261:
1262: parentActionMap.put(
1263: (String) focusInputMap.get((KeyStroke) keys[i]),
1264: new ActionListenerProxy(
1265: action,
1266: (String) focusInputMap.get((KeyStroke) keys[i])));
1267:
1268: }
1269:
1270: parentInputMap.setParent(tree.getInputMap(
1271: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).getParent());
1272: parentActionMap.setParent(tree.getActionMap().getParent());
1273: tree.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).setParent(
1274: parentInputMap);
1275: tree.getActionMap().setParent(parentActionMap);
1276: }
1277:
1278:
1285: private int convertModifiers(int mod)
1286: {
1287: if ((mod & KeyEvent.SHIFT_DOWN_MASK) != 0)
1288: {
1289: mod |= KeyEvent.SHIFT_MASK;
1290: mod &= ~KeyEvent.SHIFT_DOWN_MASK;
1291: }
1292: if ((mod & KeyEvent.CTRL_DOWN_MASK) != 0)
1293: {
1294: mod |= KeyEvent.CTRL_MASK;
1295: mod &= ~KeyEvent.CTRL_DOWN_MASK;
1296: }
1297: if ((mod & KeyEvent.META_DOWN_MASK) != 0)
1298: {
1299: mod |= KeyEvent.META_MASK;
1300: mod &= ~KeyEvent.META_DOWN_MASK;
1301: }
1302: if ((mod & KeyEvent.ALT_DOWN_MASK) != 0)
1303: {
1304: mod |= KeyEvent.ALT_MASK;
1305: mod &= ~KeyEvent.ALT_DOWN_MASK;
1306: }
1307: if ((mod & KeyEvent.ALT_GRAPH_DOWN_MASK) != 0)
1308: {
1309: mod |= KeyEvent.ALT_GRAPH_MASK;
1310: mod &= ~KeyEvent.ALT_GRAPH_DOWN_MASK;
1311: }
1312: return mod;
1313: }
1314:
1315:
1318: protected void installListeners()
1319: {
1320: tree.addPropertyChangeListener(propertyChangeListener);
1321: tree.addFocusListener(focusListener);
1322: tree.addTreeSelectionListener(treeSelectionListener);
1323: tree.addMouseListener(mouseListener);
1324: tree.addKeyListener(keyListener);
1325: tree.addPropertyChangeListener(selectionModelPropertyChangeListener);
1326: tree.addComponentListener(componentListener);
1327: tree.addTreeExpansionListener(treeExpansionListener);
1328: if (treeModel != null)
1329: treeModel.addTreeModelListener(treeModelListener);
1330: }
1331:
1332:
1338: public void installUI(JComponent c)
1339: {
1340: tree = (JTree) c;
1341: prepareForUIInstall();
1342: super.installUI(c);
1343: installDefaults();
1344:
1345: installComponents();
1346: installKeyboardActions();
1347: installListeners();
1348:
1349: setCellEditor(createDefaultCellEditor());
1350: createdCellEditor = true;
1351: isEditing = false;
1352:
1353: TreeModel mod = tree.getModel();
1354: setModel(mod);
1355: if (mod != null)
1356: {
1357: TreePath path = new TreePath(mod.getRoot());
1358: if (!tree.isExpanded(path))
1359: toggleExpandState(path);
1360: }
1361: treeSelectionModel = tree.getSelectionModel();
1362:
1363: completeUIInstall();
1364: }
1365:
1366:
1369: protected void uninstallDefaults()
1370: {
1371: tree.setFont(null);
1372: tree.setForeground(null);
1373: tree.setBackground(null);
1374: }
1375:
1376:
1382: public void uninstallUI(JComponent c)
1383: {
1384: prepareForUIUninstall();
1385: uninstallDefaults();
1386: uninstallKeyboardActions();
1387: uninstallListeners();
1388: tree = null;
1389: uninstallComponents();
1390: completeUIUninstall();
1391: }
1392:
1393:
1406: public void paint(Graphics g, JComponent c)
1407: {
1408: JTree tree = (JTree) c;
1409: if (currentVisiblePath == null)
1410: updateCurrentVisiblePath();
1411:
1412: Rectangle clip = g.getClipBounds();
1413: Insets insets = tree.getInsets();
1414:
1415: if (clip != null && treeModel != null && currentVisiblePath != null)
1416: {
1417: int startIndex = tree.getClosestRowForLocation(clip.x, clip.y);
1418: int endIndex = tree.getClosestRowForLocation(clip.x + clip.width,
1419: clip.y + clip.height);
1420:
1421: paintVerticalPartOfLeg(g, clip, insets, currentVisiblePath);
1422: for (int i = startIndex; i <= endIndex; i++)
1423: {
1424: Object curr = currentVisiblePath.getPathComponent(i);
1425: boolean isLeaf = treeModel.isLeaf(curr);
1426: TreePath path = new TreePath(getPathToRoot(curr, 0));
1427:
1428: boolean isExpanded = tree.isExpanded(path);
1429: Rectangle bounds = getPathBounds(tree, path);
1430: paintHorizontalPartOfLeg(g, clip, insets, bounds, path, i,
1431: isExpanded, false, isLeaf);
1432: paintRow(g, clip, insets, bounds, path, i, isExpanded, false,
1433: isLeaf);
1434: }
1435: }
1436: }
1437:
1438:
1446: protected void ensureRowsAreVisible(int beginRow, int endRow)
1447: {
1448: if (beginRow < endRow)
1449: {
1450: int temp = endRow;
1451: endRow = beginRow;
1452: beginRow = temp;
1453: }
1454:
1455: for (int i = beginRow; i < endRow; i++)
1456: {
1457: TreePath path = getPathForRow(tree, i);
1458: if (!tree.isVisible(path))
1459: tree.makeVisible(path);
1460: }
1461: }
1462:
1463:
1469: public void setPreferredMinSize(Dimension newSize)
1470: {
1471: preferredMinSize = newSize;
1472: }
1473:
1474:
1479: public Dimension getPreferredMinSize()
1480: {
1481: return preferredMinSize;
1482: }
1483:
1484:
1494: public Dimension getPreferredSize(JComponent c)
1495: {
1496: return getPreferredSize(c, false);
1497: }
1498:
1499:
1509: public Dimension getPreferredSize(JComponent c, boolean checkConsistancy)
1510: {
1511:
1512: if(!validCachedPreferredSize)
1513: updateCachedPreferredSize();
1514: return preferredSize;
1515: }
1516:
1517:
1525: public Dimension getMinimumSize(JComponent c)
1526: {
1527: Dimension min = getPreferredMinSize();
1528: if (min == null)
1529: return new Dimension();
1530: return min;
1531: }
1532:
1533:
1541: public Dimension getMaximumSize(JComponent c)
1542: {
1543: if (c instanceof JTree)
1544: return ((JTree) c).getPreferredSize();
1545: return new Dimension();
1546: }
1547:
1548:
1555: protected void completeEditing()
1556: {
1557: completeEditing(false, true, false);
1558: }
1559:
1560:
1573: protected void completeEditing(boolean messageStop, boolean messageCancel,
1574: boolean messageTree)
1575: {
1576: if (messageStop)
1577: {
1578: getCellEditor().stopCellEditing();
1579: stopEditingInCompleteEditing = true;
1580: }
1581:
1582: if (messageCancel)
1583: {
1584: getCellEditor().cancelCellEditing();
1585: stopEditingInCompleteEditing = true;
1586: }
1587:
1588: if (messageTree)
1589: treeModel.valueForPathChanged(tree.getLeadSelectionPath(), newVal);
1590: }
1591:
1592:
1602: protected boolean startEditing(TreePath path, MouseEvent event)
1603: {
1604: int x;
1605: int y;
1606: if (event == null)
1607: {
1608: Rectangle bounds = getPathBounds(tree, path);
1609: x = bounds.x;
1610: y = bounds.y;
1611: }
1612: else
1613: {
1614: x = event.getX();
1615: y = event.getY();
1616: }
1617:
1618: updateCellEditor();
1619: TreeCellEditor ed = getCellEditor();
1620: if (ed != null && ed.shouldSelectCell(event) && ed.isCellEditable(event))
1621: {
1622: editingPath = path;
1623: editingRow = tree.getRowForPath(editingPath);
1624:
1625: Object val = editingPath.getLastPathComponent();
1626: cellEditor.addCellEditorListener(cellEditorListener);
1627: stopEditingInCompleteEditing = false;
1628: boolean expanded = tree.isExpanded(editingPath);
1629: isEditing = true;
1630: editingComponent = ed.getTreeCellEditorComponent(tree, val, true,
1631: expanded,
1632: isLeaf(editingRow),
1633: editingRow);
1634: editingComponent.getParent().setVisible(true);
1635: editingComponent.getParent().validate();
1636: tree.add(editingComponent.getParent());
1637: editingComponent.getParent().validate();
1638: validCachedPreferredSize = false;
1639: tree.revalidate();
1640: ((JTextField) editingComponent).requestFocusInWindow(false);
1641: editorTimer.start();
1642: return true;
1643: }
1644: return false;
1645: }
1646:
1647:
1658: protected void checkForClickInExpandControl(TreePath path, int mouseX,
1659: int mouseY)
1660: {
1661: if (isLocationInExpandControl(path, mouseX, mouseY))
1662: toggleExpandState(path);
1663: }
1664:
1665:
1680: protected boolean isLocationInExpandControl(TreePath path, int mouseX,
1681: int mouseY)
1682: {
1683: boolean cntlClick = false;
1684: int row = getRowForPath(tree, path);
1685:
1686: if (!isLeaf(row))
1687: {
1688: Rectangle bounds = getPathBounds(tree, path);
1689:
1690: if (hasControlIcons() && (mouseX < bounds.x)
1691: && (mouseX > (bounds.x - getCurrentControlIcon(path).getIconWidth() - gap)))
1692: cntlClick = true;
1693: }
1694: return cntlClick;
1695: }
1696:
1697:
1708: protected void handleExpandControlClick(TreePath path, int mouseX, int mouseY)
1709: {
1710: toggleExpandState(path);
1711: }
1712:
1713:
1722: protected void toggleExpandState(TreePath path)
1723: {
1724: if (tree.isExpanded(path))
1725: tree.collapsePath(path);
1726: else
1727: tree.expandPath(path);
1728: updateCurrentVisiblePath();
1729: }
1730:
1731:
1740: protected boolean isToggleSelectionEvent(MouseEvent event)
1741: {
1742: return (tree.getSelectionModel().getSelectionMode() ==
1743: TreeSelectionModel.SINGLE_TREE_SELECTION);
1744: }
1745:
1746:
1755: protected boolean isMultiSelectEvent(MouseEvent event)
1756: {
1757: return (tree.getSelectionModel().getSelectionMode() ==
1758: TreeSelectionModel.CONTIGUOUS_TREE_SELECTION);
1759: }
1760:
1761:
1771: protected boolean isToggleEvent(MouseEvent event)
1772: {
1773: return true;
1774: }
1775:
1776:
1788: protected void selectPathForEvent(TreePath path, MouseEvent event)
1789: {
1790: if (isToggleSelectionEvent(event))
1791: {
1792: if (tree.isPathSelected(path))
1793: tree.removeSelectionPath(path);
1794: else
1795: {
1796: tree.addSelectionPath(path);
1797: tree.setAnchorSelectionPath(path);
1798: }
1799: }
1800: else if (isMultiSelectEvent(event))
1801: {
1802: TreePath anchor = tree.getAnchorSelectionPath();
1803: if (anchor != null)
1804: {
1805: int aRow = getRowForPath(tree, anchor);
1806: tree.addSelectionInterval(aRow, getRowForPath(tree, path));
1807: }
1808: else
1809: tree.addSelectionPath(path);
1810: }
1811: else
1812: tree.addSelectionPath(path);
1813: }
1814:
1815:
1822: protected boolean isLeaf(int row)
1823: {
1824: TreePath pathForRow = getPathForRow(tree, row);
1825: if (pathForRow == null)
1826: return true;
1827:
1828: Object node = pathForRow.getLastPathComponent();
1829: return treeModel.isLeaf(node);
1830: }
1831:
1832:
1837: class TreeAction
1838: extends AbstractAction
1839: {
1840:
1841:
1847: public void actionPerformed(ActionEvent e)
1848: {
1849: TreePath lead = tree.getLeadSelectionPath();
1850:
1851: if (e.getActionCommand().equals("selectPreviousChangeLead")
1852: || e.getActionCommand().equals("selectPreviousExtendSelection")
1853: || e.getActionCommand().equals("selectPrevious")
1854: || e.getActionCommand().equals("selectNext")
1855: || e.getActionCommand().equals("selectNextExtendSelection")
1856: || e.getActionCommand().equals("selectNextChangeLead"))
1857: (new TreeIncrementAction(0, "")).actionPerformed(e);
1858: else if (e.getActionCommand().equals("selectParent")
1859: || e.getActionCommand().equals("selectChild"))
1860: (new TreeTraverseAction(0, "")).actionPerformed(e);
1861: else if (e.getActionCommand().equals("selectAll"))
1862: {
1863: TreePath[] paths = new TreePath[tree.getVisibleRowCount()];
1864:
1865: Object curr = getNextVisibleNode(treeModel.getRoot());
1866: int i = 0;
1867: while (curr != null && i < paths.length)
1868: {
1869: paths[i] = new TreePath(getPathToRoot(curr, 0));
1870: i++;
1871: }
1872:
1873: tree.addSelectionPaths(paths);
1874: }
1875: else if (e.getActionCommand().equals("startEditing"))
1876: tree.startEditingAtPath(lead);
1877: else if (e.getActionCommand().equals("toggle"))
1878: {
1879: if (tree.isEditing())
1880: tree.stopEditing();
1881: else
1882: {
1883: Object last = lead.getLastPathComponent();
1884: TreePath path = new TreePath(getPathToRoot(last, 0));
1885: if (!treeModel.isLeaf(last))
1886: toggleExpandState(path);
1887: }
1888: }
1889: else if (e.getActionCommand().equals("clearSelection"))
1890: tree.clearSelection();
1891:
1892: if (tree.isEditing() && !e.getActionCommand().equals("startEditing"))
1893: tree.cancelEditing();
1894:
1895: tree.scrollPathToVisible(lead);
1896: }
1897: }
1898:
1899:
1906: private static class ActionListenerProxy
1907: extends AbstractAction
1908: {
1909: ActionListener target;
1910:
1911: String bindingCommandName;
1912:
1913: public ActionListenerProxy(ActionListener li, String cmd)
1914: {
1915: target = li;
1916: bindingCommandName = cmd;
1917: }
1918:
1919: public void actionPerformed(ActionEvent e)
1920: {
1921: ActionEvent derivedEvent = new ActionEvent(e.getSource(), e.getID(),
1922: bindingCommandName,
1923: e.getModifiers());
1924:
1925: target.actionPerformed(derivedEvent);
1926: }
1927: }
1928:
1929:
1932: private class EditorUpdateTimer
1933: extends Timer
1934: implements ActionListener
1935: {
1936:
1940: public EditorUpdateTimer()
1941: {
1942: super(300, null);
1943: addActionListener(this);
1944: }
1945:
1946:
1949: public void actionPerformed(ActionEvent ev)
1950: {
1951: Caret c = ((JTextField) editingComponent).getCaret();
1952: if (c != null)
1953: c.setVisible(!c.isVisible());
1954: tree.repaint();
1955: }
1956:
1957:
1960: public void update()
1961: {
1962: stop();
1963: Caret c = ((JTextField) editingComponent).getCaret();
1964: if (c != null)
1965: {
1966: setDelay(c.getBlinkRate());
1967: if (((JTextField) editingComponent).isEditable())
1968: start();
1969: else
1970: c.setVisible(false);
1971: }
1972: }
1973: }
1974:
1975:
1978: public class ComponentHandler extends ComponentAdapter
1979: implements ActionListener
1980: {
1981:
1984: protected Timer timer;
1985:
1986:
1987: protected JScrollBar scrollBar;
1988:
1989:
1992: public ComponentHandler()
1993: {
1994:
1995: }
1996:
1997:
2003: public void componentMoved(ComponentEvent e)
2004: {
2005:
2006: }
2007:
2008:
2012: protected void startTimer()
2013: {
2014:
2015: }
2016:
2017:
2022: protected JScrollPane getScrollPane()
2023: {
2024: return null;
2025: }
2026:
2027:
2034: public void actionPerformed(ActionEvent ae)
2035: {
2036:
2037: }
2038: }
2039:
2040:
2044: public class CellEditorHandler implements CellEditorListener
2045: {
2046:
2049: public CellEditorHandler()
2050: {
2051:
2052: }
2053:
2054:
2061: public void editingStopped(ChangeEvent e)
2062: {
2063: editingPath = null;
2064: editingRow = -1;
2065: stopEditingInCompleteEditing = false;
2066: if (editingComponent != null)
2067: {
2068: tree.remove(editingComponent.getParent());
2069: editingComponent = null;
2070: }
2071: if (cellEditor != null)
2072: {
2073: newVal = ((JTextField) getCellEditor().getCellEditorValue()).getText();
2074: completeEditing(false, false, true);
2075: if (cellEditor instanceof DefaultTreeCellEditor)
2076: tree.removeTreeSelectionListener((DefaultTreeCellEditor) cellEditor);
2077: cellEditor.removeCellEditorListener(cellEditorListener);
2078: setCellEditor(null);
2079: createdCellEditor = false;
2080: }
2081: isEditing = false;
2082: tree.requestFocusInWindow(false);
2083: editorTimer.stop();
2084: validCachedPreferredSize = false;
2085: tree.revalidate();
2086: tree.repaint();
2087: }
2088:
2089:
2096: public void editingCanceled(ChangeEvent e)
2097: {
2098: editingPath = null;
2099: editingRow = -1;
2100: stopEditingInCompleteEditing = false;
2101: if (editingComponent != null)
2102: tree.remove(editingComponent.getParent());
2103: editingComponent = null;
2104: if (cellEditor != null)
2105: {
2106: if (cellEditor instanceof DefaultTreeCellEditor)
2107: tree.removeTreeSelectionListener((DefaultTreeCellEditor) cellEditor);
2108: cellEditor.removeCellEditorListener(cellEditorListener);
2109: setCellEditor(null);
2110: createdCellEditor = false;
2111: }
2112: tree.requestFocusInWindow(false);
2113: editorTimer.stop();
2114: isEditing = false;
2115: validCachedPreferredSize = false;
2116: tree.revalidate();
2117: tree.repaint();
2118: }
2119: }
2120:
2121:
2124: public class FocusHandler
2125: implements FocusListener
2126: {
2127:
2130: public FocusHandler()
2131: {
2132:
2133: }
2134:
2135:
2142: public void focusGained(FocusEvent e)
2143: {
2144:
2145: }
2146:
2147:
2154: public void focusLost(FocusEvent e)
2155: {
2156:
2157: }
2158: }
2159:
2160:
2164: public class KeyHandler
2165: extends KeyAdapter
2166: {
2167:
2168: protected Action repeatKeyAction;
2169:
2170:
2171: protected boolean isKeyDown;
2172:
2173:
2176: public KeyHandler()
2177: {
2178:
2179: }
2180:
2181:
2190: public void keyTyped(KeyEvent e)
2191: {
2192:
2193: }
2194:
2195:
2201: public void keyPressed(KeyEvent e)
2202: {
2203:
2204: }
2205:
2206:
2212: public void keyReleased(KeyEvent e)
2213: {
2214:
2215: }
2216: }
2217:
2218:
2222: public class MouseHandler extends MouseAdapter implements MouseMotionListener
2223: {
2224:
2227: public MouseHandler()
2228: {
2229:
2230: }
2231:
2232:
2238: public void mousePressed(MouseEvent e)
2239: {
2240: Point click = e.getPoint();
2241: TreePath path = getClosestPathForLocation(tree, click.x, click.y);
2242:
2243: if (path != null)
2244: {
2245: Rectangle bounds = getPathBounds(tree, path);
2246: int row = getRowForPath(tree, path);
2247: boolean cntlClick = isLocationInExpandControl(path, click.x, click.y);
2248:
2249: boolean isLeaf = isLeaf(row);
2250:
2251: TreeCellRenderer tcr = getCellRenderer();
2252: Icon icon;
2253: if (isLeaf)
2254: icon = UIManager.getIcon("Tree.leafIcon");
2255: else if (tree.isExpanded(path))
2256: icon = UIManager.getIcon("Tree.openIcon");
2257: else
2258: icon = UIManager.getIcon("Tree.closedIcon");
2259:
2260: if (tcr instanceof DefaultTreeCellRenderer)
2261: {
2262: Icon tmp = ((DefaultTreeCellRenderer) tcr).getIcon();
2263: if (tmp != null)
2264: icon = tmp;
2265: }
2266:
2267:
2268: if (icon != null)
2269: bounds.width += icon.getIconWidth() + gap*2;
2270:
2271: boolean inBounds = bounds.contains(click.x, click.y);
2272: if ((inBounds || cntlClick) && tree.isVisible(path))
2273: {
2274: if (inBounds)
2275: {
2276: selectPath(tree, path);
2277: if (e.getClickCount() == 2 && !isLeaf(row))
2278: toggleExpandState(path);
2279: }
2280:
2281: if (cntlClick)
2282: {
2283: handleExpandControlClick(path, click.x, click.y);
2284: if (cellEditor != null)
2285: cellEditor.cancelCellEditing();
2286: tree.scrollPathToVisible(path);
2287: }
2288: else if (tree.isEditable())
2289: startEditing(path, e);
2290: }
2291: }
2292: }
2293:
2294:
2303: public void mouseDragged(MouseEvent e)
2304: {
2305:
2306: }
2307:
2308:
2315: public void mouseMoved(MouseEvent e)
2316: {
2317:
2318: }
2319:
2320:
2326: public void mouseReleased(MouseEvent e)
2327: {
2328:
2329: }
2330: }
2331:
2332:
2337: public class MouseInputHandler implements MouseInputListener
2338: {
2339:
2340: protected Component source;
2341:
2342:
2343: protected Component destination;
2344:
2345:
2355: public MouseInputHandler(Component source, Component destination,
2356: MouseEvent e)
2357: {
2358: this.source = source;
2359: this.destination = destination;
2360: }
2361:
2362:
2369: public void mouseClicked(MouseEvent e)
2370: {
2371:
2372: }
2373:
2374:
2380: public void mousePressed(MouseEvent e)
2381: {
2382:
2383: }
2384:
2385:
2391: public void mouseReleased(MouseEvent e)
2392: {
2393:
2394: }
2395:
2396:
2402: public void mouseEntered(MouseEvent e)
2403: {
2404:
2405: }
2406:
2407:
2413: public void mouseExited(MouseEvent e)
2414: {
2415:
2416: }
2417:
2418:
2427: public void mouseDragged(MouseEvent e)
2428: {
2429:
2430: }
2431:
2432:
2439: public void mouseMoved(MouseEvent e)
2440: {
2441:
2442: }
2443:
2444:
2447: protected void removeFromSource()
2448: {
2449:
2450: }
2451: }
2452:
2453:
2458: public class NodeDimensionsHandler
2459: extends AbstractLayoutCache.NodeDimensions
2460: {
2461:
2464: public NodeDimensionsHandler()
2465: {
2466:
2467: }
2468:
2469:
2487: public Rectangle getNodeDimensions(Object cell, int row, int depth,
2488: boolean expanded, Rectangle size)
2489: {
2490: if (size == null || cell == null)
2491: return null;
2492:
2493: String s = cell.toString();
2494: Font f = tree.getFont();
2495: FontMetrics fm = tree.getToolkit().getFontMetrics(f);
2496:
2497: if (s != null)
2498: {
2499: size.x = getRowX(row, depth);
2500: size.width = SwingUtilities.computeStringWidth(fm, s);
2501: size.height = fm.getHeight();
2502: }
2503: return size;
2504: }
2505:
2506:
2511: protected int getRowX(int row, int depth)
2512: {
2513: if (row == 0)
2514: return 0;
2515: return depth * rightChildIndent;
2516: }
2517: }
2518:
2519:
2523: public class PropertyChangeHandler
2524: implements PropertyChangeListener
2525: {
2526:
2527:
2530: public PropertyChangeHandler()
2531: {
2532:
2533: }
2534:
2535:
2542: public void propertyChange(PropertyChangeEvent event)
2543: {
2544: if ((event.getPropertyName()).equals("rootVisible"))
2545: {
2546: validCachedPreferredSize = false;
2547: updateCurrentVisiblePath();
2548: tree.revalidate();
2549: tree.repaint();
2550: }
2551: }
2552: }
2553:
2554:
2558: public class SelectionModelPropertyChangeHandler
2559: implements PropertyChangeListener
2560: {
2561:
2562:
2565: public SelectionModelPropertyChangeHandler()
2566: {
2567:
2568: }
2569:
2570:
2577: public void propertyChange(PropertyChangeEvent event)
2578: {
2579:
2580: }
2581: }
2582:
2583:
2586: public class TreeCancelEditingAction
2587: extends AbstractAction
2588: {
2589:
2590:
2593: public TreeCancelEditingAction(String name)
2594: {
2595:
2596: }
2597:
2598:
2604: public void actionPerformed(ActionEvent e)
2605: {
2606:
2607: }
2608:
2609:
2614: public boolean isEnabled()
2615: {
2616:
2617: return false;
2618: }
2619: }
2620:
2621:
2624: public class TreeExpansionHandler
2625: implements TreeExpansionListener
2626: {
2627:
2628:
2631: public TreeExpansionHandler()
2632: {
2633:
2634: }
2635:
2636:
2642: public void treeExpanded(TreeExpansionEvent event)
2643: {
2644: validCachedPreferredSize = false;
2645: updateCurrentVisiblePath();
2646: tree.revalidate();
2647: tree.repaint();
2648: }
2649:
2650:
2656: public void treeCollapsed(TreeExpansionEvent event)
2657: {
2658: validCachedPreferredSize = false;
2659: updateCurrentVisiblePath();
2660: tree.revalidate();
2661: tree.repaint();
2662: }
2663: }
2664:
2665:
2669: public class TreeHomeAction
2670: extends AbstractAction
2671: {
2672:
2673:
2674: protected int direction;
2675:
2676:
2684: public TreeHomeAction(int direction, String name)
2685: {
2686:
2687: }
2688:
2689:
2695: public void actionPerformed(ActionEvent e)
2696: {
2697:
2698: }
2699:
2700:
2705: public boolean isEnabled()
2706: {
2707:
2708: return false;
2709: }
2710: }
2711:
2712:
2716: public class TreeIncrementAction
2717: extends AbstractAction
2718: {
2719:
2720:
2721: protected int direction;
2722:
2723:
2731: public TreeIncrementAction(int direction, String name)
2732: {
2733:
2734: }
2735:
2736:
2742: public void actionPerformed(ActionEvent e)
2743: {
2744: Object last = tree.getLeadSelectionPath().getLastPathComponent();
2745:
2746: if (e.getActionCommand().equals("selectPreviousChangeLead"))
2747: {
2748: Object prev = getPreviousVisibleNode(last);
2749:
2750: if (prev != null)
2751: {
2752: TreePath newPath = new TreePath(getPathToRoot(prev, 0));
2753: selectPath(tree, newPath);
2754: tree.setLeadSelectionPath(newPath);
2755: }
2756: }
2757: else if (e.getActionCommand().equals("selectPreviousExtendSelection"))
2758: {
2759: Object prev = getPreviousVisibleNode(last);
2760: if (prev != null)
2761: {
2762: TreePath newPath = new TreePath(getPathToRoot(prev, 0));
2763: tree.addSelectionPath(newPath);
2764: tree.setLeadSelectionPath(newPath);
2765: }
2766: }
2767: else if (e.getActionCommand().equals("selectPrevious"))
2768: {
2769: Object prev = getPreviousVisibleNode(last);
2770:
2771: if (prev != null)
2772: {
2773: TreePath newPath = new TreePath(getPathToRoot(prev, 0));
2774: selectPath(tree, newPath);
2775: }
2776: }
2777: else if (e.getActionCommand().equals("selectNext"))
2778: {
2779: Object next = getNextVisibleNode(last);
2780:
2781: if (next != null)
2782: {
2783: TreePath newPath = new TreePath(getPathToRoot(next, 0));
2784: selectPath(tree, newPath);
2785: }
2786: }
2787: else if (e.getActionCommand().equals("selectNextExtendSelection"))
2788: {
2789: Object next = getNextVisibleNode(last);
2790: if (next != null)
2791: {
2792: TreePath newPath = new TreePath(getPathToRoot(next, 0));
2793: tree.addSelectionPath(newPath);
2794: tree.setLeadSelectionPath(newPath);
2795: }
2796: }
2797: else if (e.getActionCommand().equals("selectNextChangeLead"))
2798: {
2799: Object next = getNextVisibleNode(last);
2800: if (next != null)
2801: {
2802: TreePath newPath = new TreePath(getPathToRoot(next, 0));
2803: selectPath(tree, newPath);
2804: tree.setLeadSelectionPath(newPath);
2805: }
2806: }
2807: }
2808:
2809:
2814: public boolean isEnabled()
2815: {
2816:
2817: return false;
2818: }
2819: }
2820:
2821:
2824: public class TreeModelHandler implements TreeModelListener
2825: {
2826:
2829: public TreeModelHandler()
2830: {
2831:
2832: }
2833:
2834:
2847: public void treeNodesChanged(TreeModelEvent e)
2848: {
2849: validCachedPreferredSize = false;
2850: updateCurrentVisiblePath();
2851: tree.revalidate();
2852: tree.repaint();
2853: }
2854:
2855:
2863: public void treeNodesInserted(TreeModelEvent e)
2864: {
2865: validCachedPreferredSize = false;
2866: updateCurrentVisiblePath();
2867: tree.revalidate();
2868: tree.repaint();
2869: }
2870:
2871:
2882: public void treeNodesRemoved(TreeModelEvent e)
2883: {
2884: validCachedPreferredSize = false;
2885: updateCurrentVisiblePath();
2886: tree.revalidate();
2887: tree.repaint();
2888: }
2889:
2890:
2900: public void treeStructureChanged(TreeModelEvent e)
2901: {
2902: if (e.getPath().length == 1
2903: && !e.getPath()[0].equals(treeModel.getRoot()))
2904: tree.expandPath(new TreePath(treeModel.getRoot()));
2905: updateCurrentVisiblePath();
2906: validCachedPreferredSize = false;
2907: tree.revalidate();
2908: tree.repaint();
2909: }
2910: }
2911:
2912:
2915: public class TreePageAction extends AbstractAction
2916: {
2917:
2918: protected int direction;
2919:
2920:
2928: public TreePageAction(int direction, String name)
2929: {
2930: this.direction = direction;
2931: }
2932:
2933:
2939: public void actionPerformed(ActionEvent e)
2940: {
2941:
2942: }
2943:
2944:
2949: public boolean isEnabled()
2950: {
2951: return false;
2952: }
2953: }
2954:
2955:
2959: public class TreeSelectionHandler implements TreeSelectionListener
2960: {
2961:
2964: public TreeSelectionHandler()
2965: {
2966:
2967: }
2968:
2969:
2976: public void valueChanged(TreeSelectionEvent event)
2977: {
2978: if (tree.isEditing())
2979: tree.cancelEditing();
2980: }
2981: }
2982:
2983:
2986: public class TreeToggleAction extends AbstractAction
2987: {
2988:
2994: public TreeToggleAction(String name)
2995: {
2996:
2997: }
2998:
2999:
3005: public void actionPerformed(ActionEvent e)
3006: {
3007:
3008: }
3009:
3010:
3015: public boolean isEnabled()
3016: {
3017: return false;
3018: }
3019: }
3020:
3021:
3025: public class TreeTraverseAction extends AbstractAction
3026: {
3027:
3030: protected int direction;
3031:
3032:
3040: public TreeTraverseAction(int direction, String name)
3041: {
3042: this.direction = direction;
3043: }
3044:
3045:
3051: public void actionPerformed(ActionEvent e)
3052: {
3053: Object last = tree.getLeadSelectionPath().getLastPathComponent();
3054:
3055: if (e.getActionCommand().equals("selectParent"))
3056: {
3057: TreePath path = new TreePath(getPathToRoot(last, 0));
3058: Object p = getParent(treeModel.getRoot(), last);
3059:
3060: if (!treeModel.isLeaf(last))
3061: toggleExpandState(path);
3062: else if (p != null)
3063: selectPath(tree, new TreePath(getPathToRoot(p, 0)));
3064: }
3065: else if (e.getActionCommand().equals("selectChild"))
3066: {
3067: TreePath path = new TreePath(getPathToRoot(last, 0));
3068:
3069: if (!treeModel.isLeaf(last))
3070: toggleExpandState(path);
3071: else
3072: {
3073: Object next = getNextVisibleNode(last);
3074:
3075: if (next != null)
3076: selectPath(tree, new TreePath(getPathToRoot(next, 0)));
3077: }
3078: }
3079: }
3080:
3081:
3086: public boolean isEnabled()
3087: {
3088:
3089: return false;
3090: }
3091: }
3092:
3093:
3099: boolean hasControlIcons()
3100: {
3101: if (expandedIcon != null || collapsedIcon != null)
3102: return true;
3103: return false;
3104: }
3105:
3106:
3112: Icon getCurrentControlIcon(TreePath path)
3113: {
3114: if (tree.isExpanded(path))
3115: return expandedIcon;
3116: return collapsedIcon;
3117: }
3118:
3119:
3128: Object getParent(Object root, Object node)
3129: {
3130: if (root == null || node == null ||
3131: root.equals(node))
3132: return null;
3133:
3134: if (node instanceof TreeNode)
3135: return ((TreeNode) node).getParent();
3136: return findNode(root, node);
3137: }
3138:
3139:
3148: private Object findNode(Object root, Object node)
3149: {
3150: if (!treeModel.isLeaf(root) && !root.equals(node))
3151: {
3152: int size = treeModel.getChildCount(root);
3153: for (int j = 0; j < size; j++)
3154: {
3155: Object child = treeModel.getChild(root, j);
3156: if (node.equals(child))
3157: return root;
3158:
3159: Object n = findNode(child, node);
3160: if (n != null)
3161: return n;
3162: }
3163: }
3164: return null;
3165: }
3166:
3167:
3176: Object getPreviousVisibleNode(Object node)
3177: {
3178: if (currentVisiblePath != null)
3179: {
3180: Object[] nodes = currentVisiblePath.getPath();
3181: int i = 0;
3182: while (i < nodes.length && !node.equals(nodes[i]))
3183: i++;
3184:
3185: if (i-1 >= 0)
3186: return nodes[i-1];
3187: }
3188: return null;
3189: }
3190:
3191:
3198: Object getNextNode(Object curr)
3199: {
3200: if (!treeModel.isLeaf(curr) && treeModel.getChildCount(curr) > 0)
3201: return treeModel.getChild(curr, 0);
3202:
3203: Object node = curr;
3204: Object sibling = null;
3205: do
3206: {
3207: sibling = getNextSibling(node);
3208: node = getParent(treeModel.getRoot(), node);
3209: }
3210: while (sibling == null && node != null);
3211:
3212: return sibling;
3213: }
3214:
3215:
3223: Object getPreviousNode(Object node)
3224: {
3225: Object parent = getParent(treeModel.getRoot(), node);
3226: if (parent == null)
3227: return null;
3228:
3229: Object sibling = getPreviousSibling(node);
3230:
3231: if (sibling == null)
3232: return parent;
3233:
3234: int size = 0;
3235: if (!treeModel.isLeaf(sibling))
3236: size = treeModel.getChildCount(sibling);
3237: while (size > 0)
3238: {
3239: sibling = treeModel.getChild(sibling, size - 1);
3240: if (!treeModel.isLeaf(sibling))
3241: size = treeModel.getChildCount(sibling);
3242: else
3243: size = 0;
3244: }
3245:
3246: return sibling;
3247: }
3248:
3249:
3257: Object getNextSibling(Object node)
3258: {
3259: Object parent = getParent(treeModel.getRoot(), node);
3260: if (parent == null)
3261: return null;
3262:
3263: int index = treeModel.getIndexOfChild(parent, node) + 1;
3264:
3265: int size = 0;
3266: if (!treeModel.isLeaf(parent))
3267: size = treeModel.getChildCount(parent);
3268: if (index == 0 || index >= size)
3269: return null;
3270:
3271: return treeModel.getChild(parent, index);
3272: }
3273:
3274:
3282: Object getPreviousSibling(Object node)
3283: {
3284: Object parent = getParent(treeModel.getRoot(), node);
3285: if (parent == null)
3286: return null;
3287:
3288: int index = treeModel.getIndexOfChild(parent, node) - 1;
3289:
3290: int size = 0;
3291: if (!treeModel.isLeaf(parent))
3292: size = treeModel.getChildCount(parent);
3293: if (index < 0 || index >= size)
3294: return null;
3295:
3296: return treeModel.getChild(parent, index);
3297: }
3298:
3299:
3308: void selectPath(JTree tree, TreePath path)
3309: {
3310: if (path != null)
3311: {
3312: if (tree.getSelectionModel().getSelectionMode() ==
3313: TreeSelectionModel.SINGLE_TREE_SELECTION)
3314: {
3315: tree.getSelectionModel().clearSelection();
3316: tree.addSelectionPath(path);
3317: tree.setLeadSelectionPath(path);
3318: }
3319: else if (tree.getSelectionModel().getSelectionMode() ==
3320: TreeSelectionModel.CONTIGUOUS_TREE_SELECTION)
3321: {
3322:
3323: }
3324: else
3325: {
3326: tree.addSelectionPath(path);
3327: tree.setLeadSelectionPath(path);
3328: tree.getSelectionModel().setSelectionMode
3329: (TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
3330: }
3331: }
3332: }
3333:
3334:
3344: Object[] getPathToRoot(Object node, int depth)
3345: {
3346: if (node == null)
3347: {
3348: if (depth == 0)
3349: return null;
3350:
3351: return new Object[depth];
3352: }
3353:
3354: Object[] path = getPathToRoot(getParent(treeModel.getRoot(), node), depth + 1);
3355: path[path.length - depth - 1] = node;
3356: return path;
3357: }
3358:
3359:
3366: int getLevel(Object node)
3367: {
3368: int count = -1;
3369:
3370: Object current = node;
3371:
3372: if (treeModel != null)
3373: {
3374: Object root = treeModel.getRoot();
3375: if (!tree.isRootVisible() && tree.isExpanded(new TreePath(root)))
3376: count--;
3377:
3378: do
3379: {
3380: current = getParent(root, current);
3381: count++;
3382: }
3383: while (current != null);
3384: }
3385: return count;
3386: }
3387:
3388:
3402: protected void paintVerticalLine(Graphics g, JComponent c, int x, int top,
3403: int bottom)
3404: {
3405:
3406: g.setColor(getHashColor());
3407: g.drawLine(x, top, x, bottom);
3408: }
3409:
3410:
3424: protected void paintHorizontalLine(Graphics g, JComponent c, int y, int left,
3425: int right)
3426: {
3427:
3428: g.setColor(getHashColor());
3429: g.drawLine(left, y, right, y);
3430: }
3431:
3432:
3446: protected void drawCentered(Component c, Graphics g, Icon icon, int x, int y)
3447: {
3448: x -= icon.getIconWidth() / 2;
3449: y -= icon.getIconHeight() / 2;
3450:
3451: if (x < 0)
3452: x = 0;
3453: if (y < 0)
3454: y = 0;
3455:
3456: icon.paintIcon(c, g, x, y);
3457: }
3458:
3459:
3467: protected void drawDashedHorizontalLine(Graphics g, int y, int x1, int x2)
3468: {
3469: g.setColor(getHashColor());
3470: for (int i = x1; i < x2; i += 2)
3471: g.drawLine(i, y, i + 1, y);
3472: }
3473:
3474:
3482: protected void drawDashedVerticalLine(Graphics g, int x, int y1, int y2)
3483: {
3484: g.setColor(getHashColor());
3485: for (int i = y1; i < y2; i += 2)
3486: g.drawLine(x, i, x, i + 1);
3487: }
3488:
3489:
3503: protected void paintExpandControl(Graphics g, Rectangle clipBounds,
3504: Insets insets, Rectangle bounds,
3505: TreePath path, int row,
3506: boolean isExpanded, boolean hasBeenExpanded,
3507: boolean isLeaf)
3508: {
3509: if (shouldPaintExpandControl(path, row, isExpanded, hasBeenExpanded, isLeaf))
3510: {
3511: Icon icon = getCurrentControlIcon(path);
3512: int iconW = icon.getIconWidth();
3513: int x = bounds.x - rightChildIndent + iconW/2;
3514: if (x + iconW > bounds.x)
3515: x = bounds.x - rightChildIndent - gap;
3516: icon.paintIcon(tree, g, x, bounds.y + bounds.height/2 - icon.getIconHeight()/2);
3517: }
3518: }
3519:
3520:
3535: protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds,
3536: Insets insets, Rectangle bounds,
3537: TreePath path, int row,
3538: boolean isExpanded, boolean hasBeenExpanded,
3539: boolean isLeaf)
3540: {
3541: if (row != 0)
3542: paintHorizontalLine(g, tree, bounds.y + bounds.height/2, bounds.x - gap - 2,
3543: bounds.x);
3544: }
3545:
3546:
3555: protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds,
3556: Insets insets, TreePath path)
3557: {
3558: int max = tree.getVisibleRowCount();
3559: for (int i = 0; i < max; i++)
3560: {
3561: Object curr = path.getPathComponent(i);
3562: TreePath currPath = new TreePath(getPathToRoot(curr, 0));
3563: int numChild = treeModel.getChildCount(curr);
3564: if (numChild > 0 && tree.isExpanded(currPath))
3565: {
3566: Rectangle bounds = getPathBounds(tree, currPath);
3567: Rectangle lastChildBounds = getPathBounds(tree,
3568: new TreePath(getPathToRoot(
3569: treeModel.getChild(curr, numChild - 1),
3570: 0)));
3571: paintVerticalLine(g, tree, bounds.x + gap + 2, bounds.y +
3572: bounds.height - 2, lastChildBounds.y +
3573: lastChildBounds.height/2);
3574: }
3575: }
3576: }
3577:
3578:
3592: protected void paintRow(Graphics g, Rectangle clipBounds,
3593: Insets insets, Rectangle bounds,
3594: TreePath path, int row,
3595: boolean isExpanded, boolean hasBeenExpanded,
3596: boolean isLeaf)
3597: {
3598: boolean selected = tree.isPathSelected(path);
3599: boolean hasIcons = false;
3600: Object node = path.getLastPathComponent();
3601:
3602: if (tree.isVisible(path))
3603: {
3604: if (!validCachedPreferredSize)
3605: updateCachedPreferredSize();
3606:
3607:
3608: paintExpandControl(g, clipBounds, insets, bounds, path, row, isExpanded, hasBeenExpanded, isLeaf);
3609:
3610: if (row != 0)
3611: bounds.x += gap;
3612: bounds.width = preferredSize.width + bounds.x;
3613:
3614: if (editingComponent != null && editingPath != null && isEditing(tree)
3615: && node.equals(editingPath.getLastPathComponent()))
3616: {
3617: rendererPane.paintComponent(g, editingComponent.getParent(), null,
3618: bounds);
3619: }
3620: else
3621: {
3622: TreeCellRenderer dtcr = tree.getCellRenderer();
3623: if (dtcr == null)
3624: dtcr = createDefaultCellRenderer();
3625:
3626: Component c = dtcr.getTreeCellRendererComponent(tree, node,
3627: selected, isExpanded, isLeaf, row, tree.hasFocus());
3628: rendererPane.paintComponent(g, c, c.getParent(), bounds);
3629: }
3630: }
3631: }
3632:
3633:
3636: protected void prepareForUIUninstall()
3637: {
3638:
3639: }
3640:
3641:
3651: protected boolean shouldPaintExpandControl(TreePath path, int row,
3652: boolean isExpanded,
3653: boolean hasBeenExpanded,
3654: boolean isLeaf)
3655: {
3656: Object node = path.getLastPathComponent();
3657: return (!isLeaf && getLevel(node) != 0 && hasControlIcons());
3658: }
3659:
3660:
3664: void updateCurrentVisiblePath()
3665: {
3666: if (treeModel == null)
3667: return;
3668:
3669: Object next = treeModel.getRoot();
3670: TreePath rootPath = new TreePath(next);
3671: Rectangle bounds = getPathBounds(tree, rootPath);
3672:
3673:
3674:
3675:
3676: if ((bounds.width == 0 && bounds.height == 0) || (!isRootVisible()
3677: && tree.isExpanded(new TreePath(next))))
3678: {
3679: next = getNextNode(next);
3680: rootPath = new TreePath(next);
3681: }
3682:
3683: Object root = next;
3684: TreePath current = null;
3685: while (next != null)
3686: {
3687: if (current == null)
3688: current = rootPath;
3689: else
3690: current = current.pathByAddingChild(next);
3691:
3692: do
3693: {
3694: TreePath path = new TreePath(getPathToRoot(next, 0));
3695: if ((tree.isVisible(path) && tree.isExpanded(path))
3696: || treeModel.isLeaf(next))
3697: next = getNextNode(next);
3698: else
3699: {
3700: Object pNext = next;
3701: next = getNextSibling(pNext);
3702:
3703: if (next == null)
3704: {
3705: Object parent = getParent(root, pNext);
3706: while (next == null && parent != null)
3707: {
3708: next = getNextSibling(parent);
3709: if (next == null)
3710: parent = getParent(root, parent);
3711: }
3712: }
3713: }
3714: }
3715: while (next != null &&
3716: !tree.isVisible(new TreePath(getPathToRoot(next, 0))));
3717: }
3718:
3719: currentVisiblePath = current;
3720: tree.setVisibleRowCount(getRowCount(tree));
3721:
3722: if (tree.getSelectionModel() != null && tree.getSelectionCount() == 0 &&
3723: currentVisiblePath != null)
3724: selectPath(tree, new TreePath(getPathToRoot(currentVisiblePath.
3725: getPathComponent(0), 0)));
3726: }
3727:
3728:
3737: Object getNextVisibleNode(Object node)
3738: {
3739: if (currentVisiblePath != null)
3740: {
3741: Object[] nodes = currentVisiblePath.getPath();
3742: int i = 0;
3743: while (i < nodes.length && !node.equals(nodes[i]))
3744: i++;
3745:
3746: if (i+1 < nodes.length)
3747: return nodes[i+1];
3748: }
3749: return null;
3750: }
3751: }