1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43:
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: import ;
69: import ;
70: import ;
71: import ;
72:
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
120: extends TreeUI
121: {
122:
128: static int WAIT_TILL_EDITING = 900;
129:
130:
131: protected transient Icon collapsedIcon;
132:
133:
134: protected transient Icon expandedIcon;
135:
136:
137: protected int leftChildIndent;
138:
139:
142: protected int rightChildIndent;
143:
144:
148: protected int totalChildIndent;
149:
150:
151: protected int lastSelectedRow;
152:
153:
154: protected JTree tree;
155:
156:
157: protected transient TreeCellRenderer currentCellRenderer;
158:
159:
163: protected boolean createdRenderer;
164:
165:
166: protected transient TreeCellEditor cellEditor;
167:
168:
172: protected boolean createdCellEditor;
173:
174:
178: protected boolean stopEditingInCompleteEditing;
179:
180:
181: protected CellRendererPane rendererPane;
182:
183:
184: protected Dimension preferredSize;
185:
186:
187: protected Dimension preferredMinSize;
188:
189:
190: protected boolean validCachedPreferredSize;
191:
192:
193: protected AbstractLayoutCache treeState;
194:
195:
196: protected Hashtable drawingCache;
197:
198:
203: protected boolean largeModel;
204:
205:
206: protected AbstractLayoutCache.NodeDimensions nodeDimensions;
207:
208:
209: protected TreeModel treeModel;
210:
211:
212: protected TreeSelectionModel treeSelectionModel;
213:
214:
219: protected int depthOffset;
220:
221:
224: protected Component editingComponent;
225:
226:
227: protected TreePath editingPath;
228:
229:
233: protected int editingRow;
234:
235:
236: protected boolean editorHasDifferentSize;
237:
238:
239: TreeAction action;
240:
241:
242: boolean isEditing;
243:
244:
245: TreePath currentVisiblePath;
246:
247:
248: int gap = 4;
249:
250:
251: int maxHeight;
252:
253:
254: Color hashColor;
255:
256:
257: PropertyChangeListener propertyChangeListener;
258:
259: FocusListener focusListener;
260:
261: TreeSelectionListener treeSelectionListener;
262:
263: MouseListener mouseListener;
264:
265: KeyListener keyListener;
266:
267: PropertyChangeListener selectionModelPropertyChangeListener;
268:
269: ComponentListener componentListener;
270:
271: CellEditorListener cellEditorListener;
272:
273: TreeExpansionListener treeExpansionListener;
274:
275: TreeModelListener treeModelListener;
276:
277:
282: Timer startEditTimer;
283:
284:
287: static Icon nullIcon;
288:
289:
294: static final MouseEvent EDIT = new MouseEvent(new Label(), 7, 7, 7, 7, 7, 7,
295: false);
296:
297:
300: public BasicTreeUI()
301: {
302: validCachedPreferredSize = false;
303: drawingCache = new Hashtable();
304: nodeDimensions = createNodeDimensions();
305: configureLayoutCache();
306:
307: editingRow = - 1;
308: lastSelectedRow = - 1;
309: }
310:
311:
317: public static ComponentUI createUI(JComponent c)
318: {
319: return new BasicTreeUI();
320: }
321:
322:
327: protected Color getHashColor()
328: {
329: return hashColor;
330: }
331:
332:
337: protected void setHashColor(Color color)
338: {
339: hashColor = color;
340: }
341:
342:
347: public void setLeftChildIndent(int newAmount)
348: {
349: leftChildIndent = newAmount;
350: }
351:
352:
357: public int getLeftChildIndent()
358: {
359: return leftChildIndent;
360: }
361:
362:
367: public void setRightChildIndent(int newAmount)
368: {
369: rightChildIndent = newAmount;
370: }
371:
372:
377: public int getRightChildIndent()
378: {
379: return rightChildIndent;
380: }
381:
382:
387: public void setExpandedIcon(Icon newG)
388: {
389: expandedIcon = newG;
390: }
391:
392:
397: public Icon getExpandedIcon()
398: {
399: return expandedIcon;
400: }
401:
402:
407: public void setCollapsedIcon(Icon newG)
408: {
409: collapsedIcon = newG;
410: }
411:
412:
417: public Icon getCollapsedIcon()
418: {
419: return collapsedIcon;
420: }
421:
422:
427: protected void setLargeModel(boolean largeModel)
428: {
429: if (largeModel != this.largeModel)
430: {
431: tree.removeComponentListener(componentListener);
432: this.largeModel = largeModel;
433: tree.addComponentListener(componentListener);
434: }
435: }
436:
437:
442: protected boolean isLargeModel()
443: {
444: return largeModel;
445: }
446:
447:
452: protected void setRowHeight(int rowHeight)
453: {
454: if (rowHeight == 0)
455: rowHeight = getMaxHeight(tree);
456: treeState.setRowHeight(rowHeight);
457: }
458:
459:
464: protected int getRowHeight()
465: {
466: return tree.getRowHeight();
467: }
468:
469:
475: protected void setCellRenderer(TreeCellRenderer tcr)
476: {
477: currentCellRenderer = tcr;
478: updateRenderer();
479: }
480:
481:
487: protected TreeCellRenderer getCellRenderer()
488: {
489: if (currentCellRenderer != null)
490: return currentCellRenderer;
491:
492: return createDefaultCellRenderer();
493: }
494:
495:
500: protected void setModel(TreeModel model)
501: {
502: completeEditing();
503:
504: if (treeModel != null && treeModelListener != null)
505: treeModel.removeTreeModelListener(treeModelListener);
506:
507: treeModel = tree.getModel();
508:
509: if (treeModel != null && treeModelListener != null)
510: treeModel.addTreeModelListener(treeModelListener);
511:
512: if (treeState != null)
513: {
514: treeState.setModel(treeModel);
515: updateLayoutCacheExpandedNodes();
516: updateSize();
517: }
518: }
519:
520:
525: protected TreeModel getModel()
526: {
527: return treeModel;
528: }
529:
530:
535: protected void setRootVisible(boolean newValue)
536: {
537: tree.setRootVisible(newValue);
538: }
539:
540:
545: protected boolean isRootVisible()
546: {
547: return tree.isRootVisible();
548: }
549:
550:
555: protected void setShowsRootHandles(boolean newValue)
556: {
557: completeEditing();
558: updateDepthOffset();
559: if (treeState != null)
560: {
561: treeState.invalidateSizes();
562: updateSize();
563: }
564: }
565:
566:
571: protected boolean getShowsRootHandles()
572: {
573: return tree.getShowsRootHandles();
574: }
575:
576:
581: protected void setCellEditor(TreeCellEditor editor)
582: {
583: cellEditor = editor;
584: createdCellEditor = true;
585: }
586:
587:
592: protected TreeCellEditor getCellEditor()
593: {
594: return cellEditor;
595: }
596:
597:
602: protected void setEditable(boolean newValue)
603: {
604: tree.setEditable(newValue);
605: }
606:
607:
612: protected boolean isEditable()
613: {
614: return tree.isEditable();
615: }
616:
617:
623: protected void setSelectionModel(TreeSelectionModel newLSM)
624: {
625: if (newLSM != null)
626: {
627: treeSelectionModel = newLSM;
628: tree.setSelectionModel(treeSelectionModel);
629: }
630: }
631:
632:
637: protected TreeSelectionModel getSelectionModel()
638: {
639: return treeSelectionModel;
640: }
641:
642:
652: public Rectangle getPathBounds(JTree tree, TreePath path)
653: {
654: return treeState.getBounds(path, new Rectangle());
655: }
656:
657:
663: int getMaxHeight(JTree tree)
664: {
665: if (maxHeight != 0)
666: return maxHeight;
667:
668: Icon e = UIManager.getIcon("Tree.openIcon");
669: Icon c = UIManager.getIcon("Tree.closedIcon");
670: Icon l = UIManager.getIcon("Tree.leafIcon");
671: int rc = getRowCount(tree);
672: int iconHeight = 0;
673:
674: for (int row = 0; row < rc; row++)
675: {
676: if (isLeaf(row))
677: iconHeight = l.getIconHeight();
678: else if (tree.isExpanded(row))
679: iconHeight = e.getIconHeight();
680: else
681: iconHeight = c.getIconHeight();
682:
683: maxHeight = Math.max(maxHeight, iconHeight + gap);
684: }
685:
686: treeState.setRowHeight(maxHeight);
687: return maxHeight;
688: }
689:
690:
693: Icon getNodeIcon(TreePath path)
694: {
695: Object node = path.getLastPathComponent();
696: if (treeModel.isLeaf(node))
697: return UIManager.getIcon("Tree.leafIcon");
698: else if (treeState.getExpandedState(path))
699: return UIManager.getIcon("Tree.openIcon");
700: else
701: return UIManager.getIcon("Tree.closedIcon");
702: }
703:
704:
711: public TreePath getPathForRow(JTree tree, int row)
712: {
713: return treeState.getPathForRow(row);
714: }
715:
716:
726: public int getRowForPath(JTree tree, TreePath path)
727: {
728: return treeState.getRowForPath(path);
729: }
730:
731:
737: public int getRowCount(JTree tree)
738: {
739: return treeState.getRowCount();
740: }
741:
742:
753: public TreePath getClosestPathForLocation(JTree tree, int x, int y)
754: {
755: return treeState.getPathClosestTo(x, y);
756: }
757:
758:
765: public boolean isEditing(JTree tree)
766: {
767: return isEditing;
768: }
769:
770:
778: public boolean stopEditing(JTree tree)
779: {
780: if (isEditing(tree))
781: {
782: completeEditing(false, false, true);
783: finish();
784: }
785: return ! isEditing(tree);
786: }
787:
788:
793: public void cancelEditing(JTree tree)
794: {
795:
796:
797:
798: completeEditing(false, false, false);
799: finish();
800: }
801:
802:
809: public void startEditingAtPath(JTree tree, TreePath path)
810: {
811: startEditing(path, null);
812: }
813:
814:
820: public TreePath getEditingPath(JTree tree)
821: {
822: return editingPath;
823: }
824:
825:
829: protected void prepareForUIInstall()
830: {
831: lastSelectedRow = -1;
832: preferredSize = new Dimension();
833: largeModel = tree.isLargeModel();
834: preferredSize = new Dimension();
835: setModel(tree.getModel());
836: }
837:
838:
842: protected void completeUIInstall()
843: {
844: setShowsRootHandles(tree.getShowsRootHandles());
845: updateRenderer();
846: updateDepthOffset();
847: setSelectionModel(tree.getSelectionModel());
848: treeState = createLayoutCache();
849: treeSelectionModel.setRowMapper(treeState);
850: configureLayoutCache();
851: updateSize();
852: }
853:
854:
858: protected void completeUIUninstall()
859: {
860: tree = null;
861: }
862:
863:
866: protected void installComponents()
867: {
868: currentCellRenderer = createDefaultCellRenderer();
869: rendererPane = createCellRendererPane();
870: createdRenderer = true;
871: setCellRenderer(currentCellRenderer);
872: }
873:
874:
881: protected AbstractLayoutCache.NodeDimensions createNodeDimensions()
882: {
883: return new NodeDimensionsHandler();
884: }
885:
886:
892: protected PropertyChangeListener createPropertyChangeListener()
893: {
894: return new PropertyChangeHandler();
895: }
896:
897:
903: protected MouseListener createMouseListener()
904: {
905: return new MouseHandler();
906: }
907:
908:
914: protected FocusListener createFocusListener()
915: {
916: return new FocusHandler();
917: }
918:
919:
924: protected KeyListener createKeyListener()
925: {
926: return new KeyHandler();
927: }
928:
929:
936: protected PropertyChangeListener createSelectionModelPropertyChangeListener()
937: {
938: return new SelectionModelPropertyChangeHandler();
939: }
940:
941:
947: protected TreeSelectionListener createTreeSelectionListener()
948: {
949: return new TreeSelectionHandler();
950: }
951:
952:
957: protected CellEditorListener createCellEditorListener()
958: {
959: return new CellEditorHandler();
960: }
961:
962:
969: protected ComponentListener createComponentListener()
970: {
971: return new ComponentHandler();
972: }
973:
974:
980: protected TreeExpansionListener createTreeExpansionListener()
981: {
982: return new TreeExpansionHandler();
983: }
984:
985:
991: protected AbstractLayoutCache createLayoutCache()
992: {
993: return new VariableHeightLayoutCache();
994: }
995:
996:
1001: protected CellRendererPane createCellRendererPane()
1002: {
1003: return new CellRendererPane();
1004: }
1005:
1006:
1011: protected TreeCellEditor createDefaultCellEditor()
1012: {
1013: DefaultTreeCellEditor ed;
1014: if (currentCellRenderer != null
1015: && currentCellRenderer instanceof DefaultTreeCellRenderer)
1016: ed = new DefaultTreeCellEditor(tree,
1017: (DefaultTreeCellRenderer) currentCellRenderer);
1018: else
1019: ed = new DefaultTreeCellEditor(tree, null);
1020: return ed;
1021: }
1022:
1023:
1030: protected TreeCellRenderer createDefaultCellRenderer()
1031: {
1032: return new DefaultTreeCellRenderer();
1033: }
1034:
1035:
1040: protected TreeModelListener createTreeModelListener()
1041: {
1042: return new TreeModelHandler();
1043: }
1044:
1045:
1048: protected void uninstallListeners()
1049: {
1050: tree.removePropertyChangeListener(propertyChangeListener);
1051: tree.removeFocusListener(focusListener);
1052: tree.removeTreeSelectionListener(treeSelectionListener);
1053: tree.removeMouseListener(mouseListener);
1054: tree.removeKeyListener(keyListener);
1055: tree.removePropertyChangeListener(selectionModelPropertyChangeListener);
1056: tree.removeComponentListener(componentListener);
1057: tree.removeTreeExpansionListener(treeExpansionListener);
1058:
1059: TreeCellEditor tce = tree.getCellEditor();
1060: if (tce != null)
1061: tce.removeCellEditorListener(cellEditorListener);
1062: if (treeModel != null)
1063: treeModel.removeTreeModelListener(treeModelListener);
1064: }
1065:
1066:
1069: protected void uninstallKeyboardActions()
1070: {
1071: action = null;
1072: tree.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).setParent(
1073: null);
1074: tree.getActionMap().setParent(null);
1075: }
1076:
1077:
1080: protected void uninstallComponents()
1081: {
1082: currentCellRenderer = null;
1083: rendererPane = null;
1084: createdRenderer = false;
1085: setCellRenderer(currentCellRenderer);
1086: }
1087:
1088:
1094: protected int getVerticalLegBuffer()
1095: {
1096: return getRowHeight() / 2;
1097: }
1098:
1099:
1106: protected int getHorizontalLegBuffer()
1107: {
1108: return rightChildIndent / 2;
1109: }
1110:
1111:
1115: protected void updateLayoutCacheExpandedNodes()
1116: {
1117: if (treeModel != null && treeModel.getRoot() != null)
1118: updateExpandedDescendants(new TreePath(treeModel.getRoot()));
1119: }
1120:
1121:
1128: protected void updateExpandedDescendants(TreePath path)
1129: {
1130: Enumeration expanded = tree.getExpandedDescendants(path);
1131: while (expanded.hasMoreElements())
1132: treeState.setExpandedState((TreePath) expanded.nextElement(), true);
1133: }
1134:
1135:
1141: protected TreePath getLastChildPath(TreePath parent)
1142: {
1143: return (TreePath) parent.getLastPathComponent();
1144: }
1145:
1146:
1149: protected void updateDepthOffset()
1150: {
1151: depthOffset += getVerticalLegBuffer();
1152: }
1153:
1154:
1159: protected void updateCellEditor()
1160: {
1161: if (tree.isEditable() && cellEditor == null)
1162: setCellEditor(createDefaultCellEditor());
1163: createdCellEditor = true;
1164: }
1165:
1166:
1169: protected void updateRenderer()
1170: {
1171: if (tree != null)
1172: currentCellRenderer = tree.getCellRenderer();
1173:
1174: if (currentCellRenderer == null)
1175: currentCellRenderer = createDefaultCellRenderer();
1176:
1177: updateCellEditor();
1178: }
1179:
1180:
1185: protected void configureLayoutCache()
1186: {
1187: treeState = createLayoutCache();
1188: treeState.setNodeDimensions(nodeDimensions);
1189: }
1190:
1191:
1195: protected void updateSize()
1196: {
1197: preferredSize = null;
1198: updateCachedPreferredSize();
1199: tree.treeDidChange();
1200: }
1201:
1202:
1206: protected void updateCachedPreferredSize()
1207: {
1208: validCachedPreferredSize = false;
1209: }
1210:
1211:
1216: protected void pathWasExpanded(TreePath path)
1217: {
1218: validCachedPreferredSize = false;
1219: treeState.setExpandedState(path, true);
1220: tree.repaint();
1221: }
1222:
1223:
1226: protected void pathWasCollapsed(TreePath path)
1227: {
1228: validCachedPreferredSize = false;
1229: treeState.setExpandedState(path, false);
1230: tree.repaint();
1231: }
1232:
1233:
1236: protected void installDefaults()
1237: {
1238: LookAndFeel.installColorsAndFont(tree, "Tree.background",
1239: "Tree.foreground", "Tree.font");
1240: tree.setOpaque(true);
1241:
1242: rightChildIndent = UIManager.getInt("Tree.rightChildIndent");
1243: leftChildIndent = UIManager.getInt("Tree.leftChildIndent");
1244: totalChildIndent = rightChildIndent + leftChildIndent;
1245: setRowHeight(UIManager.getInt("Tree.rowHeight"));
1246: tree.setRowHeight(getRowHeight());
1247: tree.setScrollsOnExpand(UIManager.getBoolean("Tree.scrollsOnExpand"));
1248: setExpandedIcon(UIManager.getIcon("Tree.expandedIcon"));
1249: setCollapsedIcon(UIManager.getIcon("Tree.collapsedIcon"));
1250: }
1251:
1252:
1255: protected void installKeyboardActions()
1256: {
1257: InputMap focusInputMap =
1258: (InputMap) SharedUIDefaults.get("Tree.focusInputMap");
1259: SwingUtilities.replaceUIInputMap(tree, JComponent.WHEN_FOCUSED,
1260: focusInputMap);
1261: InputMap ancestorInputMap =
1262: (InputMap) SharedUIDefaults.get("Tree.ancestorInputMap");
1263: SwingUtilities.replaceUIInputMap(tree,
1264: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
1265: ancestorInputMap);
1266:
1267: action = new TreeAction();
1268:
1269: SwingUtilities.replaceUIActionMap(tree, getActionMap());
1270: }
1271:
1272:
1277: private ActionMap getActionMap()
1278: {
1279: ActionMap am = (ActionMap) UIManager.get("Tree.actionMap");
1280: if (am == null)
1281: {
1282: am = createDefaultActions();
1283: UIManager.getLookAndFeelDefaults().put("Tree.actionMap", am);
1284: }
1285: return am;
1286: }
1287:
1288:
1293: private ActionMap createDefaultActions()
1294: {
1295: ActionMapUIResource am = new ActionMapUIResource();
1296: Action action;
1297:
1298: action = new TreeAction();
1299: am.put(action.getValue(Action.NAME), action);
1300:
1301:
1302: action = new TreeHomeAction(-1, "selectFirst");
1303: am.put(action.getValue(Action.NAME), action);
1304: action = new TreeHomeAction(-1, "selectFirstChangeLead");
1305: am.put(action.getValue(Action.NAME), action);
1306: action = new TreeHomeAction(-1, "selectFirstExtendSelection");
1307: am.put(action.getValue(Action.NAME), action);
1308: action = new TreeHomeAction(1, "selectLast");
1309: am.put(action.getValue(Action.NAME), action);
1310: action = new TreeHomeAction(1, "selectLastChangeLead");
1311: am.put(action.getValue(Action.NAME), action);
1312: action = new TreeHomeAction(1, "selectLastExtendSelection");
1313: am.put(action.getValue(Action.NAME), action);
1314:
1315:
1316: action = new TreeIncrementAction(-1, "selectPrevious");
1317: am.put(action.getValue(Action.NAME), action);
1318: action = new TreeIncrementAction(-1, "selectPreviousExtendSelection");
1319: am.put(action.getValue(Action.NAME), action);
1320: action = new TreeIncrementAction(-1, "selectPreviousChangeLead");
1321: am.put(action.getValue(Action.NAME), action);
1322: action = new TreeIncrementAction(1, "selectNext");
1323: am.put(action.getValue(Action.NAME), action);
1324: action = new TreeIncrementAction(1, "selectNextExtendSelection");
1325: am.put(action.getValue(Action.NAME), action);
1326: action = new TreeIncrementAction(1, "selectNextChangeLead");
1327: am.put(action.getValue(Action.NAME), action);
1328:
1329:
1330: action = new TreeTraverseAction(-1, "selectParent");
1331: am.put(action.getValue(Action.NAME), action);
1332: action = new TreeTraverseAction(1, "selectChild");
1333: am.put(action.getValue(Action.NAME), action);
1334:
1335:
1336: action = new TreeToggleAction("toggleAndAnchor");
1337: am.put(action.getValue(Action.NAME), action);
1338:
1339:
1340: action = new TreePageAction(-1, "scrollUpChangeSelection");
1341: am.put(action.getValue(Action.NAME), action);
1342: action = new TreePageAction(-1, "scrollUpExtendSelection");
1343: am.put(action.getValue(Action.NAME), action);
1344: action = new TreePageAction(-1, "scrollUpChangeLead");
1345: am.put(action.getValue(Action.NAME), action);
1346: action = new TreePageAction(1, "scrollDownChangeSelection");
1347: am.put(action.getValue(Action.NAME), action);
1348: action = new TreePageAction(1, "scrollDownExtendSelection");
1349: am.put(action.getValue(Action.NAME), action);
1350: action = new TreePageAction(1, "scrollDownChangeLead");
1351: am.put(action.getValue(Action.NAME), action);
1352:
1353: return am;
1354: }
1355:
1356:
1362: private int convertModifiers(int mod)
1363: {
1364: if ((mod & KeyEvent.SHIFT_DOWN_MASK) != 0)
1365: {
1366: mod |= KeyEvent.SHIFT_MASK;
1367: mod &= ~ KeyEvent.SHIFT_DOWN_MASK;
1368: }
1369: if ((mod & KeyEvent.CTRL_DOWN_MASK) != 0)
1370: {
1371: mod |= KeyEvent.CTRL_MASK;
1372: mod &= ~ KeyEvent.CTRL_DOWN_MASK;
1373: }
1374: if ((mod & KeyEvent.META_DOWN_MASK) != 0)
1375: {
1376: mod |= KeyEvent.META_MASK;
1377: mod &= ~ KeyEvent.META_DOWN_MASK;
1378: }
1379: if ((mod & KeyEvent.ALT_DOWN_MASK) != 0)
1380: {
1381: mod |= KeyEvent.ALT_MASK;
1382: mod &= ~ KeyEvent.ALT_DOWN_MASK;
1383: }
1384: if ((mod & KeyEvent.ALT_GRAPH_DOWN_MASK) != 0)
1385: {
1386: mod |= KeyEvent.ALT_GRAPH_MASK;
1387: mod &= ~ KeyEvent.ALT_GRAPH_DOWN_MASK;
1388: }
1389: return mod;
1390: }
1391:
1392:
1395: protected void installListeners()
1396: {
1397: propertyChangeListener = createPropertyChangeListener();
1398: tree.addPropertyChangeListener(propertyChangeListener);
1399:
1400: focusListener = createFocusListener();
1401: tree.addFocusListener(focusListener);
1402:
1403: treeSelectionListener = createTreeSelectionListener();
1404: tree.addTreeSelectionListener(treeSelectionListener);
1405:
1406: mouseListener = createMouseListener();
1407: tree.addMouseListener(mouseListener);
1408:
1409: keyListener = createKeyListener();
1410: tree.addKeyListener(keyListener);
1411:
1412: selectionModelPropertyChangeListener =
1413: createSelectionModelPropertyChangeListener();
1414: if (treeSelectionModel != null
1415: && selectionModelPropertyChangeListener != null)
1416: {
1417: treeSelectionModel.addPropertyChangeListener(
1418: selectionModelPropertyChangeListener);
1419: }
1420:
1421: componentListener = createComponentListener();
1422: tree.addComponentListener(componentListener);
1423:
1424: treeExpansionListener = createTreeExpansionListener();
1425: tree.addTreeExpansionListener(treeExpansionListener);
1426:
1427: treeModelListener = createTreeModelListener();
1428: if (treeModel != null)
1429: treeModel.addTreeModelListener(treeModelListener);
1430:
1431: cellEditorListener = createCellEditorListener();
1432: }
1433:
1434:
1439: public void installUI(JComponent c)
1440: {
1441: tree = (JTree) c;
1442:
1443: prepareForUIInstall();
1444: installDefaults();
1445: installComponents();
1446: installKeyboardActions();
1447: installListeners();
1448: completeUIInstall();
1449: }
1450:
1451:
1454: protected void uninstallDefaults()
1455: {
1456: tree.setFont(null);
1457: tree.setForeground(null);
1458: tree.setBackground(null);
1459: }
1460:
1461:
1466: public void uninstallUI(JComponent c)
1467: {
1468: completeEditing();
1469:
1470: prepareForUIUninstall();
1471: uninstallDefaults();
1472: uninstallKeyboardActions();
1473: uninstallListeners();
1474: uninstallComponents();
1475: completeUIUninstall();
1476: }
1477:
1478:
1489: public void paint(Graphics g, JComponent c)
1490: {
1491: JTree tree = (JTree) c;
1492:
1493: int rows = treeState.getRowCount();
1494:
1495: if (rows == 0)
1496:
1497: return;
1498:
1499: Rectangle clip = g.getClipBounds();
1500:
1501: Insets insets = tree.getInsets();
1502:
1503: if (clip != null && treeModel != null)
1504: {
1505: int startIndex = tree.getClosestRowForLocation(clip.x, clip.y);
1506: int endIndex = tree.getClosestRowForLocation(clip.x + clip.width,
1507: clip.y + clip.height);
1508:
1509:
1510:
1511:
1512: if (endIndex < rows)
1513: for (int i = endIndex + 1; i < rows; i++)
1514: {
1515: TreePath path = treeState.getPathForRow(i);
1516: if (isLastChild(path))
1517: paintVerticalPartOfLeg(g, clip, insets, path);
1518: }
1519:
1520:
1521:
1522:
1523: int n = endIndex - startIndex + 1;
1524: Rectangle[] bounds = new Rectangle[n];
1525: boolean[] isLeaf = new boolean[n];
1526: boolean[] isExpanded = new boolean[n];
1527: TreePath[] path = new TreePath[n];
1528: int k;
1529:
1530: k = 0;
1531: for (int i = startIndex; i <= endIndex; i++, k++)
1532: {
1533: path[k] = treeState.getPathForRow(i);
1534: isLeaf[k] = treeModel.isLeaf(path[k].getLastPathComponent());
1535: isExpanded[k] = tree.isExpanded(path[k]);
1536: bounds[k] = getPathBounds(tree, path[k]);
1537:
1538: paintHorizontalPartOfLeg(g, clip, insets, bounds[k], path[k], i,
1539: isExpanded[k], false, isLeaf[k]);
1540: if (isLastChild(path[k]))
1541: paintVerticalPartOfLeg(g, clip, insets, path[k]);
1542: }
1543:
1544: k = 0;
1545: for (int i = startIndex; i <= endIndex; i++, k++)
1546: {
1547: paintRow(g, clip, insets, bounds[k], path[k], i, isExpanded[k],
1548: false, isLeaf[k]);
1549: }
1550: }
1551: }
1552:
1553:
1556: private boolean isLastChild(TreePath path)
1557: {
1558: if (path instanceof GnuPath)
1559: {
1560:
1561:
1562: return ((GnuPath) path).isLastChild;
1563: }
1564: else
1565: {
1566:
1567: TreePath parent = path.getParentPath();
1568: if (parent == null)
1569: return false;
1570: int childCount = treeState.getVisibleChildCount(parent);
1571: int p = treeModel.getIndexOfChild(parent, path.getLastPathComponent());
1572: return p == childCount - 1;
1573: }
1574: }
1575:
1576:
1582: protected void ensureRowsAreVisible(int beginRow, int endRow)
1583: {
1584: if (beginRow < endRow)
1585: {
1586: int temp = endRow;
1587: endRow = beginRow;
1588: beginRow = temp;
1589: }
1590:
1591: for (int i = beginRow; i < endRow; i++)
1592: {
1593: TreePath path = getPathForRow(tree, i);
1594: if (! tree.isVisible(path))
1595: tree.makeVisible(path);
1596: }
1597: }
1598:
1599:
1604: public void setPreferredMinSize(Dimension newSize)
1605: {
1606: preferredMinSize = newSize;
1607: }
1608:
1609:
1614: public Dimension getPreferredMinSize()
1615: {
1616: if (preferredMinSize == null)
1617: return getPreferredSize(tree);
1618: else
1619: return preferredMinSize;
1620: }
1621:
1622:
1631: public Dimension getPreferredSize(JComponent c)
1632: {
1633: return getPreferredSize(c, false);
1634: }
1635:
1636:
1644: public Dimension getPreferredSize(JComponent c, boolean checkConsistancy)
1645: {
1646: if (! validCachedPreferredSize)
1647: {
1648: Rectangle size = tree.getBounds();
1649:
1650: preferredSize = new Dimension(treeState.getPreferredWidth(size),
1651: treeState.getPreferredHeight());
1652: validCachedPreferredSize = true;
1653: }
1654: return preferredSize;
1655: }
1656:
1657:
1664: public Dimension getMinimumSize(JComponent c)
1665: {
1666: return preferredMinSize = getPreferredSize(c);
1667: }
1668:
1669:
1676: public Dimension getMaximumSize(JComponent c)
1677: {
1678: return getPreferredSize(c);
1679: }
1680:
1681:
1688: protected void completeEditing()
1689: {
1690: completeEditing(false, true, false);
1691: }
1692:
1693:
1703: protected void completeEditing(boolean messageStop, boolean messageCancel,
1704: boolean messageTree)
1705: {
1706: if (! stopEditingInCompleteEditing || editingComponent == null)
1707: return;
1708:
1709: if (messageStop)
1710: {
1711: getCellEditor().stopCellEditing();
1712: stopEditingInCompleteEditing = true;
1713: }
1714:
1715: if (messageCancel)
1716: {
1717: getCellEditor().cancelCellEditing();
1718: stopEditingInCompleteEditing = true;
1719: }
1720:
1721: if (messageTree)
1722: {
1723: TreeCellEditor editor = getCellEditor();
1724: if (editor != null)
1725: {
1726: Object value = editor.getCellEditorValue();
1727: treeModel.valueForPathChanged(tree.getLeadSelectionPath(), value);
1728: }
1729: }
1730: }
1731:
1732:
1740: protected boolean startEditing(TreePath path, MouseEvent event)
1741: {
1742: updateCellEditor();
1743: TreeCellEditor ed = getCellEditor();
1744:
1745: if (ed != null && (event == EDIT || ed.shouldSelectCell(event))
1746: && ed.isCellEditable(event))
1747: {
1748: Rectangle bounds = getPathBounds(tree, path);
1749:
1750:
1751: bounds.width = tree.getWidth() - bounds.x;
1752:
1753: editingPath = path;
1754: editingRow = tree.getRowForPath(editingPath);
1755:
1756: Object value = editingPath.getLastPathComponent();
1757:
1758: stopEditingInCompleteEditing = false;
1759: boolean expanded = tree.isExpanded(editingPath);
1760: isEditing = true;
1761: editingComponent = ed.getTreeCellEditorComponent(tree, value, true,
1762: expanded,
1763: isLeaf(editingRow),
1764: editingRow);
1765:
1766:
1767:
1768: tree.removeAll();
1769:
1770:
1771:
1772: Component container = editingComponent.getParent();
1773: container.setBounds(bounds);
1774: tree.add(container);
1775: editingComponent.requestFocus();
1776:
1777: return true;
1778: }
1779: return false;
1780: }
1781:
1782:
1790: protected void checkForClickInExpandControl(TreePath path, int mouseX,
1791: int mouseY)
1792: {
1793: if (isLocationInExpandControl(path, mouseX, mouseY))
1794: handleExpandControlClick(path, mouseX, mouseY);
1795: }
1796:
1797:
1809: protected boolean isLocationInExpandControl(TreePath path, int mouseX,
1810: int mouseY)
1811: {
1812: boolean cntlClick = false;
1813: if (! treeModel.isLeaf(path.getLastPathComponent()))
1814: {
1815: int width = 8;
1816: Icon expandedIcon = getExpandedIcon();
1817: if (expandedIcon != null)
1818: width = expandedIcon.getIconWidth();
1819:
1820: Insets i = tree.getInsets();
1821: int left = getRowX(tree.getRowForPath(path), path.getPathCount() - 1)
1822: - getRightChildIndent() - width / 2 + i.left;
1823: cntlClick = mouseX >= left && mouseX <= left + width;
1824: }
1825: return cntlClick;
1826: }
1827:
1828:
1836: protected void handleExpandControlClick(TreePath path, int mouseX, int mouseY)
1837: {
1838: toggleExpandState(path);
1839: }
1840:
1841:
1849: protected void toggleExpandState(TreePath path)
1850: {
1851: if (tree.isExpanded(path))
1852: tree.collapsePath(path);
1853: else
1854: tree.expandPath(path);
1855: }
1856:
1857:
1868: protected boolean isToggleSelectionEvent(MouseEvent event)
1869: {
1870: return
1871: (tree.getSelectionModel().getSelectionMode() !=
1872: TreeSelectionModel.SINGLE_TREE_SELECTION) &&
1873: ((event.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0);
1874: }
1875:
1876:
1887: protected boolean isMultiSelectEvent(MouseEvent event)
1888: {
1889: return
1890: (tree.getSelectionModel().getSelectionMode() !=
1891: TreeSelectionModel.SINGLE_TREE_SELECTION) &&
1892: ((event.getModifiersEx() & InputEvent.SHIFT_DOWN_MASK) != 0);
1893: }
1894:
1895:
1904: protected boolean isToggleEvent(MouseEvent event)
1905: {
1906: boolean toggle = false;
1907: if (SwingUtilities.isLeftMouseButton(event))
1908: {
1909: int clickCount = tree.getToggleClickCount();
1910: if (clickCount > 0 && event.getClickCount() == clickCount)
1911: toggle = true;
1912: }
1913: return toggle;
1914: }
1915:
1916:
1929: protected void selectPathForEvent(TreePath path, MouseEvent event)
1930: {
1931: if (isToggleSelectionEvent(event))
1932: {
1933:
1934: if (tree.isPathSelected(path))
1935: tree.removeSelectionPath(path);
1936: else
1937: {
1938: tree.addSelectionPath(path);
1939: tree.setAnchorSelectionPath(path);
1940: }
1941: }
1942: else if (isMultiSelectEvent(event))
1943: {
1944:
1945: TreePath anchor = tree.getAnchorSelectionPath();
1946: if (anchor != null)
1947: {
1948: int aRow = getRowForPath(tree, anchor);
1949: tree.addSelectionInterval(aRow, getRowForPath(tree, path));
1950: }
1951: else
1952: tree.addSelectionPath(path);
1953: }
1954: else
1955: {
1956:
1957: tree.setSelectionPath(path);
1958: if (isToggleEvent(event))
1959: toggleExpandState(path);
1960: }
1961: }
1962:
1963:
1969: protected boolean isLeaf(int row)
1970: {
1971: TreePath pathForRow = getPathForRow(tree, row);
1972: if (pathForRow == null)
1973: return true;
1974:
1975: Object node = pathForRow.getLastPathComponent();
1976: return treeModel.isLeaf(node);
1977: }
1978:
1979:
1984: class TreeAction
1985: extends AbstractAction
1986: {
1987:
1988:
1993: public void actionPerformed(ActionEvent e)
1994: {
1995: String command = e.getActionCommand();
1996: TreePath lead = tree.getLeadSelectionPath();
1997:
1998: if (command.equals("selectPreviousChangeLead")
1999: || command.equals("selectPreviousExtendSelection")
2000: || command.equals("selectPrevious") || command.equals("selectNext")
2001: || command.equals("selectNextExtendSelection")
2002: || command.equals("selectNextChangeLead"))
2003: (new TreeIncrementAction(0, "")).actionPerformed(e);
2004: else if (command.equals("selectParent") || command.equals("selectChild"))
2005: (new TreeTraverseAction(0, "")).actionPerformed(e);
2006: else if (command.equals("selectAll"))
2007: {
2008: TreePath[] paths = new TreePath[treeState.getRowCount()];
2009: for (int i = 0; i < paths.length; i++)
2010: paths[i] = treeState.getPathForRow(i);
2011: tree.addSelectionPaths(paths);
2012: }
2013: else if (command.equals("startEditing"))
2014: tree.startEditingAtPath(lead);
2015: else if (command.equals("toggle"))
2016: {
2017: if (tree.isEditing())
2018: tree.stopEditing();
2019: else
2020: {
2021: Object last = lead.getLastPathComponent();
2022: TreePath path = new TreePath(getPathToRoot(last, 0));
2023: if (! treeModel.isLeaf(last))
2024: toggleExpandState(path);
2025: }
2026: }
2027: else if (command.equals("clearSelection"))
2028: tree.clearSelection();
2029:
2030: if (tree.isEditing() && ! command.equals("startEditing"))
2031: tree.stopEditing();
2032:
2033: tree.scrollPathToVisible(tree.getLeadSelectionPath());
2034: }
2035: }
2036:
2037:
2044: private static class ActionListenerProxy
2045: extends AbstractAction
2046: {
2047: ActionListener target;
2048:
2049: String bindingCommandName;
2050:
2051: public ActionListenerProxy(ActionListener li, String cmd)
2052: {
2053: target = li;
2054: bindingCommandName = cmd;
2055: }
2056:
2057: public void actionPerformed(ActionEvent e)
2058: {
2059: ActionEvent derivedEvent = new ActionEvent(e.getSource(), e.getID(),
2060: bindingCommandName,
2061: e.getModifiers());
2062:
2063: target.actionPerformed(derivedEvent);
2064: }
2065: }
2066:
2067:
2070: public class ComponentHandler
2071: extends ComponentAdapter
2072: implements ActionListener
2073: {
2074:
2077: protected Timer timer;
2078:
2079:
2080: protected JScrollBar scrollBar;
2081:
2082:
2085: public ComponentHandler()
2086: {
2087:
2088: }
2089:
2090:
2095: public void componentMoved(ComponentEvent e)
2096: {
2097: if (timer == null)
2098: {
2099: JScrollPane scrollPane = getScrollPane();
2100: if (scrollPane == null)
2101: updateSize();
2102: else
2103: {
2104:
2105:
2106:
2107: scrollBar = scrollPane.getVerticalScrollBar();
2108: if (scrollBar == null || !scrollBar.getValueIsAdjusting())
2109: {
2110:
2111: scrollBar = scrollPane.getHorizontalScrollBar();
2112: if (scrollBar != null && scrollBar.getValueIsAdjusting())
2113: startTimer();
2114: else
2115: updateSize();
2116: }
2117: else
2118: {
2119: startTimer();
2120: }
2121: }
2122: }
2123: }
2124:
2125:
2129: protected void startTimer()
2130: {
2131: if (timer == null)
2132: {
2133: timer = new Timer(200, this);
2134: timer.setRepeats(true);
2135: }
2136: timer.start();
2137: }
2138:
2139:
2144: protected JScrollPane getScrollPane()
2145: {
2146: JScrollPane found = null;
2147: Component p = tree.getParent();
2148: while (p != null && !(p instanceof JScrollPane))
2149: p = p.getParent();
2150: if (p instanceof JScrollPane)
2151: found = (JScrollPane) p;
2152: return found;
2153: }
2154:
2155:
2161: public void actionPerformed(ActionEvent ae)
2162: {
2163: if (scrollBar == null || !scrollBar.getValueIsAdjusting())
2164: {
2165: if (timer != null)
2166: timer.stop();
2167: updateSize();
2168: timer = null;
2169: scrollBar = null;
2170: }
2171: }
2172: }
2173:
2174:
2178: public class CellEditorHandler
2179: implements CellEditorListener
2180: {
2181:
2184: public CellEditorHandler()
2185: {
2186:
2187: }
2188:
2189:
2195: public void editingStopped(ChangeEvent e)
2196: {
2197: stopEditing(tree);
2198: }
2199:
2200:
2206: public void editingCanceled(ChangeEvent e)
2207: {
2208: cancelEditing(tree);
2209: }
2210: }
2211:
2212:
2215: public class FocusHandler
2216: implements FocusListener
2217: {
2218:
2221: public FocusHandler()
2222: {
2223:
2224: }
2225:
2226:
2234: public void focusGained(FocusEvent e)
2235: {
2236: repaintLeadRow();
2237: }
2238:
2239:
2247: public void focusLost(FocusEvent e)
2248: {
2249: repaintLeadRow();
2250: }
2251:
2252:
2255: void repaintLeadRow()
2256: {
2257: TreePath lead = tree.getLeadSelectionPath();
2258: if (lead != null)
2259: tree.repaint(tree.getPathBounds(lead));
2260: }
2261: }
2262:
2263:
2267: public class KeyHandler
2268: extends KeyAdapter
2269: {
2270:
2271: protected Action repeatKeyAction;
2272:
2273:
2274: protected boolean isKeyDown;
2275:
2276:
2279: public KeyHandler()
2280: {
2281:
2282: }
2283:
2284:
2292: public void keyTyped(KeyEvent e)
2293: throws NotImplementedException
2294: {
2295:
2296: }
2297:
2298:
2303: public void keyPressed(KeyEvent e)
2304: throws NotImplementedException
2305: {
2306:
2307: }
2308:
2309:
2314: public void keyReleased(KeyEvent e)
2315: throws NotImplementedException
2316: {
2317:
2318: }
2319: }
2320:
2321:
2325: public class MouseHandler
2326: extends MouseAdapter
2327: implements MouseMotionListener
2328: {
2329:
2332: public MouseHandler()
2333: {
2334:
2335: }
2336:
2337:
2342: public void mousePressed(MouseEvent e)
2343: {
2344:
2345: if (tree != null && tree.isEnabled())
2346: {
2347:
2348: if (isEditing(tree) && tree.getInvokesStopCellEditing()
2349: && !stopEditing(tree))
2350: return;
2351:
2352: int x = e.getX();
2353: int y = e.getY();
2354: TreePath path = getClosestPathForLocation(tree, x, y);
2355:
2356: if (path != null)
2357: {
2358: Rectangle bounds = getPathBounds(tree, path);
2359: if (SwingUtilities.isLeftMouseButton(e))
2360: checkForClickInExpandControl(path, x, y);
2361:
2362: if (x > bounds.x && x <= (bounds.x + bounds.width))
2363: {
2364: if (! startEditing(path, e))
2365: selectPathForEvent(path, e);
2366: }
2367: }
2368: }
2369: }
2370:
2371:
2379: public void mouseDragged(MouseEvent e)
2380: throws NotImplementedException
2381: {
2382:
2383: }
2384:
2385:
2391: public void mouseMoved(MouseEvent e)
2392: throws NotImplementedException
2393: {
2394:
2395: }
2396:
2397:
2402: public void mouseReleased(MouseEvent e)
2403: throws NotImplementedException
2404: {
2405:
2406: }
2407: }
2408:
2409:
2414: public class MouseInputHandler
2415: implements MouseInputListener
2416: {
2417:
2418: protected Component source;
2419:
2420:
2421: protected Component destination;
2422:
2423:
2430: public MouseInputHandler(Component source, Component destination,
2431: MouseEvent e)
2432: {
2433: this.source = source;
2434: this.destination = destination;
2435: }
2436:
2437:
2443: public void mouseClicked(MouseEvent e)
2444: throws NotImplementedException
2445: {
2446:
2447: }
2448:
2449:
2454: public void mousePressed(MouseEvent e)
2455: throws NotImplementedException
2456: {
2457:
2458: }
2459:
2460:
2465: public void mouseReleased(MouseEvent e)
2466: throws NotImplementedException
2467: {
2468:
2469: }
2470:
2471:
2476: public void mouseEntered(MouseEvent e)
2477: throws NotImplementedException
2478: {
2479:
2480: }
2481:
2482:
2487: public void mouseExited(MouseEvent e)
2488: throws NotImplementedException
2489: {
2490:
2491: }
2492:
2493:
2501: public void mouseDragged(MouseEvent e)
2502: throws NotImplementedException
2503: {
2504:
2505: }
2506:
2507:
2513: public void mouseMoved(MouseEvent e)
2514: throws NotImplementedException
2515: {
2516:
2517: }
2518:
2519:
2522: protected void removeFromSource()
2523: throws NotImplementedException
2524: {
2525:
2526: }
2527: }
2528:
2529:
2534: public class NodeDimensionsHandler
2535: extends AbstractLayoutCache.NodeDimensions
2536: {
2537:
2540: public NodeDimensionsHandler()
2541: {
2542:
2543: }
2544:
2545:
2558: public Rectangle getNodeDimensions(Object cell, int row, int depth,
2559: boolean expanded, Rectangle size)
2560: {
2561: if (size == null || cell == null)
2562: return null;
2563:
2564: String s = cell.toString();
2565: Font f = tree.getFont();
2566: FontMetrics fm = tree.getToolkit().getFontMetrics(f);
2567:
2568: if (s != null)
2569: {
2570: TreePath path = treeState.getPathForRow(row);
2571: size.x = getRowX(row, depth);
2572: size.width = SwingUtilities.computeStringWidth(fm, s);
2573: size.width = size.width + getCurrentControlIcon(path).getIconWidth()
2574: + gap + getNodeIcon(path).getIconWidth();
2575: size.height = getMaxHeight(tree);
2576: size.y = size.height * row;
2577: }
2578:
2579: return size;
2580: }
2581:
2582:
2587: protected int getRowX(int row, int depth)
2588: {
2589: return BasicTreeUI.this.getRowX(row, depth);
2590: }
2591: }
2592:
2593:
2597: public class PropertyChangeHandler
2598: implements PropertyChangeListener
2599: {
2600:
2601:
2604: public PropertyChangeHandler()
2605: {
2606:
2607: }
2608:
2609:
2615: public void propertyChange(PropertyChangeEvent event)
2616: {
2617: String property = event.getPropertyName();
2618: if (property.equals(JTree.ROOT_VISIBLE_PROPERTY))
2619: {
2620: validCachedPreferredSize = false;
2621: treeState.setRootVisible(tree.isRootVisible());
2622: tree.repaint();
2623: }
2624: else if (property.equals(JTree.SELECTION_MODEL_PROPERTY))
2625: {
2626: treeSelectionModel = tree.getSelectionModel();
2627: treeSelectionModel.setRowMapper(treeState);
2628: }
2629: else if (property.equals(JTree.TREE_MODEL_PROPERTY))
2630: {
2631: setModel(tree.getModel());
2632: }
2633: else if (property.equals(JTree.CELL_RENDERER_PROPERTY))
2634: {
2635: setCellRenderer(tree.getCellRenderer());
2636:
2637: if (treeState != null)
2638: treeState.invalidateSizes();
2639: }
2640: }
2641: }
2642:
2643:
2647: public class SelectionModelPropertyChangeHandler
2648: implements PropertyChangeListener
2649: {
2650:
2651:
2654: public SelectionModelPropertyChangeHandler()
2655: {
2656:
2657: }
2658:
2659:
2665: public void propertyChange(PropertyChangeEvent event)
2666: throws NotImplementedException
2667: {
2668:
2669: }
2670: }
2671:
2672:
2675: public class TreeCancelEditingAction
2676: extends AbstractAction
2677: {
2678:
2683: public TreeCancelEditingAction(String name)
2684: {
2685: super(name);
2686: }
2687:
2688:
2694: public void actionPerformed(ActionEvent e)
2695: {
2696: if (isEnabled() && tree.isEditing())
2697: tree.cancelEditing();
2698: }
2699: }
2700:
2701:
2704: public class TreeExpansionHandler
2705: implements TreeExpansionListener
2706: {
2707:
2708:
2711: public TreeExpansionHandler()
2712: {
2713:
2714: }
2715:
2716:
2721: public void treeExpanded(TreeExpansionEvent event)
2722: {
2723: validCachedPreferredSize = false;
2724: treeState.setExpandedState(event.getPath(), true);
2725:
2726: maxHeight = 0;
2727: tree.revalidate();
2728: tree.repaint();
2729: }
2730:
2731:
2736: public void treeCollapsed(TreeExpansionEvent event)
2737: {
2738: validCachedPreferredSize = false;
2739: treeState.setExpandedState(event.getPath(), false);
2740:
2741: maxHeight = 0;
2742: tree.revalidate();
2743: tree.repaint();
2744: }
2745: }
2746:
2747:
2751: public class TreeHomeAction
2752: extends AbstractAction
2753: {
2754:
2755:
2756: protected int direction;
2757:
2758:
2765: public TreeHomeAction(int dir, String name)
2766: {
2767: direction = dir;
2768: putValue(Action.NAME, name);
2769: }
2770:
2771:
2776: public void actionPerformed(ActionEvent e)
2777: {
2778: if (tree != null)
2779: {
2780: String command = (String) getValue(Action.NAME);
2781: if (command.equals("selectFirst"))
2782: {
2783: ensureRowsAreVisible(0, 0);
2784: tree.setSelectionInterval(0, 0);
2785: }
2786: if (command.equals("selectFirstChangeLead"))
2787: {
2788: ensureRowsAreVisible(0, 0);
2789: tree.setLeadSelectionPath(getPathForRow(tree, 0));
2790: }
2791: if (command.equals("selectFirstExtendSelection"))
2792: {
2793: ensureRowsAreVisible(0, 0);
2794: TreePath anchorPath = tree.getAnchorSelectionPath();
2795: if (anchorPath == null)
2796: tree.setSelectionInterval(0, 0);
2797: else
2798: {
2799: int anchorRow = getRowForPath(tree, anchorPath);
2800: tree.setSelectionInterval(0, anchorRow);
2801: tree.setAnchorSelectionPath(anchorPath);
2802: tree.setLeadSelectionPath(getPathForRow(tree, 0));
2803: }
2804: }
2805: else if (command.equals("selectLast"))
2806: {
2807: int end = getRowCount(tree) - 1;
2808: ensureRowsAreVisible(end, end);
2809: tree.setSelectionInterval(end, end);
2810: }
2811: else if (command.equals("selectLastChangeLead"))
2812: {
2813: int end = getRowCount(tree) - 1;
2814: ensureRowsAreVisible(end, end);
2815: tree.setLeadSelectionPath(getPathForRow(tree, end));
2816: }
2817: else if (command.equals("selectLastExtendSelection"))
2818: {
2819: int end = getRowCount(tree) - 1;
2820: ensureRowsAreVisible(end, end);
2821: TreePath anchorPath = tree.getAnchorSelectionPath();
2822: if (anchorPath == null)
2823: tree.setSelectionInterval(end, end);
2824: else
2825: {
2826: int anchorRow = getRowForPath(tree, anchorPath);
2827: tree.setSelectionInterval(end, anchorRow);
2828: tree.setAnchorSelectionPath(anchorPath);
2829: tree.setLeadSelectionPath(getPathForRow(tree, end));
2830: }
2831: }
2832: }
2833: }
2834:
2835:
2840: public boolean isEnabled()
2841: {
2842: return (tree != null) && tree.isEnabled();
2843: }
2844: }
2845:
2846:
2850: public class TreeIncrementAction
2851: extends AbstractAction
2852: {
2853:
2854:
2857: protected int direction;
2858:
2859:
2865: public TreeIncrementAction(int dir, String name)
2866: {
2867: direction = dir;
2868: putValue(Action.NAME, name);
2869: }
2870:
2871:
2876: public void actionPerformed(ActionEvent e)
2877: {
2878: TreePath currentPath = tree.getLeadSelectionPath();
2879: int currentRow;
2880:
2881: if (currentPath != null)
2882: currentRow = treeState.getRowForPath(currentPath);
2883: else
2884: currentRow = 0;
2885:
2886: int rows = treeState.getRowCount();
2887:
2888: int nextRow = currentRow + 1;
2889: int prevRow = currentRow - 1;
2890: boolean hasNext = nextRow < rows;
2891: boolean hasPrev = prevRow >= 0 && rows > 0;
2892: TreePath newPath;
2893: String command = (String) getValue(Action.NAME);
2894:
2895: if (command.equals("selectPreviousChangeLead") && hasPrev)
2896: {
2897: newPath = treeState.getPathForRow(prevRow);
2898: tree.setSelectionPath(newPath);
2899: tree.setAnchorSelectionPath(newPath);
2900: tree.setLeadSelectionPath(newPath);
2901: }
2902: else if (command.equals("selectPreviousExtendSelection") && hasPrev)
2903: {
2904: newPath = treeState.getPathForRow(prevRow);
2905:
2906:
2907:
2908: if (tree.isPathSelected(newPath))
2909: tree.getSelectionModel().removeSelectionPath(currentPath);
2910:
2911:
2912:
2913: tree.addSelectionPath(newPath);
2914: tree.setLeadSelectionPath(newPath);
2915: }
2916: else if (command.equals("selectPrevious") && hasPrev)
2917: {
2918: newPath = treeState.getPathForRow(prevRow);
2919: tree.setSelectionPath(newPath);
2920: }
2921: else if (command.equals("selectNext") && hasNext)
2922: {
2923: newPath = treeState.getPathForRow(nextRow);
2924: tree.setSelectionPath(newPath);
2925: }
2926: else if (command.equals("selectNextExtendSelection") && hasNext)
2927: {
2928: newPath = treeState.getPathForRow(nextRow);
2929:
2930:
2931:
2932: if (tree.isPathSelected(newPath))
2933: tree.getSelectionModel().removeSelectionPath(currentPath);
2934:
2935:
2936:
2937: tree.addSelectionPath(newPath);
2938:
2939: tree.setLeadSelectionPath(newPath);
2940: }
2941: else if (command.equals("selectNextChangeLead") && hasNext)
2942: {
2943: newPath = treeState.getPathForRow(nextRow);
2944: tree.setSelectionPath(newPath);
2945: tree.setAnchorSelectionPath(newPath);
2946: tree.setLeadSelectionPath(newPath);
2947: }
2948: }
2949:
2950:
2955: public boolean isEnabled()
2956: {
2957: return (tree != null) && tree.isEnabled();
2958: }
2959: }
2960:
2961:
2964: public class TreeModelHandler
2965: implements TreeModelListener
2966: {
2967:
2970: public TreeModelHandler()
2971: {
2972:
2973: }
2974:
2975:
2987: public void treeNodesChanged(TreeModelEvent e)
2988: {
2989: validCachedPreferredSize = false;
2990: treeState.treeNodesChanged(e);
2991: tree.repaint();
2992: }
2993:
2994:
3001: public void treeNodesInserted(TreeModelEvent e)
3002: {
3003: validCachedPreferredSize = false;
3004: treeState.treeNodesInserted(e);
3005: tree.repaint();
3006: }
3007:
3008:
3018: public void treeNodesRemoved(TreeModelEvent e)
3019: {
3020: validCachedPreferredSize = false;
3021: treeState.treeNodesRemoved(e);
3022: tree.repaint();
3023: }
3024:
3025:
3034: public void treeStructureChanged(TreeModelEvent e)
3035: {
3036: if (e.getPath().length == 1
3037: && ! e.getPath()[0].equals(treeModel.getRoot()))
3038: tree.expandPath(new TreePath(treeModel.getRoot()));
3039: validCachedPreferredSize = false;
3040: treeState.treeStructureChanged(e);
3041: tree.repaint();
3042: }
3043: }
3044:
3045:
3048: public class TreePageAction
3049: extends AbstractAction
3050: {
3051:
3052: protected int direction;
3053:
3054:
3060: public TreePageAction(int direction, String name)
3061: {
3062: this.direction = direction;
3063: putValue(Action.NAME, name);
3064: }
3065:
3066:
3071: public void actionPerformed(ActionEvent e)
3072: {
3073: String command = (String) getValue(Action.NAME);
3074: boolean extendSelection = command.equals("scrollUpExtendSelection")
3075: || command.equals("scrollDownExtendSelection");
3076: boolean changeSelection = command.equals("scrollUpChangeSelection")
3077: || command.equals("scrollDownChangeSelection");
3078:
3079:
3080: if (!extendSelection && !changeSelection
3081: && tree.getSelectionModel().getSelectionMode() !=
3082: TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION)
3083: {
3084: changeSelection = true;
3085: }
3086:
3087: int rowCount = getRowCount(tree);
3088: if (rowCount > 0 && treeSelectionModel != null)
3089: {
3090: Dimension maxSize = tree.getSize();
3091: TreePath lead = tree.getLeadSelectionPath();
3092: TreePath newPath = null;
3093: Rectangle visible = tree.getVisibleRect();
3094: if (direction == -1)
3095: {
3096: newPath = getClosestPathForLocation(tree, visible.x, visible.y);
3097: if (newPath.equals(lead))
3098: {
3099: visible.y = Math.max(0, visible.y - visible.height);
3100: newPath = getClosestPathForLocation(tree, visible.x,
3101: visible.y);
3102: }
3103: }
3104: else
3105: {
3106: visible.y = Math.min(maxSize.height,
3107: visible.y + visible.height - 1);
3108: newPath = getClosestPathForLocation(tree, visible.x, visible.y);
3109: if (newPath.equals(lead))
3110: {
3111: visible.y = Math.min(maxSize.height,
3112: visible.y + visible.height - 1);
3113: newPath = getClosestPathForLocation(tree, visible.x,
3114: visible.y);
3115: }
3116: }
3117:
3118:
3119: Rectangle newVisible = getPathBounds(tree, newPath);
3120: newVisible.x = visible.x;
3121: newVisible.width = visible.width;
3122: if (direction == -1)
3123: {
3124: newVisible.height = visible.height;
3125: }
3126: else
3127: {
3128: newVisible.y -= visible.height - newVisible.height;
3129: newVisible.height = visible.height;
3130: }
3131:
3132: if (extendSelection)
3133: {
3134:
3135: TreePath anchorPath = tree.getAnchorSelectionPath();
3136: if (anchorPath == null)
3137: {
3138: tree.setSelectionPath(newPath);
3139: }
3140: else
3141: {
3142: int newIndex = getRowForPath(tree, newPath);
3143: int anchorIndex = getRowForPath(tree, anchorPath);
3144: tree.setSelectionInterval(Math.min(anchorIndex, newIndex),
3145: Math.max(anchorIndex, newIndex));
3146: tree.setAnchorSelectionPath(anchorPath);
3147: tree.setLeadSelectionPath(newPath);
3148: }
3149: }
3150: else if (changeSelection)
3151: {
3152: tree.setSelectionPath(newPath);
3153: }
3154: else
3155: {
3156: tree.setLeadSelectionPath(newPath);
3157: }
3158:
3159: tree.scrollRectToVisible(newVisible);
3160: }
3161: }
3162:
3163:
3168: public boolean isEnabled()
3169: {
3170: return (tree != null) && tree.isEnabled();
3171: }
3172: }
3173:
3174:
3178: public class TreeSelectionHandler
3179: implements TreeSelectionListener
3180: {
3181:
3184: public TreeSelectionHandler()
3185: {
3186:
3187: }
3188:
3189:
3195: public void valueChanged(TreeSelectionEvent event)
3196: {
3197: if (tree.isEditing())
3198: tree.cancelEditing();
3199:
3200: TreePath op = event.getOldLeadSelectionPath();
3201: TreePath np = event.getNewLeadSelectionPath();
3202:
3203:
3204: if (op != np)
3205: {
3206: Rectangle o = treeState.getBounds(event.getOldLeadSelectionPath(),
3207: new Rectangle());
3208: Rectangle n = treeState.getBounds(event.getNewLeadSelectionPath(),
3209: new Rectangle());
3210:
3211: if (o != null)
3212: tree.repaint(o);
3213: if (n != null)
3214: tree.repaint(n);
3215: }
3216: }
3217: }
3218:
3219:
3222: public class TreeToggleAction
3223: extends AbstractAction
3224: {
3225:
3230: public TreeToggleAction(String name)
3231: {
3232: putValue(Action.NAME, name);
3233: }
3234:
3235:
3240: public void actionPerformed(ActionEvent e)
3241: {
3242: int selected = tree.getLeadSelectionRow();
3243: if (selected != -1 && isLeaf(selected))
3244: {
3245: TreePath anchorPath = tree.getAnchorSelectionPath();
3246: TreePath leadPath = tree.getLeadSelectionPath();
3247: toggleExpandState(getPathForRow(tree, selected));
3248:
3249:
3250: tree.setLeadSelectionPath(leadPath);
3251: tree.setAnchorSelectionPath(anchorPath);
3252: }
3253: }
3254:
3255:
3260: public boolean isEnabled()
3261: {
3262: return (tree != null) && tree.isEnabled();
3263: }
3264: }
3265:
3266:
3270: public class TreeTraverseAction
3271: extends AbstractAction
3272: {
3273:
3276: protected int direction;
3277:
3278:
3284: public TreeTraverseAction(int direction, String name)
3285: {
3286: this.direction = direction;
3287: putValue(Action.NAME, name);
3288: }
3289:
3290:
3295: public void actionPerformed(ActionEvent e)
3296: {
3297: TreePath current = tree.getLeadSelectionPath();
3298: if (current == null)
3299: return;
3300:
3301: String command = (String) getValue(Action.NAME);
3302: if (command.equals("selectParent"))
3303: {
3304: if (current == null)
3305: return;
3306:
3307: if (tree.isExpanded(current))
3308: {
3309: tree.collapsePath(current);
3310: }
3311: else
3312: {
3313:
3314:
3315:
3316: TreePath parent = current.getParentPath();
3317: if (parent != null &&
3318: ! (parent.getPathCount() == 1 && ! tree.isRootVisible()))
3319: tree.setSelectionPath(parent);
3320: }
3321: }
3322: else if (command.equals("selectChild"))
3323: {
3324: Object node = current.getLastPathComponent();
3325: int nc = treeModel.getChildCount(node);
3326: if (nc == 0 || treeState.isExpanded(current))
3327: {
3328:
3329:
3330: int nextRow = tree.getLeadSelectionRow() + 1;
3331: if (nextRow <= tree.getRowCount())
3332: tree.setSelectionRow(nextRow);
3333: }
3334: else
3335: {
3336: tree.expandPath(current);
3337: }
3338: }
3339: }
3340:
3341:
3346: public boolean isEnabled()
3347: {
3348: return (tree != null) && tree.isEnabled();
3349: }
3350: }
3351:
3352:
3358: boolean hasControlIcons()
3359: {
3360: if (expandedIcon != null || collapsedIcon != null)
3361: return true;
3362: return false;
3363: }
3364:
3365:
3371: Icon getCurrentControlIcon(TreePath path)
3372: {
3373: if (hasControlIcons())
3374: {
3375: if (tree.isExpanded(path))
3376: return expandedIcon;
3377: else
3378: return collapsedIcon;
3379: }
3380: else
3381: {
3382: if (nullIcon == null)
3383: nullIcon = new Icon()
3384: {
3385: public int getIconHeight()
3386: {
3387: return 0;
3388: }
3389:
3390: public int getIconWidth()
3391: {
3392: return 0;
3393: }
3394:
3395: public void paintIcon(Component c, Graphics g, int x, int y)
3396: {
3397:
3398: }
3399: };
3400: return nullIcon;
3401: }
3402: }
3403:
3404:
3411: Object getParent(Object root, Object node)
3412: {
3413: if (root == null || node == null || root.equals(node))
3414: return null;
3415:
3416: if (node instanceof TreeNode)
3417: return ((TreeNode) node).getParent();
3418: return findNode(root, node);
3419: }
3420:
3421:
3428: private Object findNode(Object root, Object node)
3429: {
3430: if (! treeModel.isLeaf(root) && ! root.equals(node))
3431: {
3432: int size = treeModel.getChildCount(root);
3433: for (int j = 0; j < size; j++)
3434: {
3435: Object child = treeModel.getChild(root, j);
3436: if (node.equals(child))
3437: return root;
3438:
3439: Object n = findNode(child, node);
3440: if (n != null)
3441: return n;
3442: }
3443: }
3444: return null;
3445: }
3446:
3447:
3454: void selectPath(JTree tree, TreePath path)
3455: {
3456: if (path != null)
3457: {
3458: tree.setSelectionPath(path);
3459: tree.setLeadSelectionPath(path);
3460: tree.makeVisible(path);
3461: tree.scrollPathToVisible(path);
3462: }
3463: }
3464:
3465:
3473: Object[] getPathToRoot(Object node, int depth)
3474: {
3475: if (node == null)
3476: {
3477: if (depth == 0)
3478: return null;
3479:
3480: return new Object[depth];
3481: }
3482:
3483: Object[] path = getPathToRoot(getParent(treeModel.getRoot(), node),
3484: depth + 1);
3485: path[path.length - depth - 1] = node;
3486: return path;
3487: }
3488:
3489:
3498: protected void paintVerticalLine(Graphics g, JComponent c, int x, int top,
3499: int bottom)
3500: {
3501:
3502: g.setColor(getHashColor());
3503: g.drawLine(x, top, x, bottom);
3504: }
3505:
3506:
3515: protected void paintHorizontalLine(Graphics g, JComponent c, int y, int left,
3516: int right)
3517: {
3518:
3519: g.setColor(getHashColor());
3520: g.drawLine(left, y, right, y);
3521: }
3522:
3523:
3532: protected void drawCentered(Component c, Graphics g, Icon icon, int x, int y)
3533: {
3534: x -= icon.getIconWidth() / 2;
3535: y -= icon.getIconHeight() / 2;
3536:
3537: if (x < 0)
3538: x = 0;
3539: if (y < 0)
3540: y = 0;
3541:
3542: icon.paintIcon(c, g, x, y);
3543: }
3544:
3545:
3553: protected void drawDashedHorizontalLine(Graphics g, int y, int x1, int x2)
3554: {
3555: g.setColor(getHashColor());
3556: for (int i = x1; i < x2; i += 2)
3557: g.drawLine(i, y, i + 1, y);
3558: }
3559:
3560:
3568: protected void drawDashedVerticalLine(Graphics g, int x, int y1, int y2)
3569: {
3570: g.setColor(getHashColor());
3571: for (int i = y1; i < y2; i += 2)
3572: g.drawLine(x, i, x, i + 1);
3573: }
3574:
3575:
3589: protected void paintExpandControl(Graphics g, Rectangle clipBounds,
3590: Insets insets, Rectangle bounds,
3591: TreePath path, int row, boolean isExpanded,
3592: boolean hasBeenExpanded, boolean isLeaf)
3593: {
3594: if (shouldPaintExpandControl(path, row, isExpanded, hasBeenExpanded, isLeaf))
3595: {
3596: Icon icon = getCurrentControlIcon(path);
3597: int iconW = icon.getIconWidth();
3598: int x = bounds.x - iconW - gap;
3599: icon.paintIcon(tree, g, x, bounds.y + bounds.height / 2
3600: - icon.getIconHeight() / 2);
3601: }
3602: }
3603:
3604:
3619: protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds,
3620: Insets insets, Rectangle bounds,
3621: TreePath path, int row,
3622: boolean isExpanded,
3623: boolean hasBeenExpanded,
3624: boolean isLeaf)
3625: {
3626: if (row != 0)
3627: {
3628: paintHorizontalLine(g, tree, bounds.y + bounds.height / 2,
3629: bounds.x - leftChildIndent - gap, bounds.x - gap);
3630: }
3631: }
3632:
3633:
3642: protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds,
3643: Insets insets, TreePath path)
3644: {
3645: Rectangle bounds = getPathBounds(tree, path);
3646: TreePath parent = path.getParentPath();
3647: if (parent != null)
3648: {
3649: Rectangle parentBounds = getPathBounds(tree, parent);
3650: paintVerticalLine(g, tree, parentBounds.x + 2 * gap,
3651: parentBounds.y + parentBounds.height / 2,
3652: bounds.y + bounds.height / 2);
3653: }
3654: }
3655:
3656:
3670: protected void paintRow(Graphics g, Rectangle clipBounds, Insets insets,
3671: Rectangle bounds, TreePath path, int row,
3672: boolean isExpanded, boolean hasBeenExpanded,
3673: boolean isLeaf)
3674: {
3675: boolean selected = tree.isPathSelected(path);
3676: boolean hasIcons = false;
3677: Object node = path.getLastPathComponent();
3678:
3679: paintExpandControl(g, clipBounds, insets, bounds, path, row, isExpanded,
3680: hasBeenExpanded, isLeaf);
3681:
3682: TreeCellRenderer dtcr = currentCellRenderer;
3683:
3684: boolean focused = false;
3685: if (treeSelectionModel != null)
3686: focused = treeSelectionModel.getLeadSelectionRow() == row
3687: && tree.isFocusOwner();
3688:
3689: Component c = dtcr.getTreeCellRendererComponent(tree, node, selected,
3690: isExpanded, isLeaf, row,
3691: focused);
3692:
3693: rendererPane.paintComponent(g, c, c.getParent(), bounds);
3694: }
3695:
3696:
3699: protected void prepareForUIUninstall()
3700: {
3701:
3702: }
3703:
3704:
3714: protected boolean shouldPaintExpandControl(TreePath path, int row,
3715: boolean isExpanded,
3716: boolean hasBeenExpanded,
3717: boolean isLeaf)
3718: {
3719: Object node = path.getLastPathComponent();
3720: return ! isLeaf && hasControlIcons();
3721: }
3722:
3723:
3726: void finish()
3727: {
3728: treeState.invalidatePathBounds(treeState.getPathForRow(editingRow));
3729: editingPath = null;
3730: editingRow = - 1;
3731: stopEditingInCompleteEditing = false;
3732: isEditing = false;
3733: Rectangle bounds = editingComponent.getParent().getBounds();
3734: tree.removeAll();
3735: validCachedPreferredSize = false;
3736:
3737: tree.repaint(bounds);
3738: editingComponent = null;
3739: tree.requestFocus();
3740: }
3741:
3742:
3747: protected int getRowX(int row, int depth)
3748: {
3749: return depth * totalChildIndent;
3750: }
3751: }