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:
118: public class BasicTreeUI extends TreeUI
119: {
120:
121: protected transient Icon collapsedIcon;
122:
123:
124: protected transient Icon expandedIcon;
125:
126:
127: protected int leftChildIndent;
128:
129:
132: protected int rightChildIndent;
133:
134:
138: protected int totalChildIndent;
139:
140:
141: protected int lastSelectedRow;
142:
143:
144: protected JTree tree;
145:
146:
147: protected transient TreeCellRenderer currentCellRenderer;
148:
149:
153: protected boolean createdRenderer;
154:
155:
156: protected transient TreeCellEditor cellEditor;
157:
158:
162: protected boolean createdCellEditor;
163:
164:
168: protected boolean stopEditingInCompleteEditing;
169:
170:
171: protected CellRendererPane rendererPane;
172:
173:
174: protected Dimension preferredSize;
175:
176:
177: protected Dimension preferredMinSize;
178:
179:
180: protected boolean validCachedPreferredSize;
181:
182:
183: protected AbstractLayoutCache treeState;
184:
185:
186: protected Hashtable drawingCache;
187:
188:
193: protected boolean largeModel;
194:
195:
196: protected AbstractLayoutCache.NodeDimensions nodeDimensions;
197:
198:
199: protected TreeModel treeModel;
200:
201:
202: protected TreeSelectionModel treeSelectionModel;
203:
204:
209: protected int depthOffset;
210:
211:
214: protected Component editingComponent;
215:
216:
217: protected TreePath editingPath;
218:
219:
223: protected int editingRow;
224:
225:
226: protected boolean editorHasDifferentSize;
227:
228:
229: Timer editorTimer = new EditorUpdateTimer();
230:
231:
232: Object newVal;
233:
234:
235: TreeAction action;
236:
237:
238: boolean isEditing;
239:
240:
241: TreePath currentVisiblePath;
242:
243:
244: int gap = 4;
245:
246:
247: int maxHeight = 0;
248:
249:
250: private PropertyChangeListener propertyChangeListener;
251:
252: private FocusListener focusListener;
253:
254: private TreeSelectionListener treeSelectionListener;
255:
256: private MouseListener mouseListener;
257:
258: private KeyListener keyListener;
259:
260: private PropertyChangeListener selectionModelPropertyChangeListener;
261:
262: private ComponentListener componentListener;
263:
264: CellEditorListener cellEditorListener;
265:
266: private TreeExpansionListener treeExpansionListener;
267:
268: private TreeModelListener treeModelListener;
269:
270:
273: public BasicTreeUI()
274: {
275: validCachedPreferredSize = false;
276: drawingCache = new Hashtable();
277: nodeDimensions = createNodeDimensions();
278: configureLayoutCache();
279:
280: propertyChangeListener = createPropertyChangeListener();
281: focusListener = createFocusListener();
282: treeSelectionListener = createTreeSelectionListener();
283: mouseListener = createMouseListener();
284: keyListener = createKeyListener();
285: selectionModelPropertyChangeListener = createSelectionModelPropertyChangeListener();
286: componentListener = createComponentListener();
287: cellEditorListener = createCellEditorListener();
288: treeExpansionListener = createTreeExpansionListener();
289: treeModelListener = createTreeModelListener();
290:
291: editingRow = -1;
292: lastSelectedRow = -1;
293: }
294:
295:
302: public static ComponentUI createUI(JComponent c)
303: {
304: return new BasicTreeUI();
305: }
306:
307:
312: protected Color getHashColor()
313: {
314: return UIManager.getColor("Tree.hash");
315: }
316:
317:
323: protected void setHashColor(Color color)
324: {
325:
326: UIManager.put("Tree.hash", color);
327: }
328:
329:
335: public void setLeftChildIndent(int newAmount)
336: {
337: leftChildIndent = newAmount;
338: }
339:
340:
345: public int getLeftChildIndent()
346: {
347: return leftChildIndent;
348: }
349:
350:
356: public void setRightChildIndent(int newAmount)
357: {
358: rightChildIndent = newAmount;
359: }
360:
361:
366: public int getRightChildIndent()
367: {
368: return rightChildIndent;
369: }
370:
371:
377: public void setExpandedIcon(Icon newG)
378: {
379: expandedIcon = newG;
380: }
381:
382:
387: public Icon getExpandedIcon()
388: {
389: return expandedIcon;
390: }
391:
392:
398: public void setCollapsedIcon(Icon newG)
399: {
400: collapsedIcon = newG;
401: }
402:
403:
408: public Icon getCollapsedIcon()
409: {
410: return collapsedIcon;
411: }
412:
413:
419: protected void setLargeModel(boolean largeModel)
420: {
421: if (largeModel != this.largeModel)
422: {
423: tree.removeComponentListener(componentListener);
424: this.largeModel = largeModel;
425: tree.addComponentListener(componentListener);
426: }
427: }
428:
429:
434: protected boolean isLargeModel()
435: {
436: return largeModel;
437: }
438:
439:
445: protected void setRowHeight(int rowHeight)
446: {
447: if (rowHeight == 0)
448: rowHeight = Math.max(getMaxHeight(tree), 20);
449: treeState.setRowHeight(rowHeight);
450: }
451:
452:
457: protected int getRowHeight()
458: {
459: return treeState.getRowHeight();
460: }
461:
462:
469: protected void setCellRenderer(TreeCellRenderer tcr)
470: {
471: currentCellRenderer = tcr;
472: updateRenderer();
473: }
474:
475:
481: protected TreeCellRenderer getCellRenderer()
482: {
483: if (currentCellRenderer != null)
484: return currentCellRenderer;
485:
486: return createDefaultCellRenderer();
487: }
488:
489:
495: protected void setModel(TreeModel model)
496: {
497: tree.setModel(model);
498: treeModel = tree.getModel();
499: }
500:
501:
506: protected TreeModel getModel()
507: {
508: return treeModel;
509: }
510:
511:
517: protected void setRootVisible(boolean newValue)
518: {
519: tree.setRootVisible(newValue);
520: }
521:
522:
527: protected boolean isRootVisible()
528: {
529: return tree.isRootVisible();
530: }
531:
532:
538: protected void setShowsRootHandles(boolean newValue)
539: {
540: tree.setShowsRootHandles(newValue);
541: }
542:
543:
548: protected boolean getShowsRootHandles()
549: {
550: return tree.getShowsRootHandles();
551: }
552:
553:
559: protected void setCellEditor(TreeCellEditor editor)
560: {
561: cellEditor = editor;
562: createdCellEditor = true;
563: }
564:
565:
570: protected TreeCellEditor getCellEditor()
571: {
572: return cellEditor;
573: }
574:
575:
581: protected void setEditable(boolean newValue)
582: {
583: tree.setEditable(newValue);
584: }
585:
586:
591: protected boolean isEditable()
592: {
593: return tree.isEditable();
594: }
595:
596:
603: protected void setSelectionModel(TreeSelectionModel newLSM)
604: {
605: if (newLSM != null)
606: {
607: treeSelectionModel = newLSM;
608: tree.setSelectionModel(treeSelectionModel);
609: }
610: }
611:
612:
617: protected TreeSelectionModel getSelectionModel()
618: {
619: return treeSelectionModel;
620: }
621:
622:
634: public Rectangle getPathBounds(JTree tree, TreePath path)
635: {
636: int row = -1;
637: Object cell = null;
638: if (path != null)
639: {
640: row = getRowForPath(tree, path);
641: cell = path.getLastPathComponent();
642: }
643: return nodeDimensions.getNodeDimensions(cell, row, getLevel(cell),
644: tree.isExpanded(path),
645: new Rectangle());
646: }
647:
648:
655: private int getMaxHeight(JTree tree)
656: {
657: if (maxHeight != 0)
658: return maxHeight;
659:
660: Icon e = UIManager.getIcon("Tree.openIcon");
661: Icon c = UIManager.getIcon("Tree.closedIcon");
662: Icon l = UIManager.getIcon("Tree.leafIcon");
663: int rc = getRowCount(tree);
664: int iconHeight = 0;
665:
666: for (int row = 0; row < rc; row++)
667: {
668: if (isLeaf(row))
669: iconHeight = l.getIconHeight();
670: else if (tree.isExpanded(row))
671: iconHeight = e.getIconHeight();
672: else
673: iconHeight = c.getIconHeight();
674:
675: maxHeight = Math.max(maxHeight, iconHeight + gap);
676: }
677:
678: return maxHeight;
679: }
680:
681:
690: public TreePath getPathForRow(JTree tree, int row)
691: {
692: if (treeModel != null && currentVisiblePath != null)
693: {
694: Object[] nodes = currentVisiblePath.getPath();
695: if (row < nodes.length)
696: return new TreePath(getPathToRoot(nodes[row], 0));
697: }
698: return null;
699: }
700:
701:
713: public int getRowForPath(JTree tree, TreePath path)
714: {
715: int row = 0;
716: Object dest = path.getLastPathComponent();
717: int rowCount = getRowCount(tree);
718: if (currentVisiblePath != null)
719: {
720: Object[] nodes = currentVisiblePath.getPath();
721: while (row < rowCount)
722: {
723: if (dest.equals(nodes[row]))
724: return row;
725: row++;
726: }
727: }
728: return -1;
729: }
730:
731:
738: public int getRowCount(JTree tree)
739: {
740: if (currentVisiblePath != null)
741: return currentVisiblePath.getPathCount();
742: return 0;
743: }
744:
745:
759: public TreePath getClosestPathForLocation(JTree tree, int x, int y)
760: {
761: int row = Math.round(y / getMaxHeight(tree));
762: TreePath path = getPathForRow(tree, row);
763:
764:
765: while (row > 0 && path == null)
766: {
767: --row;
768: path = getPathForRow(tree, row);
769: }
770:
771: return path;
772: }
773:
774:
782: public boolean isEditing(JTree tree)
783: {
784: return isEditing;
785: }
786:
787:
796: public boolean stopEditing(JTree tree)
797: {
798: if (isEditing(tree))
799: completeEditing(true, false, false);
800: return !isEditing(tree);
801: }
802:
803:
809: public void cancelEditing(JTree tree)
810: {
811: if (isEditing(tree))
812: completeEditing(false, true, false);
813: }
814:
815:
824: public void startEditingAtPath(JTree tree, TreePath path)
825: {
826: startEditing(path, null);
827: }
828:
829:
836: public TreePath getEditingPath(JTree tree)
837: {
838: return editingPath;
839: }
840:
841:
845: protected void prepareForUIInstall()
846: {
847:
848: }
849:
850:
854: protected void completeUIInstall()
855: {
856:
857: }
858:
859:
863: protected void completeUIUninstall()
864: {
865:
866: }
867:
868:
871: protected void installComponents()
872: {
873: currentCellRenderer = createDefaultCellRenderer();
874: rendererPane = createCellRendererPane();
875: createdRenderer = true;
876: setCellRenderer(currentCellRenderer);
877: }
878:
879:
885: protected AbstractLayoutCache.NodeDimensions createNodeDimensions()
886: {
887: return new NodeDimensionsHandler();
888: }
889:
890:
896: protected PropertyChangeListener createPropertyChangeListener()
897: {
898: return new PropertyChangeHandler();
899: }
900:
901:
907: protected MouseListener createMouseListener()
908: {
909: return new MouseHandler();
910: }
911:
912:
918: protected FocusListener createFocusListener()
919: {
920: return new FocusHandler();
921: }
922:
923:
928: protected KeyListener createKeyListener()
929: {
930: return new KeyHandler();
931: }
932:
933:
940: protected PropertyChangeListener createSelectionModelPropertyChangeListener()
941: {
942: return new SelectionModelPropertyChangeHandler();
943: }
944:
945:
951: protected TreeSelectionListener createTreeSelectionListener()
952: {
953: return new TreeSelectionHandler();
954: }
955:
956:
961: protected CellEditorListener createCellEditorListener()
962: {
963: return new CellEditorHandler();
964: }
965:
966:
973: protected ComponentListener createComponentListener()
974: {
975: return new ComponentHandler();
976: }
977:
978:
984: protected TreeExpansionListener createTreeExpansionListener()
985: {
986: return new TreeExpansionHandler();
987: }
988:
989:
995: protected AbstractLayoutCache createLayoutCache()
996: {
997: return new FixedHeightLayoutCache();
998: }
999:
1000:
1005: protected CellRendererPane createCellRendererPane()
1006: {
1007: return new CellRendererPane();
1008: }
1009:
1010:
1015: protected TreeCellEditor createDefaultCellEditor()
1016: {
1017: if (currentCellRenderer != null)
1018: return new DefaultTreeCellEditor(
1019: tree,
1020: (DefaultTreeCellRenderer) currentCellRenderer,
1021: cellEditor);
1022: return new DefaultTreeCellEditor(
1023: tree,
1024: (DefaultTreeCellRenderer) createDefaultCellRenderer(),
1025: cellEditor);
1026: }
1027:
1028:
1035: protected TreeCellRenderer createDefaultCellRenderer()
1036: {
1037: return new DefaultTreeCellRenderer();
1038: }
1039:
1040:
1045: protected TreeModelListener createTreeModelListener()
1046: {
1047: return new TreeModelHandler();
1048: }
1049:
1050:
1053: protected void uninstallListeners()
1054: {
1055: tree.removePropertyChangeListener(propertyChangeListener);
1056: tree.removeFocusListener(focusListener);
1057: tree.removeTreeSelectionListener(treeSelectionListener);
1058: tree.removeMouseListener(mouseListener);
1059: tree.removeKeyListener(keyListener);
1060: tree.removePropertyChangeListener(selectionModelPropertyChangeListener);
1061: tree.removeComponentListener(componentListener);
1062: tree.removeTreeExpansionListener(treeExpansionListener);
1063:
1064: TreeCellEditor tce = tree.getCellEditor();
1065: if (tce != null)
1066: tce.removeCellEditorListener(cellEditorListener);
1067: if (treeModel != null)
1068: treeModel.removeTreeModelListener(treeModelListener);
1069: }
1070:
1071:
1074: protected void uninstallKeyboardActions()
1075: {
1076: action = null;
1077: tree.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).setParent(
1078: null);
1079: tree.getActionMap().setParent(null);
1080: }
1081:
1082:
1085: protected void uninstallComponents()
1086: {
1087: currentCellRenderer = null;
1088: rendererPane = null;
1089: createdRenderer = false;
1090: setCellRenderer(currentCellRenderer);
1091: }
1092:
1093:
1099: protected int getVerticalLegBuffer()
1100: {
1101: return getRowHeight() / 2;
1102: }
1103:
1104:
1111: protected int getHorizontalLegBuffer()
1112: {
1113: return rightChildIndent / 2;
1114: }
1115:
1116:
1120: protected void updateLayoutCacheExpandedNodes()
1121: {
1122: if (treeModel != null)
1123: updateExpandedDescendants(new TreePath(treeModel.getRoot()));
1124: }
1125:
1126:
1134: protected void updateExpandedDescendants(TreePath path)
1135: {
1136: Enumeration expanded = tree.getExpandedDescendants(path);
1137: while (expanded.hasMoreElements())
1138: treeState.setExpandedState(((TreePath) expanded.nextElement()), true);
1139: }
1140:
1141:
1148: protected TreePath getLastChildPath(TreePath parent)
1149: {
1150: return ((TreePath) parent.getLastPathComponent());
1151: }
1152:
1153:
1156: protected void updateDepthOffset()
1157: {
1158: depthOffset += getVerticalLegBuffer();
1159: }
1160:
1161:
1166: protected void updateCellEditor()
1167: {
1168: if (tree.isEditable() && cellEditor == null)
1169: setCellEditor(createDefaultCellEditor());
1170: createdCellEditor = true;
1171: }
1172:
1173:
1176: protected void updateRenderer()
1177: {
1178: if (tree != null)
1179: {
1180: if (tree.getCellRenderer() == null)
1181: {
1182: if (currentCellRenderer == null)
1183: currentCellRenderer = createDefaultCellRenderer();
1184: tree.setCellRenderer(currentCellRenderer);
1185: }
1186: }
1187: }
1188:
1189:
1193: protected void configureLayoutCache()
1194: {
1195: treeState = createLayoutCache();
1196: }
1197:
1198:
1202: protected void updateSize()
1203: {
1204: preferredSize = null;
1205: updateCachedPreferredSize();
1206: tree.treeDidChange();
1207: }
1208:
1209:
1213: protected void updateCachedPreferredSize()
1214: {
1215: int maxWidth = 0;
1216: boolean isLeaf = false;
1217: if (currentVisiblePath != null)
1218: {
1219: Object[] path = currentVisiblePath.getPath();
1220: for (int i = 0; i < path.length; i++)
1221: {
1222: TreePath curr = new TreePath(getPathToRoot(path[i], 0));
1223: Rectangle bounds = getPathBounds(tree, curr);
1224: if (treeModel != null)
1225: isLeaf = treeModel.isLeaf(path[i]);
1226: if (!isLeaf && hasControlIcons())
1227: bounds.width += getCurrentControlIcon(curr).getIconWidth();
1228: maxWidth = Math.max(maxWidth, bounds.x + bounds.width);
1229: }
1230:
1231: maxHeight = 0;
1232: maxHeight = getMaxHeight(tree);
1233: preferredSize = new Dimension(maxWidth, (maxHeight * path.length));
1234: }
1235: else
1236: preferredSize = new Dimension(0, 0);
1237: validCachedPreferredSize = true;
1238: }
1239:
1240:
1246: protected void pathWasExpanded(TreePath path)
1247: {
1248: validCachedPreferredSize = false;
1249: tree.repaint();
1250: }
1251:
1252:
1255: protected void pathWasCollapsed(TreePath path)
1256: {
1257: validCachedPreferredSize = false;
1258: tree.repaint();
1259: }
1260:
1261:
1264: protected void installDefaults()
1265: {
1266: LookAndFeel.installColorsAndFont(tree, "Tree.background",
1267: "Tree.foreground", "Tree.font");
1268: tree.setOpaque(true);
1269:
1270: rightChildIndent = UIManager.getInt("Tree.rightChildIndent");
1271: leftChildIndent = UIManager.getInt("Tree.leftChildIndent");
1272: setRowHeight(UIManager.getInt("Tree.rowHeight"));
1273: tree.setRowHeight(getRowHeight());
1274: tree.requestFocusInWindow(false);
1275: tree.setScrollsOnExpand(UIManager.getBoolean("Tree.scrollsOnExpand"));
1276: setExpandedIcon(UIManager.getIcon("Tree.expandedIcon"));
1277: setCollapsedIcon(UIManager.getIcon("Tree.collapsedIcon"));
1278: }
1279:
1280:
1283: protected void installKeyboardActions()
1284: {
1285: InputMap focusInputMap = (InputMap) UIManager.get("Tree.focusInputMap");
1286: InputMapUIResource parentInputMap = new InputMapUIResource();
1287: ActionMap parentActionMap = new ActionMapUIResource();
1288: action = new TreeAction();
1289: Object keys[] = focusInputMap.allKeys();
1290:
1291: for (int i = 0; i < keys.length; i++)
1292: {
1293: parentInputMap.put(
1294: KeyStroke.getKeyStroke(
1295: ((KeyStroke) keys[i]).getKeyCode(),
1296: convertModifiers(((KeyStroke) keys[i]).getModifiers())),
1297: (String) focusInputMap.get((KeyStroke) keys[i]));
1298:
1299: parentInputMap.put(
1300: KeyStroke.getKeyStroke(
1301: ((KeyStroke) keys[i]).getKeyCode(),
1302: ((KeyStroke) keys[i]).getModifiers()),
1303: (String) focusInputMap.get((KeyStroke) keys[i]));
1304:
1305: parentActionMap.put(
1306: (String) focusInputMap.get((KeyStroke) keys[i]),
1307: new ActionListenerProxy(
1308: action,
1309: (String) focusInputMap.get((KeyStroke) keys[i])));
1310:
1311: }
1312:
1313: parentInputMap.setParent(tree.getInputMap(
1314: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).getParent());
1315: parentActionMap.setParent(tree.getActionMap().getParent());
1316: tree.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).setParent(
1317: parentInputMap);
1318: tree.getActionMap().setParent(parentActionMap);
1319: }
1320:
1321:
1328: private int convertModifiers(int mod)
1329: {
1330: if ((mod & KeyEvent.SHIFT_DOWN_MASK) != 0)
1331: {
1332: mod |= KeyEvent.SHIFT_MASK;
1333: mod &= ~KeyEvent.SHIFT_DOWN_MASK;
1334: }
1335: if ((mod & KeyEvent.CTRL_DOWN_MASK) != 0)
1336: {
1337: mod |= KeyEvent.CTRL_MASK;
1338: mod &= ~KeyEvent.CTRL_DOWN_MASK;
1339: }
1340: if ((mod & KeyEvent.META_DOWN_MASK) != 0)
1341: {
1342: mod |= KeyEvent.META_MASK;
1343: mod &= ~KeyEvent.META_DOWN_MASK;
1344: }
1345: if ((mod & KeyEvent.ALT_DOWN_MASK) != 0)
1346: {
1347: mod |= KeyEvent.ALT_MASK;
1348: mod &= ~KeyEvent.ALT_DOWN_MASK;
1349: }
1350: if ((mod & KeyEvent.ALT_GRAPH_DOWN_MASK) != 0)
1351: {
1352: mod |= KeyEvent.ALT_GRAPH_MASK;
1353: mod &= ~KeyEvent.ALT_GRAPH_DOWN_MASK;
1354: }
1355: return mod;
1356: }
1357:
1358:
1361: protected void installListeners()
1362: {
1363: tree.addPropertyChangeListener(propertyChangeListener);
1364: tree.addFocusListener(focusListener);
1365: tree.addTreeSelectionListener(treeSelectionListener);
1366: tree.addMouseListener(mouseListener);
1367: tree.addKeyListener(keyListener);
1368: tree.addPropertyChangeListener(selectionModelPropertyChangeListener);
1369: tree.addComponentListener(componentListener);
1370: tree.addTreeExpansionListener(treeExpansionListener);
1371: if (treeModel != null)
1372: treeModel.addTreeModelListener(treeModelListener);
1373: }
1374:
1375:
1381: public void installUI(JComponent c)
1382: {
1383: tree = (JTree) c;
1384: prepareForUIInstall();
1385: super.installUI(c);
1386: installDefaults();
1387:
1388: installComponents();
1389: installKeyboardActions();
1390: installListeners();
1391:
1392: setCellEditor(createDefaultCellEditor());
1393: createdCellEditor = true;
1394: isEditing = false;
1395:
1396: setModel(tree.getModel());
1397: treeSelectionModel = tree.getSelectionModel();
1398:
1399: completeUIInstall();
1400: }
1401:
1402:
1405: protected void uninstallDefaults()
1406: {
1407: tree.setFont(null);
1408: tree.setForeground(null);
1409: tree.setBackground(null);
1410: }
1411:
1412:
1418: public void uninstallUI(JComponent c)
1419: {
1420: prepareForUIUninstall();
1421: uninstallDefaults();
1422: uninstallKeyboardActions();
1423: uninstallListeners();
1424: tree = null;
1425: uninstallComponents();
1426: completeUIUninstall();
1427: }
1428:
1429:
1442: public void paint(Graphics g, JComponent c)
1443: {
1444: JTree tree = (JTree) c;
1445: updateCurrentVisiblePath();
1446:
1447: Rectangle clip = g.getClipBounds();
1448: Insets insets = tree.getInsets();
1449:
1450: if (clip != null && treeModel != null && currentVisiblePath != null)
1451: {
1452: int startIndex = tree.getClosestRowForLocation(clip.x, clip.y);
1453: int endIndex = tree.getClosestRowForLocation(clip.x + clip.width,
1454: clip.y + clip.height);
1455:
1456: paintVerticalPartOfLeg(g, clip, insets, currentVisiblePath);
1457: for (int i = startIndex; i <= endIndex; i++)
1458: {
1459: Object curr = currentVisiblePath.getPathComponent(i);
1460: boolean isLeaf = treeModel.isLeaf(curr);
1461: TreePath path = new TreePath(getPathToRoot(curr, 0));
1462:
1463: boolean isExpanded = tree.isExpanded(path);
1464: Rectangle bounds = getPathBounds(tree, path);
1465: paintHorizontalPartOfLeg(g, clip, insets, bounds, path, i,
1466: isExpanded, false, isLeaf);
1467: paintRow(g, clip, insets, bounds, path, i, isExpanded, false,
1468: isLeaf);
1469: }
1470: }
1471: }
1472:
1473:
1481: protected void ensureRowsAreVisible(int beginRow, int endRow)
1482: {
1483: if (beginRow < endRow)
1484: {
1485: int temp = endRow;
1486: endRow = beginRow;
1487: beginRow = temp;
1488: }
1489:
1490: for (int i = beginRow; i < endRow; i++)
1491: {
1492: TreePath path = getPathForRow(tree, i);
1493: if (!tree.isVisible(path))
1494: tree.makeVisible(path);
1495: }
1496: }
1497:
1498:
1504: public void setPreferredMinSize(Dimension newSize)
1505: {
1506: preferredMinSize = newSize;
1507: }
1508:
1509:
1514: public Dimension getPreferredMinSize()
1515: {
1516: return preferredMinSize;
1517: }
1518:
1519:
1529: public Dimension getPreferredSize(JComponent c)
1530: {
1531: return getPreferredSize(c, false);
1532: }
1533:
1534:
1544: public Dimension getPreferredSize(JComponent c, boolean checkConsistancy)
1545: {
1546:
1547: if (!validCachedPreferredSize)
1548: updateCachedPreferredSize();
1549: return preferredSize;
1550: }
1551:
1552:
1560: public Dimension getMinimumSize(JComponent c)
1561: {
1562: Dimension min = getPreferredMinSize();
1563: if (min == null)
1564: return new Dimension();
1565: return min;
1566: }
1567:
1568:
1576: public Dimension getMaximumSize(JComponent c)
1577: {
1578: if (c instanceof JTree)
1579: return ((JTree) c).getPreferredSize();
1580: return new Dimension();
1581: }
1582:
1583:
1590: protected void completeEditing()
1591: {
1592: completeEditing(false, true, false);
1593: }
1594:
1595:
1608: protected void completeEditing(boolean messageStop, boolean messageCancel,
1609: boolean messageTree)
1610: {
1611: if (messageStop)
1612: {
1613: getCellEditor().stopCellEditing();
1614: stopEditingInCompleteEditing = true;
1615: }
1616:
1617: if (messageCancel)
1618: {
1619: getCellEditor().cancelCellEditing();
1620: stopEditingInCompleteEditing = true;
1621: }
1622:
1623: if (messageTree)
1624: treeModel.valueForPathChanged(tree.getLeadSelectionPath(), newVal);
1625: }
1626:
1627:
1637: protected boolean startEditing(TreePath path, MouseEvent event)
1638: {
1639: int x;
1640: int y;
1641: if (event == null)
1642: {
1643: Rectangle bounds = getPathBounds(tree, path);
1644: x = bounds.x;
1645: y = bounds.y;
1646: }
1647: else
1648: {
1649: x = event.getX();
1650: y = event.getY();
1651: }
1652:
1653: updateCellEditor();
1654: TreeCellEditor ed = getCellEditor();
1655: if (ed != null && ed.shouldSelectCell(event) && ed.isCellEditable(event))
1656: {
1657: editingPath = path;
1658: editingRow = tree.getRowForPath(editingPath);
1659:
1660: Object val = editingPath.getLastPathComponent();
1661: cellEditor.addCellEditorListener(cellEditorListener);
1662: stopEditingInCompleteEditing = false;
1663: boolean expanded = tree.isExpanded(editingPath);
1664: isEditing = true;
1665: editingComponent = ed.getTreeCellEditorComponent(tree, val, true,
1666: expanded,
1667: isLeaf(editingRow),
1668: editingRow);
1669: editingComponent.getParent().setVisible(true);
1670: editingComponent.getParent().validate();
1671: tree.add(editingComponent.getParent());
1672: editingComponent.getParent().validate();
1673: validCachedPreferredSize = false;
1674:
1675: ((JTextField) editingComponent).requestFocusInWindow(false);
1676: editorTimer.start();
1677: return true;
1678: }
1679: return false;
1680: }
1681:
1682:
1693: protected void checkForClickInExpandControl(TreePath path, int mouseX,
1694: int mouseY)
1695: {
1696: if (isLocationInExpandControl(path, mouseX, mouseY))
1697: toggleExpandState(path);
1698: }
1699:
1700:
1715: protected boolean isLocationInExpandControl(TreePath path, int mouseX,
1716: int mouseY)
1717: {
1718: boolean cntlClick = false;
1719: int row = getRowForPath(tree, path);
1720:
1721: if (!isLeaf(row))
1722: {
1723: Rectangle bounds = getPathBounds(tree, path);
1724:
1725: if (hasControlIcons()
1726: && (mouseX < bounds.x)
1727: && (mouseX > (bounds.x - getCurrentControlIcon(path).getIconWidth() - gap)))
1728: cntlClick = true;
1729: }
1730: return cntlClick;
1731: }
1732:
1733:
1744: protected void handleExpandControlClick(TreePath path, int mouseX, int mouseY)
1745: {
1746: toggleExpandState(path);
1747: }
1748:
1749:
1758: protected void toggleExpandState(TreePath path)
1759: {
1760: if (tree.isExpanded(path))
1761: tree.collapsePath(path);
1762: else
1763: tree.expandPath(path);
1764: }
1765:
1766:
1775: protected boolean isToggleSelectionEvent(MouseEvent event)
1776: {
1777: return (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.SINGLE_TREE_SELECTION);
1778: }
1779:
1780:
1789: protected boolean isMultiSelectEvent(MouseEvent event)
1790: {
1791: return (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.CONTIGUOUS_TREE_SELECTION);
1792: }
1793:
1794:
1804: protected boolean isToggleEvent(MouseEvent event)
1805: {
1806: return true;
1807: }
1808:
1809:
1821: protected void selectPathForEvent(TreePath path, MouseEvent event)
1822: {
1823: if (isToggleSelectionEvent(event))
1824: {
1825: if (tree.isPathSelected(path))
1826: tree.removeSelectionPath(path);
1827: else
1828: {
1829: tree.addSelectionPath(path);
1830: tree.setAnchorSelectionPath(path);
1831: }
1832: }
1833: else if (isMultiSelectEvent(event))
1834: {
1835: TreePath anchor = tree.getAnchorSelectionPath();
1836: if (anchor != null)
1837: {
1838: int aRow = getRowForPath(tree, anchor);
1839: tree.addSelectionInterval(aRow, getRowForPath(tree, path));
1840: }
1841: else
1842: tree.addSelectionPath(path);
1843: }
1844: else
1845: tree.addSelectionPath(path);
1846: }
1847:
1848:
1855: protected boolean isLeaf(int row)
1856: {
1857: TreePath pathForRow = getPathForRow(tree, row);
1858: if (pathForRow == null)
1859: return true;
1860:
1861: Object node = pathForRow.getLastPathComponent();
1862: return treeModel.isLeaf(node);
1863: }
1864:
1865:
1870: class TreeAction extends AbstractAction
1871: {
1872:
1873:
1879: public void actionPerformed(ActionEvent e)
1880: {
1881: TreePath lead = tree.getLeadSelectionPath();
1882:
1883: if (e.getActionCommand().equals("selectPreviousChangeLead")
1884: || e.getActionCommand().equals("selectPreviousExtendSelection")
1885: || e.getActionCommand().equals("selectPrevious")
1886: || e.getActionCommand().equals("selectNext")
1887: || e.getActionCommand().equals("selectNextExtendSelection")
1888: || e.getActionCommand().equals("selectNextChangeLead"))
1889: (new TreeIncrementAction(0, "")).actionPerformed(e);
1890: else if (e.getActionCommand().equals("selectParent")
1891: || e.getActionCommand().equals("selectChild"))
1892: (new TreeTraverseAction(0, "")).actionPerformed(e);
1893: else if (e.getActionCommand().equals("selectAll"))
1894: {
1895: TreePath[] paths = new TreePath[tree.getVisibleRowCount()];
1896:
1897: Object curr = getNextVisibleNode(treeModel.getRoot());
1898: int i = 0;
1899: while (curr != null && i < paths.length)
1900: {
1901: paths[i] = new TreePath(getPathToRoot(curr, 0));
1902: i++;
1903: }
1904:
1905: tree.addSelectionPaths(paths);
1906: }
1907: else if (e.getActionCommand().equals("startEditing"))
1908: tree.startEditingAtPath(lead);
1909: else if (e.getActionCommand().equals("toggle"))
1910: {
1911: if (tree.isEditing())
1912: tree.stopEditing();
1913: else
1914: {
1915: Object last = lead.getLastPathComponent();
1916: TreePath path = new TreePath(getPathToRoot(last, 0));
1917: if (!treeModel.isLeaf(last))
1918: toggleExpandState(path);
1919: }
1920: }
1921: else if (e.getActionCommand().equals("clearSelection"))
1922: tree.clearSelection();
1923:
1924: if (tree.isEditing() && !e.getActionCommand().equals("startEditing"))
1925: tree.cancelEditing();
1926:
1927: tree.scrollPathToVisible(lead);
1928: }
1929: }
1930:
1931:
1938: private static class ActionListenerProxy extends AbstractAction
1939: {
1940: ActionListener target;
1941:
1942: String bindingCommandName;
1943:
1944: public ActionListenerProxy(ActionListener li, String cmd)
1945: {
1946: target = li;
1947: bindingCommandName = cmd;
1948: }
1949:
1950: public void actionPerformed(ActionEvent e)
1951: {
1952: ActionEvent derivedEvent = new ActionEvent(e.getSource(), e.getID(),
1953: bindingCommandName,
1954: e.getModifiers());
1955:
1956: target.actionPerformed(derivedEvent);
1957: }
1958: }
1959:
1960:
1963: private class EditorUpdateTimer extends Timer implements ActionListener
1964: {
1965:
1969: public EditorUpdateTimer()
1970: {
1971: super(300, null);
1972: addActionListener(this);
1973: }
1974:
1975:
1978: public void actionPerformed(ActionEvent ev)
1979: {
1980: Caret c = ((JTextField) editingComponent).getCaret();
1981: if (c != null)
1982: c.setVisible(!c.isVisible());
1983: tree.repaint();
1984: }
1985:
1986:
1989: public void update()
1990: {
1991: stop();
1992: Caret c = ((JTextField) editingComponent).getCaret();
1993: if (c != null)
1994: {
1995: setDelay(c.getBlinkRate());
1996: if (((JTextField) editingComponent).isEditable())
1997: start();
1998: else
1999: c.setVisible(false);
2000: }
2001: }
2002: }
2003:
2004:
2007: public class ComponentHandler extends ComponentAdapter implements
2008: ActionListener
2009: {
2010:
2013: protected Timer timer;
2014:
2015:
2016: protected JScrollBar scrollBar;
2017:
2018:
2021: public ComponentHandler()
2022: {
2023:
2024: }
2025:
2026:
2032: public void componentMoved(ComponentEvent e)
2033: {
2034:
2035: }
2036:
2037:
2041: protected void startTimer()
2042: {
2043:
2044: }
2045:
2046:
2051: protected JScrollPane getScrollPane()
2052: {
2053: return null;
2054: }
2055:
2056:
2063: public void actionPerformed(ActionEvent ae)
2064: {
2065:
2066: }
2067: }
2068:
2069:
2073: public class CellEditorHandler implements CellEditorListener
2074: {
2075:
2078: public CellEditorHandler()
2079: {
2080:
2081: }
2082:
2083:
2090: public void editingStopped(ChangeEvent e)
2091: {
2092: editingPath = null;
2093: editingRow = -1;
2094: stopEditingInCompleteEditing = false;
2095: if (editingComponent != null)
2096: {
2097: tree.remove(editingComponent.getParent());
2098: editingComponent = null;
2099: }
2100: if (cellEditor != null)
2101: {
2102: newVal = ((JTextField) getCellEditor().getCellEditorValue()).getText();
2103: completeEditing(false, false, true);
2104: if (cellEditor instanceof DefaultTreeCellEditor)
2105: tree.removeTreeSelectionListener((DefaultTreeCellEditor) cellEditor);
2106: cellEditor.removeCellEditorListener(cellEditorListener);
2107: setCellEditor(null);
2108: createdCellEditor = false;
2109: }
2110: isEditing = false;
2111: tree.requestFocusInWindow(false);
2112: editorTimer.stop();
2113: validCachedPreferredSize = false;
2114: tree.repaint();
2115: }
2116:
2117:
2124: public void editingCanceled(ChangeEvent e)
2125: {
2126: editingPath = null;
2127: editingRow = -1;
2128: stopEditingInCompleteEditing = false;
2129: if (editingComponent != null)
2130: tree.remove(editingComponent.getParent());
2131: editingComponent = null;
2132: if (cellEditor != null)
2133: {
2134: if (cellEditor instanceof DefaultTreeCellEditor)
2135: tree.removeTreeSelectionListener((DefaultTreeCellEditor) cellEditor);
2136: cellEditor.removeCellEditorListener(cellEditorListener);
2137: setCellEditor(null);
2138: createdCellEditor = false;
2139: }
2140: tree.requestFocusInWindow(false);
2141: editorTimer.stop();
2142: isEditing = false;
2143: validCachedPreferredSize = false;
2144: tree.repaint();
2145: }
2146: }
2147:
2148:
2151: public class FocusHandler implements FocusListener
2152: {
2153:
2156: public FocusHandler()
2157: {
2158:
2159: }
2160:
2161:
2168: public void focusGained(FocusEvent e)
2169: {
2170:
2171: }
2172:
2173:
2180: public void focusLost(FocusEvent e)
2181: {
2182:
2183: }
2184: }
2185:
2186:
2190: public class KeyHandler extends KeyAdapter
2191: {
2192:
2193: protected Action repeatKeyAction;
2194:
2195:
2196: protected boolean isKeyDown;
2197:
2198:
2201: public KeyHandler()
2202: {
2203:
2204: }
2205:
2206:
2215: public void keyTyped(KeyEvent e)
2216: {
2217:
2218: }
2219:
2220:
2226: public void keyPressed(KeyEvent e)
2227: {
2228:
2229: }
2230:
2231:
2237: public void keyReleased(KeyEvent e)
2238: {
2239:
2240: }
2241: }
2242:
2243:
2247: public class MouseHandler extends MouseAdapter implements MouseMotionListener
2248: {
2249:
2252: public MouseHandler()
2253: {
2254:
2255: }
2256:
2257:
2263: public void mousePressed(MouseEvent e)
2264: {
2265: Point click = e.getPoint();
2266: TreePath path = getClosestPathForLocation(tree, click.x, click.y);
2267:
2268: if (path != null)
2269: {
2270: Rectangle bounds = getPathBounds(tree, path);
2271: int row = getRowForPath(tree, path);
2272: boolean cntlClick = isLocationInExpandControl(path, click.x, click.y);
2273:
2274: boolean isLeaf = isLeaf(row);
2275:
2276: TreeCellRenderer tcr = getCellRenderer();
2277: Icon icon;
2278: if (isLeaf)
2279: icon = UIManager.getIcon("Tree.leafIcon");
2280: else if (tree.isExpanded(path))
2281: icon = UIManager.getIcon("Tree.openIcon");
2282: else
2283: icon = UIManager.getIcon("Tree.closedIcon");
2284:
2285: if (tcr instanceof DefaultTreeCellRenderer)
2286: {
2287: Icon tmp = ((DefaultTreeCellRenderer) tcr).getIcon();
2288: if (tmp != null)
2289: icon = tmp;
2290: }
2291:
2292:
2293: if (icon != null)
2294: bounds.width += icon.getIconWidth() + gap * 2;
2295:
2296: boolean inBounds = bounds.contains(click.x, click.y);
2297: if ((inBounds || cntlClick) && tree.isVisible(path))
2298: {
2299: if (inBounds)
2300: {
2301: selectPath(tree, path);
2302: if (e.getClickCount() == 2 && !isLeaf(row))
2303: toggleExpandState(path);
2304: }
2305:
2306: if (cntlClick)
2307: {
2308: handleExpandControlClick(path, click.x, click.y);
2309: if (cellEditor != null)
2310: cellEditor.cancelCellEditing();
2311: tree.scrollPathToVisible(path);
2312: }
2313: else if (tree.isEditable())
2314: startEditing(path, e);
2315: }
2316: }
2317: }
2318:
2319:
2328: public void mouseDragged(MouseEvent e)
2329: {
2330:
2331: }
2332:
2333:
2340: public void mouseMoved(MouseEvent e)
2341: {
2342:
2343: }
2344:
2345:
2351: public void mouseReleased(MouseEvent e)
2352: {
2353:
2354: }
2355: }
2356:
2357:
2362: public class MouseInputHandler implements MouseInputListener
2363: {
2364:
2365: protected Component source;
2366:
2367:
2368: protected Component destination;
2369:
2370:
2380: public MouseInputHandler(Component source, Component destination,
2381: MouseEvent e)
2382: {
2383: this.source = source;
2384: this.destination = destination;
2385: }
2386:
2387:
2394: public void mouseClicked(MouseEvent e)
2395: {
2396:
2397: }
2398:
2399:
2405: public void mousePressed(MouseEvent e)
2406: {
2407:
2408: }
2409:
2410:
2416: public void mouseReleased(MouseEvent e)
2417: {
2418:
2419: }
2420:
2421:
2427: public void mouseEntered(MouseEvent e)
2428: {
2429:
2430: }
2431:
2432:
2438: public void mouseExited(MouseEvent e)
2439: {
2440:
2441: }
2442:
2443:
2452: public void mouseDragged(MouseEvent e)
2453: {
2454:
2455: }
2456:
2457:
2464: public void mouseMoved(MouseEvent e)
2465: {
2466:
2467: }
2468:
2469:
2472: protected void removeFromSource()
2473: {
2474:
2475: }
2476: }
2477:
2478:
2483: public class NodeDimensionsHandler extends AbstractLayoutCache.NodeDimensions
2484: {
2485:
2488: public NodeDimensionsHandler()
2489: {
2490:
2491: }
2492:
2493:
2511: public Rectangle getNodeDimensions(Object cell, int row, int depth,
2512: boolean expanded, Rectangle size)
2513: {
2514: if (size == null || cell == null)
2515: return null;
2516:
2517: String s = cell.toString();
2518: Font f = tree.getFont();
2519: FontMetrics fm = tree.getToolkit().getFontMetrics(f);
2520:
2521: if (s != null)
2522: {
2523: size.x = getRowX(row, depth);
2524: size.width = SwingUtilities.computeStringWidth(fm, s);
2525: size.height = getMaxHeight(tree);
2526: size.y = size.height * row;
2527: }
2528:
2529: return size;
2530: }
2531:
2532:
2537: protected int getRowX(int row, int depth)
2538: {
2539: if (row == 0)
2540: return 0;
2541: return depth * rightChildIndent;
2542: }
2543: }
2544:
2545:
2549: public class PropertyChangeHandler implements PropertyChangeListener
2550: {
2551:
2552:
2555: public PropertyChangeHandler()
2556: {
2557:
2558: }
2559:
2560:
2567: public void propertyChange(PropertyChangeEvent event)
2568: {
2569: if ((event.getPropertyName()).equals("rootVisible"))
2570: {
2571: validCachedPreferredSize = false;
2572: tree.repaint();
2573: }
2574: }
2575: }
2576:
2577:
2581: public class SelectionModelPropertyChangeHandler implements
2582: PropertyChangeListener
2583: {
2584:
2585:
2588: public SelectionModelPropertyChangeHandler()
2589: {
2590:
2591: }
2592:
2593:
2600: public void propertyChange(PropertyChangeEvent event)
2601: {
2602:
2603: }
2604: }
2605:
2606:
2609: public class TreeCancelEditingAction extends AbstractAction
2610: {
2611:
2612:
2615: public TreeCancelEditingAction(String name)
2616: {
2617:
2618: }
2619:
2620:
2626: public void actionPerformed(ActionEvent e)
2627: {
2628:
2629: }
2630:
2631:
2636: public boolean isEnabled()
2637: {
2638:
2639: return false;
2640: }
2641: }
2642:
2643:
2646: public class TreeExpansionHandler implements TreeExpansionListener
2647: {
2648:
2649:
2652: public TreeExpansionHandler()
2653: {
2654:
2655: }
2656:
2657:
2663: public void treeExpanded(TreeExpansionEvent event)
2664: {
2665: validCachedPreferredSize = false;
2666: tree.repaint();
2667: }
2668:
2669:
2675: public void treeCollapsed(TreeExpansionEvent event)
2676: {
2677: validCachedPreferredSize = false;
2678: tree.repaint();
2679: }
2680: }
2681:
2682:
2686: public class TreeHomeAction extends AbstractAction
2687: {
2688:
2689:
2690: protected int direction;
2691:
2692:
2700: public TreeHomeAction(int direction, String name)
2701: {
2702:
2703: }
2704:
2705:
2711: public void actionPerformed(ActionEvent e)
2712: {
2713:
2714: }
2715:
2716:
2721: public boolean isEnabled()
2722: {
2723:
2724: return false;
2725: }
2726: }
2727:
2728:
2732: public class TreeIncrementAction extends AbstractAction
2733: {
2734:
2735:
2736: protected int direction;
2737:
2738:
2746: public TreeIncrementAction(int direction, String name)
2747: {
2748:
2749: }
2750:
2751:
2757: public void actionPerformed(ActionEvent e)
2758: {
2759: Object last = tree.getLeadSelectionPath().getLastPathComponent();
2760:
2761: if (e.getActionCommand().equals("selectPreviousChangeLead"))
2762: {
2763: Object prev = getPreviousVisibleNode(last);
2764:
2765: if (prev != null)
2766: {
2767: TreePath newPath = new TreePath(getPathToRoot(prev, 0));
2768: selectPath(tree, newPath);
2769: tree.setLeadSelectionPath(newPath);
2770: }
2771: }
2772: else if (e.getActionCommand().equals("selectPreviousExtendSelection"))
2773: {
2774: Object prev = getPreviousVisibleNode(last);
2775: if (prev != null)
2776: {
2777: TreePath newPath = new TreePath(getPathToRoot(prev, 0));
2778: tree.addSelectionPath(newPath);
2779: tree.setLeadSelectionPath(newPath);
2780: }
2781: }
2782: else if (e.getActionCommand().equals("selectPrevious"))
2783: {
2784: Object prev = getPreviousVisibleNode(last);
2785:
2786: if (prev != null)
2787: {
2788: TreePath newPath = new TreePath(getPathToRoot(prev, 0));
2789: selectPath(tree, newPath);
2790: }
2791: }
2792: else if (e.getActionCommand().equals("selectNext"))
2793: {
2794: Object next = getNextVisibleNode(last);
2795:
2796: if (next != null)
2797: {
2798: TreePath newPath = new TreePath(getPathToRoot(next, 0));
2799: selectPath(tree, newPath);
2800: }
2801: }
2802: else if (e.getActionCommand().equals("selectNextExtendSelection"))
2803: {
2804: Object next = getNextVisibleNode(last);
2805: if (next != null)
2806: {
2807: TreePath newPath = new TreePath(getPathToRoot(next, 0));
2808: tree.addSelectionPath(newPath);
2809: tree.setLeadSelectionPath(newPath);
2810: }
2811: }
2812: else if (e.getActionCommand().equals("selectNextChangeLead"))
2813: {
2814: Object next = getNextVisibleNode(last);
2815: if (next != null)
2816: {
2817: TreePath newPath = new TreePath(getPathToRoot(next, 0));
2818: selectPath(tree, newPath);
2819: tree.setLeadSelectionPath(newPath);
2820: }
2821: }
2822: }
2823:
2824:
2829: public boolean isEnabled()
2830: {
2831:
2832: return false;
2833: }
2834: }
2835:
2836:
2839: public class TreeModelHandler implements TreeModelListener
2840: {
2841:
2844: public TreeModelHandler()
2845: {
2846:
2847: }
2848:
2849:
2862: public void treeNodesChanged(TreeModelEvent e)
2863: {
2864: validCachedPreferredSize = false;
2865: tree.repaint();
2866: }
2867:
2868:
2876: public void treeNodesInserted(TreeModelEvent e)
2877: {
2878: validCachedPreferredSize = false;
2879: tree.repaint();
2880: }
2881:
2882:
2893: public void treeNodesRemoved(TreeModelEvent e)
2894: {
2895: validCachedPreferredSize = false;
2896: tree.repaint();
2897: }
2898:
2899:
2909: public void treeStructureChanged(TreeModelEvent e)
2910: {
2911: if (e.getPath().length == 1
2912: && !e.getPath()[0].equals(treeModel.getRoot()))
2913: tree.expandPath(new TreePath(treeModel.getRoot()));
2914: validCachedPreferredSize = false;
2915: tree.repaint();
2916: }
2917: }
2918:
2919:
2922: public class TreePageAction extends AbstractAction
2923: {
2924:
2925: protected int direction;
2926:
2927:
2935: public TreePageAction(int direction, String name)
2936: {
2937: this.direction = direction;
2938: }
2939:
2940:
2946: public void actionPerformed(ActionEvent e)
2947: {
2948:
2949: }
2950:
2951:
2956: public boolean isEnabled()
2957: {
2958: return false;
2959: }
2960: }
2961:
2962:
2966: public class TreeSelectionHandler implements TreeSelectionListener
2967: {
2968:
2971: public TreeSelectionHandler()
2972: {
2973:
2974: }
2975:
2976:
2983: public void valueChanged(TreeSelectionEvent event)
2984: {
2985: if (tree.isEditing())
2986: tree.cancelEditing();
2987: }
2988: }
2989:
2990:
2993: public class TreeToggleAction extends AbstractAction
2994: {
2995:
3001: public TreeToggleAction(String name)
3002: {
3003:
3004: }
3005:
3006:
3012: public void actionPerformed(ActionEvent e)
3013: {
3014:
3015: }
3016:
3017:
3022: public boolean isEnabled()
3023: {
3024: return false;
3025: }
3026: }
3027:
3028:
3032: public class TreeTraverseAction extends AbstractAction
3033: {
3034:
3037: protected int direction;
3038:
3039:
3047: public TreeTraverseAction(int direction, String name)
3048: {
3049: this.direction = direction;
3050: }
3051:
3052:
3058: public void actionPerformed(ActionEvent e)
3059: {
3060: Object last = tree.getLeadSelectionPath().getLastPathComponent();
3061:
3062: if (e.getActionCommand().equals("selectParent"))
3063: {
3064: TreePath path = new TreePath(getPathToRoot(last, 0));
3065: Object p = getParent(treeModel.getRoot(), last);
3066:
3067: if (!treeModel.isLeaf(last))
3068: toggleExpandState(path);
3069: else if (p != null)
3070: selectPath(tree, new TreePath(getPathToRoot(p, 0)));
3071: }
3072: else if (e.getActionCommand().equals("selectChild"))
3073: {
3074: TreePath path = new TreePath(getPathToRoot(last, 0));
3075:
3076: if (!treeModel.isLeaf(last))
3077: toggleExpandState(path);
3078: else
3079: {
3080: Object next = getNextVisibleNode(last);
3081:
3082: if (next != null)
3083: selectPath(tree, new TreePath(getPathToRoot(next, 0)));
3084: }
3085: }
3086: }
3087:
3088:
3093: public boolean isEnabled()
3094: {
3095:
3096: return false;
3097: }
3098: }
3099:
3100:
3106: boolean hasControlIcons()
3107: {
3108: if (expandedIcon != null || collapsedIcon != null)
3109: return true;
3110: return false;
3111: }
3112:
3113:
3119: Icon getCurrentControlIcon(TreePath path)
3120: {
3121: if (tree.isExpanded(path))
3122: return expandedIcon;
3123: return collapsedIcon;
3124: }
3125:
3126:
3135: Object getParent(Object root, Object node)
3136: {
3137: if (root == null || node == null || root.equals(node))
3138: return null;
3139:
3140: if (node instanceof TreeNode)
3141: return ((TreeNode) node).getParent();
3142: return findNode(root, node);
3143: }
3144:
3145:
3154: private Object findNode(Object root, Object node)
3155: {
3156: if (!treeModel.isLeaf(root) && !root.equals(node))
3157: {
3158: int size = treeModel.getChildCount(root);
3159: for (int j = 0; j < size; j++)
3160: {
3161: Object child = treeModel.getChild(root, j);
3162: if (node.equals(child))
3163: return root;
3164:
3165: Object n = findNode(child, node);
3166: if (n != null)
3167: return n;
3168: }
3169: }
3170: return null;
3171: }
3172:
3173:
3182: Object getPreviousVisibleNode(Object node)
3183: {
3184: if (currentVisiblePath != null)
3185: {
3186: Object[] nodes = currentVisiblePath.getPath();
3187: int i = 0;
3188: while (i < nodes.length && !node.equals(nodes[i]))
3189: i++;
3190:
3191: if (i - 1 >= 0)
3192: return nodes[i - 1];
3193: }
3194: return null;
3195: }
3196:
3197:
3204: Object getNextNode(Object curr)
3205: {
3206: if (!treeModel.isLeaf(curr) && treeModel.getChildCount(curr) > 0)
3207: return treeModel.getChild(curr, 0);
3208:
3209: Object node = curr;
3210: Object sibling = null;
3211: do
3212: {
3213: sibling = getNextSibling(node);
3214: node = getParent(treeModel.getRoot(), node);
3215: }
3216: while (sibling == null && node != null);
3217:
3218: return sibling;
3219: }
3220:
3221:
3229: Object getPreviousNode(Object node)
3230: {
3231: Object parent = getParent(treeModel.getRoot(), node);
3232: if (parent == null)
3233: return null;
3234:
3235: Object sibling = getPreviousSibling(node);
3236:
3237: if (sibling == null)
3238: return parent;
3239:
3240: int size = 0;
3241: if (!treeModel.isLeaf(sibling))
3242: size = treeModel.getChildCount(sibling);
3243: while (size > 0)
3244: {
3245: sibling = treeModel.getChild(sibling, size - 1);
3246: if (!treeModel.isLeaf(sibling))
3247: size = treeModel.getChildCount(sibling);
3248: else
3249: size = 0;
3250: }
3251:
3252: return sibling;
3253: }
3254:
3255:
3263: Object getNextSibling(Object node)
3264: {
3265: Object parent = getParent(treeModel.getRoot(), node);
3266: if (parent == null)
3267: return null;
3268:
3269: int index = treeModel.getIndexOfChild(parent, node) + 1;
3270:
3271: int size = 0;
3272: if (!treeModel.isLeaf(parent))
3273: size = treeModel.getChildCount(parent);
3274: if (index == 0 || index >= size)
3275: return null;
3276:
3277: return treeModel.getChild(parent, index);
3278: }
3279:
3280:
3288: Object getPreviousSibling(Object node)
3289: {
3290: Object parent = getParent(treeModel.getRoot(), node);
3291: if (parent == null)
3292: return null;
3293:
3294: int index = treeModel.getIndexOfChild(parent, node) - 1;
3295:
3296: int size = 0;
3297: if (!treeModel.isLeaf(parent))
3298: size = treeModel.getChildCount(parent);
3299: if (index < 0 || index >= size)
3300: return null;
3301:
3302: return treeModel.getChild(parent, index);
3303: }
3304:
3305:
3314: void selectPath(JTree tree, TreePath path)
3315: {
3316: if (path != null)
3317: {
3318: if (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.SINGLE_TREE_SELECTION)
3319: {
3320: tree.getSelectionModel().clearSelection();
3321: tree.addSelectionPath(path);
3322: tree.setLeadSelectionPath(path);
3323: }
3324: else if (tree.getSelectionModel().getSelectionMode() == TreeSelectionModel.CONTIGUOUS_TREE_SELECTION)
3325: {
3326:
3327: }
3328: else
3329: {
3330: tree.addSelectionPath(path);
3331: tree.setLeadSelectionPath(path);
3332: tree.getSelectionModel().setSelectionMode(
3333: TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
3334: }
3335: }
3336: }
3337:
3338:
3348: Object[] getPathToRoot(Object node, int depth)
3349: {
3350: if (node == null)
3351: {
3352: if (depth == 0)
3353: return null;
3354:
3355: return new Object[depth];
3356: }
3357:
3358: Object[] path = getPathToRoot(getParent(treeModel.getRoot(), node),
3359: depth + 1);
3360: path[path.length - depth - 1] = node;
3361: return path;
3362: }
3363:
3364:
3371: int getLevel(Object node)
3372: {
3373: int count = -1;
3374:
3375: Object current = node;
3376:
3377: if (treeModel != null)
3378: {
3379: Object root = treeModel.getRoot();
3380: if (!tree.isRootVisible() && tree.isExpanded(new TreePath(root)))
3381: count--;
3382:
3383: do
3384: {
3385: current = getParent(root, current);
3386: count++;
3387: }
3388: while (current != null);
3389: }
3390: return count;
3391: }
3392:
3393:
3407: protected void paintVerticalLine(Graphics g, JComponent c, int x, int top,
3408: int bottom)
3409: {
3410:
3411: g.setColor(getHashColor());
3412: g.drawLine(x, top, x, bottom);
3413: }
3414:
3415:
3429: protected void paintHorizontalLine(Graphics g, JComponent c, int y, int left,
3430: int right)
3431: {
3432:
3433: g.setColor(getHashColor());
3434: g.drawLine(left, y, right, y);
3435: }
3436:
3437:
3451: protected void drawCentered(Component c, Graphics g, Icon icon, int x, int y)
3452: {
3453: x -= icon.getIconWidth() / 2;
3454: y -= icon.getIconHeight() / 2;
3455:
3456: if (x < 0)
3457: x = 0;
3458: if (y < 0)
3459: y = 0;
3460:
3461: icon.paintIcon(c, g, x, y);
3462: }
3463:
3464:
3476: protected void drawDashedHorizontalLine(Graphics g, int y, int x1, int x2)
3477: {
3478: g.setColor(getHashColor());
3479: for (int i = x1; i < x2; i += 2)
3480: g.drawLine(i, y, i + 1, y);
3481: }
3482:
3483:
3495: protected void drawDashedVerticalLine(Graphics g, int x, int y1, int y2)
3496: {
3497: g.setColor(getHashColor());
3498: for (int i = y1; i < y2; i += 2)
3499: g.drawLine(x, i, x, i + 1);
3500: }
3501:
3502:
3523: protected void paintExpandControl(Graphics g, Rectangle clipBounds,
3524: Insets insets, Rectangle bounds,
3525: TreePath path, int row, boolean isExpanded,
3526: boolean hasBeenExpanded, boolean isLeaf)
3527: {
3528: if (shouldPaintExpandControl(path, row, isExpanded, hasBeenExpanded, isLeaf))
3529: {
3530: Icon icon = getCurrentControlIcon(path);
3531: int iconW = icon.getIconWidth();
3532: int x = bounds.x - rightChildIndent + iconW / 2;
3533: if (x + iconW > bounds.x)
3534: x = bounds.x - rightChildIndent - gap;
3535: icon.paintIcon(tree, g, x, bounds.y + bounds.height / 2
3536: - icon.getIconHeight() / 2);
3537: }
3538: }
3539:
3540:
3562: protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds,
3563: Insets insets, Rectangle bounds,
3564: TreePath path, int row,
3565: boolean isExpanded,
3566: boolean hasBeenExpanded,
3567: boolean isLeaf)
3568: {
3569: if (row != 0)
3570: paintHorizontalLine(g, tree, bounds.y + bounds.height / 2, bounds.x - gap
3571: - 2, bounds.x);
3572: }
3573:
3574:
3585: protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds,
3586: Insets insets, TreePath path)
3587: {
3588: int max = tree.getVisibleRowCount();
3589: for (int i = 0; i < max; i++)
3590: {
3591: Object curr = path.getPathComponent(i);
3592: TreePath currPath = new TreePath(getPathToRoot(curr, 0));
3593: int numChild = treeModel.getChildCount(curr);
3594: if (numChild > 0 && tree.isExpanded(currPath))
3595: {
3596: Rectangle bounds = getPathBounds(tree, currPath);
3597: Rectangle lastChildBounds = getPathBounds(
3598: tree,
3599: new TreePath(
3600: getPathToRoot(
3601: treeModel.getChild(
3602: curr,
3603: numChild - 1),
3604: 0)));
3605: paintVerticalLine(g, tree, bounds.x + gap + 2, bounds.y
3606: + bounds.height - 2,
3607: lastChildBounds.y + lastChildBounds.height / 2);
3608: }
3609: }
3610: }
3611:
3612:
3633: protected void paintRow(Graphics g, Rectangle clipBounds, Insets insets,
3634: Rectangle bounds, TreePath path, int row,
3635: boolean isExpanded, boolean hasBeenExpanded,
3636: boolean isLeaf)
3637: {
3638: boolean selected = tree.isPathSelected(path);
3639: boolean hasIcons = false;
3640: Object node = path.getLastPathComponent();
3641:
3642: if (tree.isVisible(path))
3643: {
3644: if (!validCachedPreferredSize)
3645: updateCachedPreferredSize();
3646:
3647: paintExpandControl(g, clipBounds, insets, bounds, path, row,
3648: isExpanded, hasBeenExpanded, isLeaf);
3649:
3650: if (row != 0)
3651: bounds.x += gap;
3652: bounds.width = preferredSize.width + bounds.x;
3653: if (editingComponent != null && editingPath != null && isEditing(tree)
3654: && node.equals(editingPath.getLastPathComponent()))
3655: {
3656: rendererPane.paintComponent(g, editingComponent.getParent(), null,
3657: bounds);
3658: }
3659: else
3660: {
3661: TreeCellRenderer dtcr = tree.getCellRenderer();
3662: if (dtcr == null)
3663: dtcr = createDefaultCellRenderer();
3664:
3665: Component c = dtcr.getTreeCellRendererComponent(tree, node,
3666: selected,
3667: isExpanded, isLeaf,
3668: row,
3669: tree.hasFocus());
3670: rendererPane.paintComponent(g, c, c.getParent(), bounds);
3671: }
3672: }
3673: }
3674:
3675:
3678: protected void prepareForUIUninstall()
3679: {
3680:
3681: }
3682:
3683:
3698: protected boolean shouldPaintExpandControl(TreePath path, int row,
3699: boolean isExpanded,
3700: boolean hasBeenExpanded,
3701: boolean isLeaf)
3702: {
3703: Object node = path.getLastPathComponent();
3704: return (!isLeaf && getLevel(node) != 0 && hasControlIcons());
3705: }
3706:
3707:
3710: void updateCurrentVisiblePath()
3711: {
3712: if (treeModel == null)
3713: return;
3714:
3715: Object next = treeModel.getRoot();
3716: if (next == null)
3717: return;
3718:
3719: TreePath rootPath = new TreePath(next);
3720: Rectangle bounds = getPathBounds(tree, rootPath);
3721:
3722:
3723:
3724:
3725: if ((bounds.width == 0 && bounds.height == 0)
3726: || (!isRootVisible() && tree.isExpanded(new TreePath(next))))
3727: {
3728: next = getNextNode(next);
3729: rootPath = new TreePath(next);
3730: }
3731:
3732: Object root = next;
3733: TreePath current = null;
3734: while (next != null)
3735: {
3736: if (current == null)
3737: current = rootPath;
3738: else
3739: current = current.pathByAddingChild(next);
3740:
3741: do
3742: {
3743: TreePath path = new TreePath(getPathToRoot(next, 0));
3744: if ((tree.isVisible(path) && tree.isExpanded(path))
3745: || treeModel.isLeaf(next))
3746: next = getNextNode(next);
3747: else
3748: {
3749: Object pNext = next;
3750: next = getNextSibling(pNext);
3751:
3752: if (next == null)
3753: {
3754: Object parent = getParent(root, pNext);
3755: while (next == null && parent != null)
3756: {
3757: next = getNextSibling(parent);
3758: if (next == null)
3759: parent = getParent(root, parent);
3760: }
3761: }
3762: }
3763: }
3764: while (next != null
3765: && !tree.isVisible(new TreePath(getPathToRoot(next, 0))));
3766: }
3767:
3768: currentVisiblePath = current;
3769: tree.setVisibleRowCount(getRowCount(tree));
3770:
3771: if (tree.getSelectionModel() != null && tree.getSelectionCount() == 0
3772: && currentVisiblePath != null)
3773: selectPath(
3774: tree,
3775: new TreePath(
3776: getPathToRoot(
3777: currentVisiblePath.getPathComponent(0),
3778: 0)));
3779: }
3780:
3781:
3790: Object getNextVisibleNode(Object node)
3791: {
3792: if (currentVisiblePath != null)
3793: {
3794: Object[] nodes = currentVisiblePath.getPath();
3795: int i = 0;
3796: while (i < nodes.length && !node.equals(nodes[i]))
3797: i++;
3798:
3799: if (i + 1 < nodes.length)
3800: return nodes[i + 1];
3801: }
3802: return null;
3803: }
3804: }