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: Rectangle bounds;
243:
244:
245: TreePath currentVisiblePath;
246:
247:
248: int gap = 4;
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.getLookAndFeelDefaults().getColor("Tree.hash");
307: }
308:
309:
315: protected void setHashColor(Color color)
316: {
317: UIDefaults defaults = UIManager.getLookAndFeelDefaults();
318: defaults.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: treeState.setRowHeight(rowHeight);
440: }
441:
442:
447: protected int getRowHeight()
448: {
449: return treeState.getRowHeight();
450: }
451:
452:
459: protected void setCellRenderer(TreeCellRenderer tcr)
460: {
461: currentCellRenderer = tcr;
462: updateRenderer();
463: }
464:
465:
471: protected TreeCellRenderer getCellRenderer()
472: {
473: if (currentCellRenderer != null)
474: return currentCellRenderer;
475:
476: return createDefaultCellRenderer();
477: }
478:
479:
485: protected void setModel(TreeModel model)
486: {
487: tree.setModel(model);
488: treeModel = tree.getModel();
489: }
490:
491:
496: protected TreeModel getModel()
497: {
498: return treeModel;
499: }
500:
501:
507: protected void setRootVisible(boolean newValue)
508: {
509: tree.setRootVisible(newValue);
510: }
511:
512:
517: protected boolean isRootVisible()
518: {
519: return tree.isRootVisible();
520: }
521:
522:
528: protected void setShowsRootHandles(boolean newValue)
529: {
530: tree.setShowsRootHandles(newValue);
531: }
532:
533:
538: protected boolean getShowsRootHandles()
539: {
540: return tree.getShowsRootHandles();
541: }
542:
543:
549: protected void setCellEditor(TreeCellEditor editor)
550: {
551: cellEditor = editor;
552: createdCellEditor = true;
553: }
554:
555:
560: protected TreeCellEditor getCellEditor()
561: {
562: return cellEditor;
563: }
564:
565:
571: protected void setEditable(boolean newValue)
572: {
573: tree.setEditable(newValue);
574: }
575:
576:
581: protected boolean isEditable()
582: {
583: return tree.isEditable();
584: }
585:
586:
593: protected void setSelectionModel(TreeSelectionModel newLSM)
594: {
595: if (newLSM != null)
596: {
597: treeSelectionModel = newLSM;
598: tree.setSelectionModel(treeSelectionModel);
599: }
600: }
601:
602:
607: protected TreeSelectionModel getSelectionModel()
608: {
609: return treeSelectionModel;
610: }
611:
612:
624: public Rectangle getPathBounds(JTree tree, TreePath path)
625: {
626: if (path != null)
627: {
628: Object cell = path.getLastPathComponent();
629:
630: if (treeModel != null)
631: {
632: Object root = treeModel.getRoot();
633:
634: if (!tree.isRootVisible() && tree.isExpanded(new TreePath(root)))
635: root = getNextNode(root);
636:
637: Point loc = getCellLocation(0, 0, tree, treeModel, cell, root);
638: return getCellBounds(loc.x, loc.y, cell);
639: }
640: }
641: return null;
642: }
643:
644:
653: public TreePath getPathForRow(JTree tree, int row)
654: {
655: if (treeModel != null && currentVisiblePath != null)
656: {
657: Object[] nodes = currentVisiblePath.getPath();
658: if (row < nodes.length)
659: return new TreePath(getPathToRoot(nodes[row], 0));
660: }
661: return null;
662: }
663:
664:
676: public int getRowForPath(JTree tree, TreePath path)
677: {
678: int row = 0;
679: Object dest = path.getLastPathComponent();
680: int rowCount = getRowCount(tree);
681: if (currentVisiblePath != null)
682: {
683: Object[] nodes = currentVisiblePath.getPath();
684: while (row < rowCount)
685: {
686: if (dest.equals(nodes[row]))
687: return row;
688: row++;
689: }
690: }
691: return -1;
692: }
693:
694:
701: public int getRowCount(JTree tree)
702: {
703: if (currentVisiblePath != null)
704: return currentVisiblePath.getPathCount();
705: return 0;
706: }
707:
708:
722: public TreePath getClosestPathForLocation(JTree tree, int x, int y)
723: {
724:
725:
726:
727: int row = Math.round(y / getRowHeight());
728: TreePath path = getPathForRow(tree, row);
729:
730:
731: while (row > 0 && path == null)
732: {
733: --row;
734: path = getPathForRow(tree, row);
735: }
736:
737: return path;
738: }
739:
740:
748: public boolean isEditing(JTree tree)
749: {
750: return isEditing;
751: }
752:
753:
762: public boolean stopEditing(JTree tree)
763: {
764: if (isEditing(tree))
765: completeEditing(true, false, false);
766: return !isEditing(tree);
767: }
768:
769:
775: public void cancelEditing(JTree tree)
776: {
777: if (isEditing(tree))
778: completeEditing(false, true, false);
779: }
780:
781:
790: public void startEditingAtPath(JTree tree, TreePath path)
791: {
792: startEditing(path, null);
793: }
794:
795:
802: public TreePath getEditingPath(JTree tree)
803: {
804: return editingPath;
805: }
806:
807:
811: protected void prepareForUIInstall()
812: {
813:
814: }
815:
816:
820: protected void completeUIInstall()
821: {
822:
823: }
824:
825:
829: protected void completeUIUninstall()
830: {
831:
832: }
833:
834:
837: protected void installComponents()
838: {
839: currentCellRenderer = createDefaultCellRenderer();
840: rendererPane = createCellRendererPane();
841: createdRenderer = true;
842: setCellRenderer(currentCellRenderer);
843: }
844:
845:
851: protected AbstractLayoutCache.NodeDimensions createNodeDimensions()
852: {
853: return new NodeDimensionsHandler();
854: }
855:
856:
862: protected PropertyChangeListener createPropertyChangeListener()
863: {
864: return new PropertyChangeHandler();
865: }
866:
867:
873: protected MouseListener createMouseListener()
874: {
875: return new MouseHandler();
876: }
877:
878:
884: protected FocusListener createFocusListener()
885: {
886: return new FocusHandler();
887: }
888:
889:
894: protected KeyListener createKeyListener()
895: {
896: return new KeyHandler();
897: }
898:
899:
906: protected PropertyChangeListener createSelectionModelPropertyChangeListener()
907: {
908: return new SelectionModelPropertyChangeHandler();
909: }
910:
911:
917: protected TreeSelectionListener createTreeSelectionListener()
918: {
919: return new TreeSelectionHandler();
920: }
921:
922:
927: protected CellEditorListener createCellEditorListener()
928: {
929: return new CellEditorHandler();
930: }
931:
932:
939: protected ComponentListener createComponentListener()
940: {
941: return new ComponentHandler();
942: }
943:
944:
950: protected TreeExpansionListener createTreeExpansionListener()
951: {
952: return new TreeExpansionHandler();
953: }
954:
955:
961: protected AbstractLayoutCache createLayoutCache()
962: {
963: return new FixedHeightLayoutCache();
964: }
965:
966:
971: protected CellRendererPane createCellRendererPane()
972: {
973: return new CellRendererPane();
974: }
975:
976:
981: protected TreeCellEditor createDefaultCellEditor()
982: {
983: if (currentCellRenderer != null)
984: return new DefaultTreeCellEditor(tree,
985: (DefaultTreeCellRenderer) currentCellRenderer,
986: cellEditor);
987: return new DefaultTreeCellEditor(tree,
988: (DefaultTreeCellRenderer) createDefaultCellRenderer(),
989: cellEditor);
990: }
991:
992:
999: protected TreeCellRenderer createDefaultCellRenderer()
1000: {
1001: return new DefaultTreeCellRenderer();
1002: }
1003:
1004:
1009: protected TreeModelListener createTreeModelListener()
1010: {
1011: return new TreeModelHandler();
1012: }
1013:
1014:
1017: protected void uninstallListeners()
1018: {
1019: tree.removePropertyChangeListener(propertyChangeListener);
1020: tree.removeFocusListener(focusListener);
1021: tree.removeTreeSelectionListener(treeSelectionListener);
1022: tree.removeMouseListener(mouseListener);
1023: tree.removeKeyListener(keyListener);
1024: tree.removePropertyChangeListener(selectionModelPropertyChangeListener);
1025: tree.removeComponentListener(componentListener);
1026: tree.removeTreeExpansionListener(treeExpansionListener);
1027:
1028: TreeCellEditor tce = tree.getCellEditor();
1029: if (tce != null)
1030: tce.removeCellEditorListener(cellEditorListener);
1031: if (treeModel != null)
1032: treeModel.removeTreeModelListener(treeModelListener);
1033: }
1034:
1035:
1038: protected void uninstallKeyboardActions()
1039: {
1040:
1041: }
1042:
1043:
1046: protected void uninstallComponents()
1047: {
1048: currentCellRenderer = null;
1049: rendererPane = null;
1050: createdRenderer = false;
1051: setCellRenderer(currentCellRenderer);
1052: }
1053:
1054:
1060: protected int getVerticalLegBuffer()
1061: {
1062: return getRowHeight() / 2;
1063: }
1064:
1065:
1072: protected int getHorizontalLegBuffer()
1073: {
1074: return rightChildIndent / 2;
1075: }
1076:
1077:
1081: protected void updateLayoutCacheExpandedNodes()
1082: {
1083: if (treeModel != null)
1084: updateExpandedDescendants(new TreePath(treeModel.getRoot()));
1085: }
1086:
1087:
1095: protected void updateExpandedDescendants(TreePath path)
1096: {
1097: Enumeration expanded = tree.getExpandedDescendants(path);
1098: while (expanded.hasMoreElements())
1099: treeState.setExpandedState(((TreePath) expanded.nextElement()), true);
1100: }
1101:
1102:
1109: protected TreePath getLastChildPath(TreePath parent)
1110: {
1111: return ((TreePath) parent.getLastPathComponent());
1112: }
1113:
1114:
1117: protected void updateDepthOffset()
1118: {
1119: depthOffset += getVerticalLegBuffer();
1120: }
1121:
1122:
1127: protected void updateCellEditor()
1128: {
1129: if (tree.isEditable() && cellEditor == null)
1130: setCellEditor(createDefaultCellEditor());
1131: createdCellEditor = true;
1132: }
1133:
1134:
1137: protected void updateRenderer()
1138: {
1139: if (tree != null)
1140: {
1141: if(tree.getCellRenderer() == null)
1142: {
1143: if(currentCellRenderer == null)
1144: currentCellRenderer = createDefaultCellRenderer();
1145: tree.setCellRenderer(currentCellRenderer);
1146: }
1147: }
1148: }
1149:
1150:
1154: protected void configureLayoutCache()
1155: {
1156: treeState = createLayoutCache();
1157: }
1158:
1159:
1163: protected void updateSize()
1164: {
1165: preferredSize = null;
1166: updateCachedPreferredSize();
1167: tree.treeDidChange();
1168: }
1169:
1170:
1174: protected void updateCachedPreferredSize()
1175: {
1176: int maxWidth = 0;
1177: boolean isLeaf = false;
1178: if (currentVisiblePath != null)
1179: {
1180: Object[] path = currentVisiblePath.getPath();
1181: for (int i = 0; i < path.length; i++)
1182: {
1183: TreePath curr = new TreePath(getPathToRoot(path[i], 0));
1184: Rectangle bounds = getPathBounds(tree, curr);
1185:
1186: if (treeModel != null)
1187: isLeaf = treeModel.isLeaf(path[i]);
1188: if (!isLeaf && hasControlIcons())
1189: bounds.width += getCurrentControlIcon(curr).getIconWidth();
1190: maxWidth = Math.max(maxWidth, bounds.x + bounds.width);
1191: }
1192: preferredSize = new Dimension(maxWidth, (getRowHeight() * path.length));
1193: }
1194: else preferredSize = new Dimension(0, 0);
1195: validCachedPreferredSize = true;
1196: }
1197:
1198:
1204: protected void pathWasExpanded(TreePath path)
1205: {
1206: validCachedPreferredSize = false;
1207: tree.revalidate();
1208: tree.repaint();
1209: }
1210:
1211:
1214: protected void pathWasCollapsed(TreePath path)
1215: {
1216: validCachedPreferredSize = false;
1217: tree.revalidate();
1218: tree.repaint();
1219: }
1220:
1221:
1224: protected void installDefaults()
1225: {
1226: LookAndFeel.installColorsAndFont(tree, "Tree.background",
1227: "Tree.foreground", "Tree.font");
1228: tree.setOpaque(true);
1229:
1230: rightChildIndent = UIManager.getInt("Tree.rightChildIndent");
1231: leftChildIndent = UIManager.getInt("Tree.leftChildIndent");
1232: setRowHeight(UIManager.getInt("Tree.rowHeight"));
1233: tree.setRowHeight(UIManager.getInt("Tree.rowHeight"));
1234: tree.requestFocusInWindow(false);
1235: tree.setScrollsOnExpand(UIManager.getBoolean("Tree.scrollsOnExpand"));
1236: setExpandedIcon(UIManager.getIcon("Tree.expandedIcon"));
1237: setCollapsedIcon(UIManager.getIcon("Tree.collapsedIcon"));
1238: }
1239:
1240:
1243: protected void installKeyboardActions()
1244: {
1245: UIDefaults defaults = UIManager.getLookAndFeelDefaults();
1246: InputMap focusInputMap = (InputMap) defaults.get("Tree.focusInputMap");
1247: InputMapUIResource parentInputMap = new InputMapUIResource();
1248: ActionMap parentActionMap = new ActionMap();
1249: action = new TreeAction();
1250: Object keys[] = focusInputMap.allKeys();
1251:
1252: for (int i = 0; i < keys.length; i++)
1253: {
1254: parentInputMap.put(
1255: KeyStroke.getKeyStroke(
1256: ((KeyStroke) keys[i]).getKeyCode(),
1257: convertModifiers(((KeyStroke) keys[i]).getModifiers())),
1258: (String) focusInputMap.get((KeyStroke) keys[i]));
1259:
1260: parentInputMap.put(
1261: KeyStroke.getKeyStroke(
1262: ((KeyStroke) keys[i]).getKeyCode(),
1263: ((KeyStroke) keys[i]).getModifiers()),
1264: (String) focusInputMap.get((KeyStroke) keys[i]));
1265:
1266: parentActionMap.put(
1267: (String) focusInputMap.get((KeyStroke) keys[i]),
1268: new ActionListenerProxy(
1269: action,
1270: (String) focusInputMap.get((KeyStroke) keys[i])));
1271:
1272: }
1273:
1274: parentInputMap.setParent(tree.getInputMap(
1275: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).getParent());
1276: parentActionMap.setParent(tree.getActionMap().getParent());
1277: tree.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).setParent(
1278: parentInputMap);
1279: tree.getActionMap().setParent(parentActionMap);
1280: }
1281:
1282:
1289: private int convertModifiers(int mod)
1290: {
1291: if ((mod & KeyEvent.SHIFT_DOWN_MASK) != 0)
1292: {
1293: mod |= KeyEvent.SHIFT_MASK;
1294: mod &= ~KeyEvent.SHIFT_DOWN_MASK;
1295: }
1296: if ((mod & KeyEvent.CTRL_DOWN_MASK) != 0)
1297: {
1298: mod |= KeyEvent.CTRL_MASK;
1299: mod &= ~KeyEvent.CTRL_DOWN_MASK;
1300: }
1301: if ((mod & KeyEvent.META_DOWN_MASK) != 0)
1302: {
1303: mod |= KeyEvent.META_MASK;
1304: mod &= ~KeyEvent.META_DOWN_MASK;
1305: }
1306: if ((mod & KeyEvent.ALT_DOWN_MASK) != 0)
1307: {
1308: mod |= KeyEvent.ALT_MASK;
1309: mod &= ~KeyEvent.ALT_DOWN_MASK;
1310: }
1311: if ((mod & KeyEvent.ALT_GRAPH_DOWN_MASK) != 0)
1312: {
1313: mod |= KeyEvent.ALT_GRAPH_MASK;
1314: mod &= ~KeyEvent.ALT_GRAPH_DOWN_MASK;
1315: }
1316: return mod;
1317: }
1318:
1319:
1322: protected void installListeners()
1323: {
1324: tree.addPropertyChangeListener(propertyChangeListener);
1325: tree.addFocusListener(focusListener);
1326: tree.addTreeSelectionListener(treeSelectionListener);
1327: tree.addMouseListener(mouseListener);
1328: tree.addKeyListener(keyListener);
1329: tree.addPropertyChangeListener(selectionModelPropertyChangeListener);
1330: tree.addComponentListener(componentListener);
1331: tree.addTreeExpansionListener(treeExpansionListener);
1332: if (treeModel != null)
1333: treeModel.addTreeModelListener(treeModelListener);
1334: }
1335:
1336:
1342: public void installUI(JComponent c)
1343: {
1344: tree = (JTree) c;
1345: prepareForUIInstall();
1346: super.installUI(c);
1347: installDefaults();
1348:
1349: installComponents();
1350: installKeyboardActions();
1351: installListeners();
1352:
1353: setCellEditor(createDefaultCellEditor());
1354: createdCellEditor = true;
1355: isEditing = false;
1356:
1357: TreeModel mod = tree.getModel();
1358: setModel(mod);
1359: if (mod != null)
1360: {
1361: TreePath path = new TreePath(mod.getRoot());
1362: if (!tree.isExpanded(path))
1363: toggleExpandState(path);
1364: }
1365: treeSelectionModel = tree.getSelectionModel();
1366:
1367: completeUIInstall();
1368: }
1369:
1370:
1373: protected void uninstallDefaults()
1374: {
1375: tree.setFont(null);
1376: tree.setForeground(null);
1377: tree.setBackground(null);
1378: }
1379:
1380:
1386: public void uninstallUI(JComponent c)
1387: {
1388: prepareForUIUninstall();
1389: uninstallDefaults();
1390: uninstallKeyboardActions();
1391: uninstallListeners();
1392: tree = null;
1393: uninstallComponents();
1394: completeUIUninstall();
1395: }
1396:
1397:
1410: public void paint(Graphics g, JComponent c)
1411: {
1412: JTree tree = (JTree) c;
1413: if (currentVisiblePath == null)
1414: updateCurrentVisiblePath();
1415:
1416: if (treeModel != null)
1417: {
1418: Object root = treeModel.getRoot();
1419: paintRecursive(g, 0, 0, 0, tree, treeModel, root);
1420:
1421: if (hasControlIcons())
1422: paintControlIcons(g, 0, 0, 0, tree, treeModel, root);
1423: }
1424: }
1425:
1426:
1434: protected void ensureRowsAreVisible(int beginRow, int endRow)
1435: {
1436: if (beginRow < endRow)
1437: {
1438: int temp = endRow;
1439: endRow = beginRow;
1440: beginRow = temp;
1441: }
1442:
1443: for (int i = beginRow; i < endRow; i++)
1444: {
1445: TreePath path = getPathForRow(tree, i);
1446: if (!tree.isVisible(path))
1447: tree.makeVisible(path);
1448: }
1449: }
1450:
1451:
1457: public void setPreferredMinSize(Dimension newSize)
1458: {
1459: preferredMinSize = newSize;
1460: }
1461:
1462:
1467: public Dimension getPreferredMinSize()
1468: {
1469: return preferredMinSize;
1470: }
1471:
1472:
1482: public Dimension getPreferredSize(JComponent c)
1483: {
1484: return getPreferredSize(c, false);
1485: }
1486:
1487:
1497: public Dimension getPreferredSize(JComponent c, boolean checkConsistancy)
1498: {
1499:
1500: if(!validCachedPreferredSize)
1501: updateCachedPreferredSize();
1502: return preferredSize;
1503: }
1504:
1505:
1513: public Dimension getMinimumSize(JComponent c)
1514: {
1515: Dimension min = getPreferredMinSize();
1516: if (min == null)
1517: return new Dimension();
1518: return min;
1519: }
1520:
1521:
1529: public Dimension getMaximumSize(JComponent c)
1530: {
1531: if (c instanceof JTree)
1532: return ((JTree) c).getPreferredSize();
1533: return new Dimension();
1534: }
1535:
1536:
1543: protected void completeEditing()
1544: {
1545: completeEditing(false, true, false);
1546: }
1547:
1548:
1561: protected void completeEditing(boolean messageStop, boolean messageCancel,
1562: boolean messageTree)
1563: {
1564: if (messageStop)
1565: {
1566: getCellEditor().stopCellEditing();
1567: stopEditingInCompleteEditing = true;
1568: }
1569:
1570: if (messageCancel)
1571: {
1572: getCellEditor().cancelCellEditing();
1573: stopEditingInCompleteEditing = true;
1574: }
1575:
1576: if (messageTree)
1577: treeModel.valueForPathChanged(tree.getLeadSelectionPath(), newVal);
1578: }
1579:
1580:
1590: protected boolean startEditing(TreePath path, MouseEvent event)
1591: {
1592: int x;
1593: int y;
1594: if (event == null)
1595: {
1596: bounds = getPathBounds(tree, path);
1597: x = bounds.x;
1598: y = bounds.y;
1599: }
1600: else
1601: {
1602: x = event.getX();
1603: y = event.getY();
1604: }
1605:
1606: updateCellEditor();
1607: TreeCellEditor ed = getCellEditor();
1608: if (ed != null && ed.shouldSelectCell(event) && ed.isCellEditable(event))
1609: {
1610: editingPath = path;
1611: editingRow = tree.getRowForPath(editingPath);
1612:
1613: Object val = editingPath.getLastPathComponent();
1614: cellEditor.addCellEditorListener(cellEditorListener);
1615: stopEditingInCompleteEditing = false;
1616: boolean expanded = tree.isExpanded(editingPath);
1617: isEditing = true;
1618: editingComponent = ed.getTreeCellEditorComponent(tree, val, true,
1619: expanded,
1620: isLeaf(editingRow),
1621: editingRow);
1622: editingComponent.getParent().setVisible(true);
1623: editingComponent.getParent().validate();
1624: tree.add(editingComponent.getParent());
1625: editingComponent.getParent().validate();
1626: validCachedPreferredSize = false;
1627: tree.revalidate();
1628: ((JTextField) editingComponent).requestFocusInWindow(false);
1629: editorTimer.start();
1630: return true;
1631: }
1632: return false;
1633: }
1634:
1635:
1646: protected void checkForClickInExpandControl(TreePath path, int mouseX,
1647: int mouseY)
1648: {
1649: if (isLocationInExpandControl(path, mouseX, mouseY))
1650: toggleExpandState(path);
1651: }
1652:
1653:
1668: protected boolean isLocationInExpandControl(TreePath path, int mouseX,
1669: int mouseY)
1670: {
1671: boolean cntlClick = false;
1672: int row = getRowForPath(tree, path);
1673:
1674: if (!isLeaf(row))
1675: {
1676: bounds = getPathBounds(tree, path);
1677:
1678: if (hasControlIcons() && (mouseX < bounds.x)
1679: && (mouseX > (bounds.x - getCurrentControlIcon(path).getIconWidth() - gap)))
1680: cntlClick = true;
1681: }
1682: return cntlClick;
1683: }
1684:
1685:
1696: protected void handleExpandControlClick(TreePath path, int mouseX, int mouseY)
1697: {
1698: toggleExpandState(path);
1699: }
1700:
1701:
1710: protected void toggleExpandState(TreePath path)
1711: {
1712: if (tree.isExpanded(path))
1713: tree.collapsePath(path);
1714: else
1715: tree.expandPath(path);
1716: updateCurrentVisiblePath();
1717: }
1718:
1719:
1728: protected boolean isToggleSelectionEvent(MouseEvent event)
1729: {
1730: return (tree.getSelectionModel().getSelectionMode() ==
1731: TreeSelectionModel.SINGLE_TREE_SELECTION);
1732: }
1733:
1734:
1743: protected boolean isMultiSelectEvent(MouseEvent event)
1744: {
1745: return (tree.getSelectionModel().getSelectionMode() ==
1746: TreeSelectionModel.CONTIGUOUS_TREE_SELECTION);
1747: }
1748:
1749:
1759: protected boolean isToggleEvent(MouseEvent event)
1760: {
1761: return true;
1762: }
1763:
1764:
1776: protected void selectPathForEvent(TreePath path, MouseEvent event)
1777: {
1778: if (isToggleSelectionEvent(event))
1779: {
1780: if (tree.isPathSelected(path))
1781: tree.removeSelectionPath(path);
1782: else
1783: {
1784: tree.addSelectionPath(path);
1785: tree.setAnchorSelectionPath(path);
1786: }
1787: }
1788: else if (isMultiSelectEvent(event))
1789: {
1790: TreePath anchor = tree.getAnchorSelectionPath();
1791: if (anchor != null)
1792: {
1793: int aRow = getRowForPath(tree, anchor);
1794: tree.addSelectionInterval(aRow, getRowForPath(tree, path));
1795: }
1796: else
1797: tree.addSelectionPath(path);
1798: }
1799: else
1800: tree.addSelectionPath(path);
1801: }
1802:
1803:
1810: protected boolean isLeaf(int row)
1811: {
1812: TreePath pathForRow = getPathForRow(tree, row);
1813: if (pathForRow == null)
1814: return true;
1815:
1816: Object node = pathForRow.getLastPathComponent();
1817: return treeModel.isLeaf(node);
1818: }
1819:
1820:
1825: class TreeAction
1826: extends AbstractAction
1827: {
1828:
1829:
1835: public void actionPerformed(ActionEvent e)
1836: {
1837: TreePath lead = tree.getLeadSelectionPath();
1838:
1839: if (e.getActionCommand().equals("selectPreviousChangeLead")
1840: || e.getActionCommand().equals("selectPreviousExtendSelection")
1841: || e.getActionCommand().equals("selectPrevious")
1842: || e.getActionCommand().equals("selectNext")
1843: || e.getActionCommand().equals("selectNextExtendSelection")
1844: || e.getActionCommand().equals("selectNextChangeLead"))
1845: (new TreeIncrementAction(0, "")).actionPerformed(e);
1846: else if (e.getActionCommand().equals("selectParent")
1847: || e.getActionCommand().equals("selectChild"))
1848: (new TreeTraverseAction(0, "")).actionPerformed(e);
1849: else if (e.getActionCommand().equals("selectAll"))
1850: {
1851: TreePath[] paths = new TreePath[tree.getVisibleRowCount()];
1852:
1853: Object curr = getNextVisibleNode(treeModel.getRoot());
1854: int i = 0;
1855: while (curr != null && i < paths.length)
1856: {
1857: paths[i] = new TreePath(getPathToRoot(curr, 0));
1858: i++;
1859: }
1860:
1861: tree.addSelectionPaths(paths);
1862: }
1863: else if (e.getActionCommand().equals("startEditing"))
1864: tree.startEditingAtPath(lead);
1865: else if (e.getActionCommand().equals("toggle"))
1866: {
1867: if (tree.isEditing())
1868: tree.stopEditing();
1869: else
1870: {
1871: Object last = lead.getLastPathComponent();
1872: TreePath path = new TreePath(getPathToRoot(last, 0));
1873: if (!treeModel.isLeaf(last))
1874: toggleExpandState(path);
1875: }
1876: }
1877: else if (e.getActionCommand().equals("clearSelection"))
1878: tree.clearSelection();
1879:
1880: if (tree.isEditing() && !e.getActionCommand().equals("startEditing"))
1881: tree.cancelEditing();
1882:
1883: tree.scrollPathToVisible(lead);
1884: }
1885: }
1886:
1887:
1894: private static class ActionListenerProxy
1895: extends AbstractAction
1896: {
1897: ActionListener target;
1898:
1899: String bindingCommandName;
1900:
1901: public ActionListenerProxy(ActionListener li, String cmd)
1902: {
1903: target = li;
1904: bindingCommandName = cmd;
1905: }
1906:
1907: public void actionPerformed(ActionEvent e)
1908: {
1909: ActionEvent derivedEvent = new ActionEvent(e.getSource(), e.getID(),
1910: bindingCommandName,
1911: e.getModifiers());
1912:
1913: target.actionPerformed(derivedEvent);
1914: }
1915: }
1916:
1917:
1920: private class EditorUpdateTimer
1921: extends Timer
1922: implements ActionListener
1923: {
1924:
1928: public EditorUpdateTimer()
1929: {
1930: super(300, null);
1931: addActionListener(this);
1932: }
1933:
1934:
1937: public void actionPerformed(ActionEvent ev)
1938: {
1939: Caret c = ((JTextField) editingComponent).getCaret();
1940: if (c != null)
1941: c.setVisible(!c.isVisible());
1942: tree.repaint();
1943: }
1944:
1945:
1948: public void update()
1949: {
1950: stop();
1951: Caret c = ((JTextField) editingComponent).getCaret();
1952: if (c != null)
1953: {
1954: setDelay(c.getBlinkRate());
1955: if (((JTextField) editingComponent).isEditable())
1956: start();
1957: else
1958: c.setVisible(false);
1959: }
1960: }
1961: }
1962:
1963:
1966: public class ComponentHandler extends ComponentAdapter
1967: implements ActionListener
1968: {
1969:
1972: protected Timer timer;
1973:
1974:
1975: protected JScrollBar scrollBar;
1976:
1977:
1980: public ComponentHandler()
1981: {
1982:
1983: }
1984:
1985:
1991: public void componentMoved(ComponentEvent e)
1992: {
1993:
1994: }
1995:
1996:
2000: protected void startTimer()
2001: {
2002:
2003: }
2004:
2005:
2010: protected JScrollPane getScrollPane()
2011: {
2012: return null;
2013: }
2014:
2015:
2022: public void actionPerformed(ActionEvent ae)
2023: {
2024:
2025: }
2026: }
2027:
2028:
2032: public class CellEditorHandler implements CellEditorListener
2033: {
2034:
2037: public CellEditorHandler()
2038: {
2039:
2040: }
2041:
2042:
2049: public void editingStopped(ChangeEvent e)
2050: {
2051: editingPath = null;
2052: editingRow = -1;
2053: stopEditingInCompleteEditing = false;
2054: if (editingComponent != null)
2055: {
2056: tree.remove(editingComponent.getParent());
2057: editingComponent = null;
2058: }
2059: if (cellEditor != null)
2060: {
2061: newVal = ((JTextField) getCellEditor().getCellEditorValue()).getText();
2062: completeEditing(false, false, true);
2063: if (cellEditor instanceof DefaultTreeCellEditor)
2064: tree.removeTreeSelectionListener((DefaultTreeCellEditor) cellEditor);
2065: cellEditor.removeCellEditorListener(cellEditorListener);
2066: setCellEditor(null);
2067: createdCellEditor = false;
2068: }
2069: isEditing = false;
2070: tree.requestFocusInWindow(false);
2071: editorTimer.stop();
2072: validCachedPreferredSize = false;
2073: tree.revalidate();
2074: tree.repaint();
2075: }
2076:
2077:
2084: public void editingCanceled(ChangeEvent e)
2085: {
2086: editingPath = null;
2087: editingRow = -1;
2088: stopEditingInCompleteEditing = false;
2089: if (editingComponent != null)
2090: tree.remove(editingComponent.getParent());
2091: editingComponent = null;
2092: if (cellEditor != null)
2093: {
2094: if (cellEditor instanceof DefaultTreeCellEditor)
2095: tree.removeTreeSelectionListener((DefaultTreeCellEditor) cellEditor);
2096: cellEditor.removeCellEditorListener(cellEditorListener);
2097: setCellEditor(null);
2098: createdCellEditor = false;
2099: }
2100: tree.requestFocusInWindow(false);
2101: editorTimer.stop();
2102: isEditing = false;
2103: validCachedPreferredSize = false;
2104: tree.revalidate();
2105: tree.repaint();
2106: }
2107: }
2108:
2109:
2112: public class FocusHandler
2113: implements FocusListener
2114: {
2115:
2118: public FocusHandler()
2119: {
2120:
2121: }
2122:
2123:
2130: public void focusGained(FocusEvent e)
2131: {
2132:
2133: }
2134:
2135:
2142: public void focusLost(FocusEvent e)
2143: {
2144:
2145: }
2146: }
2147:
2148:
2152: public class KeyHandler
2153: extends KeyAdapter
2154: {
2155:
2156: protected Action repeatKeyAction;
2157:
2158:
2159: protected boolean isKeyDown;
2160:
2161:
2164: public KeyHandler()
2165: {
2166:
2167: }
2168:
2169:
2178: public void keyTyped(KeyEvent e)
2179: {
2180:
2181: }
2182:
2183:
2189: public void keyPressed(KeyEvent e)
2190: {
2191:
2192: }
2193:
2194:
2200: public void keyReleased(KeyEvent e)
2201: {
2202:
2203: }
2204: }
2205:
2206:
2210: public class MouseHandler extends MouseAdapter implements MouseMotionListener
2211: {
2212:
2215: public MouseHandler()
2216: {
2217:
2218: }
2219:
2220:
2226: public void mousePressed(MouseEvent e)
2227: {
2228: Point click = e.getPoint();
2229: TreePath path = getClosestPathForLocation(tree, click.x, click.y);
2230:
2231: if (path != null)
2232: {
2233: bounds = getPathBounds(tree, path);
2234: int row = getRowForPath(tree, path);
2235: boolean cntlClick = isLocationInExpandControl(path, click.x, click.y);
2236:
2237: boolean isLeaf = isLeaf(row);
2238:
2239: TreeCellRenderer tcr = getCellRenderer();
2240: Icon icon;
2241: if (isLeaf)
2242: icon = UIManager.getIcon("Tree.leafIcon");
2243: else if (tree.isExpanded(path))
2244: icon = UIManager.getIcon("Tree.openIcon");
2245: else
2246: icon = UIManager.getIcon("Tree.closedIcon");
2247:
2248: if (tcr instanceof DefaultTreeCellRenderer)
2249: {
2250: Icon tmp = ((DefaultTreeCellRenderer) tcr).getIcon();
2251: if (tmp != null)
2252: icon = tmp;
2253: }
2254:
2255:
2256: if (icon != null)
2257: bounds.width += icon.getIconWidth() + gap*2;
2258:
2259: boolean inBounds = bounds.contains(click.x, click.y);
2260: if ((inBounds || cntlClick) && tree.isVisible(path))
2261: {
2262: selectPath(tree, path);
2263: if (inBounds && e.getClickCount() == 2 && !isLeaf(row))
2264: toggleExpandState(path);
2265:
2266: if (cntlClick)
2267: {
2268: handleExpandControlClick(path, click.x, click.y);
2269: if (cellEditor != null)
2270: cellEditor.cancelCellEditing();
2271: }
2272: else if (tree.isEditable())
2273: startEditing(path, e);
2274: }
2275: }
2276: }
2277:
2278:
2287: public void mouseDragged(MouseEvent e)
2288: {
2289:
2290: }
2291:
2292:
2299: public void mouseMoved(MouseEvent e)
2300: {
2301:
2302: }
2303:
2304:
2310: public void mouseReleased(MouseEvent e)
2311: {
2312:
2313: }
2314: }
2315:
2316:
2321: public class MouseInputHandler implements MouseInputListener
2322: {
2323:
2324: protected Component source;
2325:
2326:
2327: protected Component destination;
2328:
2329:
2339: public MouseInputHandler(Component source, Component destination,
2340: MouseEvent e)
2341: {
2342: this.source = source;
2343: this.destination = destination;
2344: }
2345:
2346:
2353: public void mouseClicked(MouseEvent e)
2354: {
2355:
2356: }
2357:
2358:
2364: public void mousePressed(MouseEvent e)
2365: {
2366:
2367: }
2368:
2369:
2375: public void mouseReleased(MouseEvent e)
2376: {
2377:
2378: }
2379:
2380:
2386: public void mouseEntered(MouseEvent e)
2387: {
2388:
2389: }
2390:
2391:
2397: public void mouseExited(MouseEvent e)
2398: {
2399:
2400: }
2401:
2402:
2411: public void mouseDragged(MouseEvent e)
2412: {
2413:
2414: }
2415:
2416:
2423: public void mouseMoved(MouseEvent e)
2424: {
2425:
2426: }
2427:
2428:
2431: protected void removeFromSource()
2432: {
2433:
2434: }
2435: }
2436:
2437:
2442: public class NodeDimensionsHandler
2443: extends AbstractLayoutCache.NodeDimensions
2444: {
2445:
2448: public NodeDimensionsHandler()
2449: {
2450:
2451: }
2452:
2453:
2468: public Rectangle getNodeDimensions(Object value, int row, int depth,
2469: boolean expanded, Rectangle size)
2470: {
2471: return null;
2472: }
2473:
2474:
2479: protected int getRowX(int row, int depth)
2480: {
2481: return 0;
2482: }
2483: }
2484:
2485:
2489: public class PropertyChangeHandler
2490: implements PropertyChangeListener
2491: {
2492:
2493:
2496: public PropertyChangeHandler()
2497: {
2498:
2499: }
2500:
2501:
2508: public void propertyChange(PropertyChangeEvent event)
2509: {
2510:
2511: }
2512: }
2513:
2514:
2518: public class SelectionModelPropertyChangeHandler
2519: implements PropertyChangeListener
2520: {
2521:
2522:
2525: public SelectionModelPropertyChangeHandler()
2526: {
2527:
2528: }
2529:
2530:
2537: public void propertyChange(PropertyChangeEvent event)
2538: {
2539:
2540: }
2541: }
2542:
2543:
2546: public class TreeCancelEditingAction
2547: extends AbstractAction
2548: {
2549:
2550:
2553: public TreeCancelEditingAction(String name)
2554: {
2555:
2556: }
2557:
2558:
2564: public void actionPerformed(ActionEvent e)
2565: {
2566:
2567: }
2568:
2569:
2574: public boolean isEnabled()
2575: {
2576:
2577: return false;
2578: }
2579: }
2580:
2581:
2584: public class TreeExpansionHandler
2585: implements TreeExpansionListener
2586: {
2587:
2588:
2591: public TreeExpansionHandler()
2592: {
2593:
2594: }
2595:
2596:
2602: public void treeExpanded(TreeExpansionEvent event)
2603: {
2604: validCachedPreferredSize = false;
2605: updateCurrentVisiblePath();
2606: tree.revalidate();
2607: tree.repaint();
2608: }
2609:
2610:
2616: public void treeCollapsed(TreeExpansionEvent event)
2617: {
2618: validCachedPreferredSize = false;
2619: updateCurrentVisiblePath();
2620: tree.revalidate();
2621: tree.repaint();
2622: }
2623: }
2624:
2625:
2629: public class TreeHomeAction
2630: extends AbstractAction
2631: {
2632:
2633:
2634: protected int direction;
2635:
2636:
2644: public TreeHomeAction(int direction, String name)
2645: {
2646:
2647: }
2648:
2649:
2655: public void actionPerformed(ActionEvent e)
2656: {
2657:
2658: }
2659:
2660:
2665: public boolean isEnabled()
2666: {
2667:
2668: return false;
2669: }
2670: }
2671:
2672:
2676: public class TreeIncrementAction
2677: extends AbstractAction
2678: {
2679:
2680:
2681: protected int direction;
2682:
2683:
2691: public TreeIncrementAction(int direction, String name)
2692: {
2693:
2694: }
2695:
2696:
2702: public void actionPerformed(ActionEvent e)
2703: {
2704: Object last = tree.getLeadSelectionPath().getLastPathComponent();
2705:
2706: if (e.getActionCommand().equals("selectPreviousChangeLead"))
2707: {
2708: Object prev = getPreviousVisibleNode(last);
2709:
2710: if (prev != null)
2711: {
2712: TreePath newPath = new TreePath(getPathToRoot(prev, 0));
2713: selectPath(tree, newPath);
2714: tree.setLeadSelectionPath(newPath);
2715: }
2716: }
2717: else if (e.getActionCommand().equals("selectPreviousExtendSelection"))
2718: {
2719: Object prev = getPreviousVisibleNode(last);
2720: if (prev != null)
2721: {
2722: TreePath newPath = new TreePath(getPathToRoot(prev, 0));
2723: tree.addSelectionPath(newPath);
2724: tree.setLeadSelectionPath(newPath);
2725: }
2726: }
2727: else if (e.getActionCommand().equals("selectPrevious"))
2728: {
2729: Object prev = getPreviousVisibleNode(last);
2730: if (prev != null)
2731: {
2732: TreePath newPath = new TreePath(getPathToRoot(prev, 0));
2733: selectPath(tree, newPath);
2734: }
2735: }
2736: else if (e.getActionCommand().equals("selectNext"))
2737: {
2738: Object next = getNextVisibleNode(last);
2739: if (next != null)
2740: {
2741: TreePath newPath = new TreePath(getPathToRoot(next, 0));
2742: selectPath(tree, newPath);
2743: }
2744: }
2745: else if (e.getActionCommand().equals("selectNextExtendSelection"))
2746: {
2747: Object next = getNextVisibleNode(last);
2748: if (next != null)
2749: {
2750: TreePath newPath = new TreePath(getPathToRoot(next, 0));
2751: tree.addSelectionPath(newPath);
2752: tree.setLeadSelectionPath(newPath);
2753: }
2754: }
2755: else if (e.getActionCommand().equals("selectNextChangeLead"))
2756: {
2757: Object next = getNextVisibleNode(last);
2758: if (next != null)
2759: {
2760: TreePath newPath = new TreePath(getPathToRoot(next, 0));
2761: selectPath(tree, newPath);
2762: tree.setLeadSelectionPath(newPath);
2763: }
2764: }
2765: }
2766:
2767:
2772: public boolean isEnabled()
2773: {
2774:
2775: return false;
2776: }
2777: }
2778:
2779:
2782: public class TreeModelHandler implements TreeModelListener
2783: {
2784:
2787: public TreeModelHandler()
2788: {
2789:
2790: }
2791:
2792:
2805: public void treeNodesChanged(TreeModelEvent e)
2806: {
2807: validCachedPreferredSize = false;
2808: updateCurrentVisiblePath();
2809: tree.revalidate();
2810: tree.repaint();
2811: }
2812:
2813:
2821: public void treeNodesInserted(TreeModelEvent e)
2822: {
2823: validCachedPreferredSize = false;
2824: updateCurrentVisiblePath();
2825: tree.revalidate();
2826: tree.repaint();
2827: }
2828:
2829:
2840: public void treeNodesRemoved(TreeModelEvent e)
2841: {
2842: validCachedPreferredSize = false;
2843: updateCurrentVisiblePath();
2844: tree.revalidate();
2845: tree.repaint();
2846: }
2847:
2848:
2858: public void treeStructureChanged(TreeModelEvent e)
2859: {
2860: validCachedPreferredSize = false;
2861: updateCurrentVisiblePath();
2862: tree.revalidate();
2863: tree.repaint();
2864: }
2865: }
2866:
2867:
2870: public class TreePageAction extends AbstractAction
2871: {
2872:
2873: protected int direction;
2874:
2875:
2883: public TreePageAction(int direction, String name)
2884: {
2885: this.direction = direction;
2886: }
2887:
2888:
2894: public void actionPerformed(ActionEvent e)
2895: {
2896:
2897: }
2898:
2899:
2904: public boolean isEnabled()
2905: {
2906: return false;
2907: }
2908: }
2909:
2910:
2914: public class TreeSelectionHandler implements TreeSelectionListener
2915: {
2916:
2919: public TreeSelectionHandler()
2920: {
2921:
2922: }
2923:
2924:
2931: public void valueChanged(TreeSelectionEvent event)
2932: {
2933: if (tree.isEditing())
2934: tree.cancelEditing();
2935: }
2936: }
2937:
2938:
2941: public class TreeToggleAction extends AbstractAction
2942: {
2943:
2949: public TreeToggleAction(String name)
2950: {
2951:
2952: }
2953:
2954:
2960: public void actionPerformed(ActionEvent e)
2961: {
2962:
2963: }
2964:
2965:
2970: public boolean isEnabled()
2971: {
2972: return false;
2973: }
2974: }
2975:
2976:
2980: public class TreeTraverseAction extends AbstractAction
2981: {
2982:
2985: protected int direction;
2986:
2987:
2995: public TreeTraverseAction(int direction, String name)
2996: {
2997: this.direction = direction;
2998: }
2999:
3000:
3006: public void actionPerformed(ActionEvent e)
3007: {
3008: Object last = tree.getLeadSelectionPath().getLastPathComponent();
3009:
3010: if (e.getActionCommand().equals("selectParent"))
3011: {
3012: TreePath path = new TreePath(getPathToRoot(last, 0));
3013: Object p = getParent(treeModel.getRoot(), last);
3014:
3015: if (!treeModel.isLeaf(last))
3016: toggleExpandState(path);
3017: else if (p != null)
3018: selectPath(tree, new TreePath(getPathToRoot(p, 0)));
3019: }
3020: else if (e.getActionCommand().equals("selectChild"))
3021: {
3022: TreePath path = new TreePath(getPathToRoot(last, 0));
3023:
3024: if (!treeModel.isLeaf(last))
3025: toggleExpandState(path);
3026: else
3027: {
3028: Object next = getNextVisibleNode(last);
3029:
3030: if (next != null)
3031: selectPath(tree, new TreePath(getPathToRoot(next, 0)));
3032: }
3033: }
3034: }
3035:
3036:
3041: public boolean isEnabled()
3042: {
3043:
3044: return false;
3045: }
3046: }
3047:
3048:
3060: Rectangle getCellBounds(int x, int y, Object cell)
3061: {
3062: if (cell != null)
3063: {
3064: String s = cell.toString();
3065: Font f = tree.getFont();
3066: FontMetrics fm = tree.getToolkit().getFontMetrics(f);
3067:
3068: if (s != null)
3069: return new Rectangle(x, y, SwingUtilities.computeStringWidth(fm, s),
3070: fm.getHeight());
3071: }
3072: return new Rectangle(x, y, 0, 0);
3073: }
3074:
3075:
3093: Point getCellLocation(int x, int y, JTree tree, TreeModel mod, Object node,
3094: Object startNode)
3095: {
3096: int rowHeight = getRowHeight();
3097: if (startNode == null || startNode.equals(node))
3098: {
3099: int level = getLevel(node);
3100: if (level == 0)
3101: return new Point(x, y);
3102: if (!tree.isRootVisible() &&
3103: tree.isExpanded(new TreePath(mod.getRoot())))
3104: return new Point(x + ((level - 1) * rightChildIndent), y);
3105: return new Point(x + (level * rightChildIndent), y);
3106: }
3107: return getCellLocation(x, y + rowHeight, tree, mod, node,
3108: getNextVisibleNode(startNode));
3109: }
3110:
3111:
3131: int paintRecursive(Graphics g, int indentation, int descent,
3132: int depth, JTree tree, TreeModel mod, Object curr)
3133: {
3134: Rectangle clip = tree.getVisibleRect();
3135: if (indentation > clip.x + clip.width + rightChildIndent
3136: || descent > clip.y + clip.height + getRowHeight())
3137: return descent;
3138:
3139: TreePath path = new TreePath(getPathToRoot(curr, 0));
3140: int halfHeight = getRowHeight() / 2;
3141: int halfWidth = rightChildIndent / 2;
3142: int y0 = descent + halfHeight;
3143: int heightOfLine = descent + halfHeight;
3144: int row = getRowForPath(tree, path);
3145: boolean isRootVisible = tree.isRootVisible();
3146: boolean isExpanded = tree.isExpanded(path);
3147: boolean isLeaf = mod.isLeaf(curr);
3148: Rectangle bounds = getPathBounds(tree, path);
3149: Object root = mod.getRoot();
3150:
3151: if (isLeaf)
3152: {
3153: paintRow(g, clip, null, bounds, path, row, true, false, true);
3154: descent += getRowHeight();
3155: }
3156: else
3157: {
3158: if (depth > 0 || isRootVisible)
3159: {
3160: paintRow(g, clip, null, bounds, path, row, isExpanded, false, false);
3161: descent += getRowHeight();
3162: y0 += halfHeight;
3163: }
3164:
3165: int max = mod.getChildCount(curr);
3166: if (isExpanded)
3167: {
3168: for (int i = 0; i < max; i++)
3169: {
3170: int indent = indentation + rightChildIndent;
3171: if (!isRootVisible && depth == 0)
3172: indent = 0;
3173: else if (isRootVisible ||
3174: (!isRootVisible && !curr.equals(root)))
3175: {
3176: g.setColor(getHashColor());
3177: heightOfLine = descent + halfHeight;
3178: paintHorizontalLine(g, (JComponent) tree, heightOfLine,
3179: indentation + halfWidth, indentation + rightChildIndent);
3180: }
3181:
3182: descent = paintRecursive(g, indent, descent, depth + 1,
3183: tree, mod, mod.getChild(curr, i));
3184: }
3185: }
3186: }
3187:
3188: if (isExpanded)
3189: if (y0 != heightOfLine && !isLeaf
3190: && mod.getChildCount(curr) > 0)
3191: {
3192: g.setColor(getHashColor());
3193: paintVerticalLine(g, (JComponent) tree, indentation + halfWidth,
3194: y0, heightOfLine);
3195: }
3196:
3197: return descent;
3198: }
3199:
3200:
3220: int paintControlIcons(Graphics g, int indentation, int descent,
3221: int depth, JTree tree, TreeModel mod,
3222: Object node)
3223: {
3224: int rowHeight = getRowHeight();
3225: TreePath path = new TreePath(getPathToRoot(node, 0));
3226: Icon icon = getCurrentControlIcon(path);
3227:
3228: Rectangle clip = tree.getVisibleRect();
3229: if (indentation > clip.x + clip.width + rightChildIndent
3230: || descent > clip.y + clip.height + getRowHeight())
3231: return descent;
3232:
3233: if (mod.isLeaf(node))
3234: descent += rowHeight;
3235: else
3236: {
3237: if (!node.equals(mod.getRoot()) &&
3238: (tree.isRootVisible() || getLevel(node) != 1))
3239: {
3240: int width = icon.getIconWidth();
3241: int height = icon.getIconHeight() + 2;
3242: int posX = indentation - rightChildIndent;
3243: int posY = descent;
3244: if (width > rightChildIndent)
3245: posX -= gap;
3246: else posX += width/2;
3247:
3248: if (height < rowHeight)
3249: posY += height/2;
3250:
3251: icon.paintIcon(tree, g, posX, posY);
3252: }
3253:
3254: if (depth > 0 || tree.isRootVisible())
3255: descent += rowHeight;
3256:
3257: if (tree.isExpanded(path))
3258: {
3259: int max = 0;
3260: if (!mod.isLeaf(node))
3261: max = mod.getChildCount(node);
3262:
3263: for (int i = 0; i < max; i++)
3264: {
3265: int indent = indentation + rightChildIndent;
3266: if (depth == 0 && !tree.isRootVisible())
3267: indent = 1;
3268:
3269: descent = paintControlIcons(g, indent, descent, depth + 1,
3270: tree, mod, mod.getChild(node, i));
3271: }
3272: }
3273: }
3274:
3275: return descent;
3276: }
3277:
3278:
3284: boolean hasControlIcons()
3285: {
3286: if (expandedIcon != null || collapsedIcon != null)
3287: return true;
3288: return false;
3289: }
3290:
3291:
3297: Icon getCurrentControlIcon(TreePath path)
3298: {
3299: if (tree.isExpanded(path))
3300: return expandedIcon;
3301: return collapsedIcon;
3302: }
3303:
3304:
3313: Object getParent(Object root, Object node)
3314: {
3315: if (root == null || node == null)
3316: return null;
3317: if (node instanceof TreeNode)
3318: return ((TreeNode) node).getParent();
3319: return findNode(root, node);
3320: }
3321:
3322:
3331: private Object findNode(Object root, Object node)
3332: {
3333: int size = 0;
3334: if (!treeModel.isLeaf(root))
3335: size = treeModel.getChildCount(root);
3336: for (int i = 0; i < size; i++)
3337: {
3338: if (treeModel.getIndexOfChild(root, node) != -1)
3339: return root;
3340:
3341: Object n = findNode(treeModel.getChild(root, i), node);
3342: if (n != null)
3343: return n;
3344: }
3345: return null;
3346: }
3347:
3348:
3357: Object getPreviousVisibleNode(Object node)
3358: {
3359: if (currentVisiblePath != null)
3360: {
3361: Object[] nodes = currentVisiblePath.getPath();
3362: int i = 0;
3363: while (i < nodes.length && !node.equals(nodes[i]))
3364: i++;
3365:
3366: if (i-1 > 0)
3367: return nodes[i-1];
3368: }
3369: return null;
3370: }
3371:
3372:
3379: Object getNextNode(Object curr)
3380: {
3381: if (!treeModel.isLeaf(curr) && treeModel.getChildCount(curr) > 0)
3382: return treeModel.getChild(curr, 0);
3383:
3384: Object node = curr;
3385: Object sibling = null;
3386:
3387: do
3388: {
3389: sibling = getNextSibling(node);
3390: node = getParent(treeModel.getRoot(), node);
3391: }
3392: while (sibling == null && node != null);
3393:
3394: return sibling;
3395: }
3396:
3397:
3405: Object getPreviousNode(Object node)
3406: {
3407: Object parent = getParent(treeModel.getRoot(), node);
3408: if (parent == null)
3409: return null;
3410:
3411: Object sibling = getPreviousSibling(node);
3412:
3413: if (sibling == null)
3414: return parent;
3415:
3416: int size = 0;
3417: if (!treeModel.isLeaf(sibling))
3418: size = treeModel.getChildCount(sibling);
3419: while (size > 0)
3420: {
3421: sibling = treeModel.getChild(sibling, size - 1);
3422: if (!treeModel.isLeaf(sibling))
3423: size = treeModel.getChildCount(sibling);
3424: else
3425: size = 0;
3426: }
3427:
3428: return sibling;
3429: }
3430:
3431:
3439: Object getNextSibling(Object node)
3440: {
3441: Object parent = getParent(treeModel.getRoot(), node);
3442: if (parent == null)
3443: return null;
3444:
3445: int index = treeModel.getIndexOfChild(parent, node) + 1;
3446:
3447: int size = 0;
3448: if (!treeModel.isLeaf(parent))
3449: size = treeModel.getChildCount(parent);
3450: if (index == 0 || index >= size)
3451: return null;
3452:
3453: return treeModel.getChild(parent, index);
3454: }
3455:
3456:
3464: Object getPreviousSibling(Object node)
3465: {
3466: Object parent = getParent(treeModel.getRoot(), node);
3467: if (parent == null)
3468: return null;
3469:
3470: int index = treeModel.getIndexOfChild(parent, node) - 1;
3471:
3472: int size = 0;
3473: if (!treeModel.isLeaf(parent))
3474: size = treeModel.getChildCount(parent);
3475: if (index < 0 || index >= size)
3476: return null;
3477:
3478: return treeModel.getChild(parent, index);
3479: }
3480:
3481:
3490: void selectPath(JTree tree, TreePath path)
3491: {
3492: if (path != null)
3493: {
3494: if (tree.getSelectionModel().getSelectionMode() ==
3495: TreeSelectionModel.SINGLE_TREE_SELECTION)
3496: {
3497: tree.getSelectionModel().clearSelection();
3498: tree.addSelectionPath(path);
3499: tree.setLeadSelectionPath(path);
3500: }
3501: else if (tree.getSelectionModel().getSelectionMode() ==
3502: TreeSelectionModel.CONTIGUOUS_TREE_SELECTION)
3503: {
3504:
3505: }
3506: else
3507: {
3508: tree.addSelectionPath(path);
3509: tree.setLeadSelectionPath(path);
3510: tree.getSelectionModel().setSelectionMode
3511: (TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
3512: }
3513: }
3514: }
3515:
3516:
3526: Object[] getPathToRoot(Object node, int depth)
3527: {
3528: if (node == null)
3529: {
3530: if (depth == 0)
3531: return null;
3532:
3533: return new Object[depth];
3534: }
3535:
3536: Object[] path = getPathToRoot(getParent(treeModel.getRoot(), node), depth + 1);
3537: path[path.length - depth - 1] = node;
3538: return path;
3539: }
3540:
3541:
3548: int getLevel(Object node)
3549: {
3550: int count = -1;
3551: Object current = node;
3552:
3553: do
3554: {
3555: current = getParent(treeModel.getRoot(), current);
3556: count++;
3557: }
3558: while (current != null);
3559:
3560: return count;
3561: }
3562:
3563:
3577: protected void paintVerticalLine(Graphics g, JComponent c, int x, int top,
3578: int bottom)
3579: {
3580: g.drawLine(x, top, x, bottom);
3581: }
3582:
3583:
3597: protected void paintHorizontalLine(Graphics g, JComponent c, int y, int left,
3598: int right)
3599: {
3600: g.drawLine(left, y, right, y);
3601: }
3602:
3603:
3618: protected void drawCentered(Component c, Graphics g, Icon icon, int x, int y)
3619: {
3620: int beginPositionX = x - icon.getIconWidth() / 2;
3621: int beginPositionY = y - icon.getIconHeight() / 2;
3622: icon.paintIcon(c, g, beginPositionX, beginPositionY);
3623: }
3624:
3625:
3633: protected void drawDashedHorizontalLine(Graphics g, int y, int x1, int x2)
3634: {
3635: for (int i = x1; i < x2; i += 2)
3636: g.drawLine(i, y, i + 1, y);
3637: }
3638:
3639:
3647: protected void drawDashedVerticalLine(Graphics g, int x, int y1, int y2)
3648: {
3649: for (int i = y1; i < y2; i += 2)
3650: g.drawLine(x, i, x, i + 1);
3651: }
3652:
3653:
3667: protected void paintExpandControl(Graphics g, Rectangle clipBounds,
3668: Insets insets, Rectangle bounds,
3669: TreePath path, int row,
3670: boolean isExpanded, boolean hasBeenExpanded,
3671: boolean isLeaf)
3672: {
3673: if (treeModel != null && hasControlIcons())
3674: paintControlIcons(g, 0, 0, 0, tree, treeModel, path.getLastPathComponent());
3675: }
3676:
3677:
3692: protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds,
3693: Insets insets, Rectangle bounds,
3694: TreePath path, int row,
3695: boolean isExpanded, boolean hasBeenExpanded,
3696: boolean isLeaf)
3697: {
3698:
3699: }
3700:
3701:
3710: protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds,
3711: Insets insets, TreePath path)
3712: {
3713:
3714: }
3715:
3716:
3730: protected void paintRow(Graphics g, Rectangle clipBounds,
3731: Insets insets, Rectangle bounds,
3732: TreePath path, int row,
3733: boolean isExpanded, boolean hasBeenExpanded,
3734: boolean isLeaf)
3735: {
3736: boolean selected = tree.isPathSelected(path);
3737: boolean hasIcons = false;
3738: Object node = path.getLastPathComponent();
3739:
3740: if (tree.isVisible(path))
3741: {
3742: bounds.width = preferredSize.width;
3743: bounds.x += gap;
3744:
3745: if (editingComponent != null && editingPath != null && isEditing(tree)
3746: && node.equals(editingPath.getLastPathComponent()))
3747: {
3748: rendererPane.paintComponent(g, editingComponent.getParent(), null,
3749: bounds);
3750: }
3751: else
3752: {
3753: TreeCellRenderer dtcr = tree.getCellRenderer();
3754: if (dtcr == null)
3755: dtcr = createDefaultCellRenderer();
3756:
3757: Component c = dtcr.getTreeCellRendererComponent(tree, node,
3758: selected, isExpanded, isLeaf, row, false);
3759: rendererPane.paintComponent(g, c, c.getParent(), bounds);
3760: }
3761: }
3762: }
3763:
3764:
3767: protected void prepareForUIUninstall()
3768: {
3769:
3770: }
3771:
3772:
3782: protected boolean shouldPaintExpandControl(TreePath path, int row,
3783: boolean isExpanded,
3784: boolean hasBeenExpanded,
3785: boolean isLeaf)
3786: {
3787: Object node = path.getLastPathComponent();
3788: if (treeModel != null && (!isLeaf && !node.equals(treeModel.getRoot())) &&
3789: (tree.isRootVisible() || getLevel(node) != 1))
3790: return true;
3791: return false;
3792: }
3793:
3794:
3798: void updateCurrentVisiblePath()
3799: {
3800: if (treeModel == null)
3801: return;
3802:
3803: Object next = treeModel.getRoot();
3804: Rectangle bounds = getCellBounds(0, 0, next);
3805:
3806:
3807:
3808:
3809: if ((bounds.width == 0 && bounds.height == 0) || (!isRootVisible()
3810: && tree.isExpanded(new TreePath(next))))
3811: next = getNextNode(next);
3812: TreePath current = null;
3813:
3814: while (next != null)
3815: {
3816: if (current == null)
3817: current = new TreePath(next);
3818: else
3819: current = current.pathByAddingChild(next);
3820: do
3821: next = getNextNode(next);
3822: while (next != null &&
3823: !tree.isVisible(new TreePath(getPathToRoot(next, 0))));
3824: }
3825: currentVisiblePath = current;
3826: tree.setVisibleRowCount(getRowCount(tree));
3827: if (tree.getSelectionModel() != null && tree.getSelectionCount() == 0 &&
3828: currentVisiblePath != null)
3829: tree.addSelectionRow(0);
3830: }
3831:
3832:
3841: Object getNextVisibleNode(Object node)
3842: {
3843: if (currentVisiblePath != null)
3844: {
3845: Object[] nodes = currentVisiblePath.getPath();
3846: int i = 0;
3847: while (i < nodes.length && !node.equals(nodes[i]))
3848: i++;
3849:
3850: if (i+1 < nodes.length)
3851: return nodes[i+1];
3852: }
3853: return null;
3854: }
3855: }