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:
181: protected boolean stopEditingInCompleteEditing;
182:
183:
184: protected CellRendererPane rendererPane;
185:
186:
187: protected Dimension preferredSize;
188:
189:
190: protected Dimension preferredMinSize;
191:
192:
193: protected boolean validCachedPreferredSize;
194:
195:
196: protected AbstractLayoutCache treeState;
197:
198:
199: protected Hashtable drawingCache;
200:
201:
206: protected boolean largeModel;
207:
208:
209: protected AbstractLayoutCache.NodeDimensions nodeDimensions;
210:
211:
212: protected TreeModel treeModel;
213:
214:
215: protected TreeSelectionModel treeSelectionModel;
216:
217:
222: protected int depthOffset;
223:
224:
227: protected Component editingComponent;
228:
229:
230: protected TreePath editingPath;
231:
232:
236: protected int editingRow;
237:
238:
239: protected boolean editorHasDifferentSize;
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:
478: completeEditing();
479:
480:
481: updateRenderer();
482:
483:
484: if (treeState != null)
485: {
486: treeState.invalidateSizes();
487: updateSize();
488: }
489: }
490:
491:
497: protected TreeCellRenderer getCellRenderer()
498: {
499: if (currentCellRenderer != null)
500: return currentCellRenderer;
501:
502: return createDefaultCellRenderer();
503: }
504:
505:
510: protected void setModel(TreeModel model)
511: {
512: completeEditing();
513:
514: if (treeModel != null && treeModelListener != null)
515: treeModel.removeTreeModelListener(treeModelListener);
516:
517: treeModel = tree.getModel();
518:
519: if (treeModel != null && treeModelListener != null)
520: treeModel.addTreeModelListener(treeModelListener);
521:
522: if (treeState != null)
523: {
524: treeState.setModel(treeModel);
525: updateLayoutCacheExpandedNodes();
526: updateSize();
527: }
528: }
529:
530:
535: protected TreeModel getModel()
536: {
537: return treeModel;
538: }
539:
540:
545: protected void setRootVisible(boolean newValue)
546: {
547: tree.setRootVisible(newValue);
548: }
549:
550:
555: protected boolean isRootVisible()
556: {
557: return tree.isRootVisible();
558: }
559:
560:
565: protected void setShowsRootHandles(boolean newValue)
566: {
567: completeEditing();
568: updateDepthOffset();
569: if (treeState != null)
570: {
571: treeState.invalidateSizes();
572: updateSize();
573: }
574: }
575:
576:
581: protected boolean getShowsRootHandles()
582: {
583: return tree.getShowsRootHandles();
584: }
585:
586:
591: protected void setCellEditor(TreeCellEditor editor)
592: {
593: cellEditor = editor;
594: createdCellEditor = true;
595: }
596:
597:
602: protected TreeCellEditor getCellEditor()
603: {
604: return cellEditor;
605: }
606:
607:
612: protected void setEditable(boolean newValue)
613: {
614: tree.setEditable(newValue);
615: }
616:
617:
622: protected boolean isEditable()
623: {
624: return tree.isEditable();
625: }
626:
627:
633: protected void setSelectionModel(TreeSelectionModel newLSM)
634: {
635: if (newLSM != null)
636: {
637: treeSelectionModel = newLSM;
638: tree.setSelectionModel(treeSelectionModel);
639: }
640: }
641:
642:
647: protected TreeSelectionModel getSelectionModel()
648: {
649: return treeSelectionModel;
650: }
651:
652:
662: public Rectangle getPathBounds(JTree tree, TreePath path)
663: {
664: return treeState.getBounds(path, new Rectangle());
665: }
666:
667:
673: int getMaxHeight(JTree tree)
674: {
675: if (maxHeight != 0)
676: return maxHeight;
677:
678: Icon e = UIManager.getIcon("Tree.openIcon");
679: Icon c = UIManager.getIcon("Tree.closedIcon");
680: Icon l = UIManager.getIcon("Tree.leafIcon");
681: int rc = getRowCount(tree);
682: int iconHeight = 0;
683:
684: for (int row = 0; row < rc; row++)
685: {
686: if (isLeaf(row))
687: iconHeight = l.getIconHeight();
688: else if (tree.isExpanded(row))
689: iconHeight = e.getIconHeight();
690: else
691: iconHeight = c.getIconHeight();
692:
693: maxHeight = Math.max(maxHeight, iconHeight + gap);
694: }
695:
696: treeState.setRowHeight(maxHeight);
697: return maxHeight;
698: }
699:
700:
703: Icon getNodeIcon(TreePath path)
704: {
705: Object node = path.getLastPathComponent();
706: if (treeModel.isLeaf(node))
707: return UIManager.getIcon("Tree.leafIcon");
708: else if (treeState.getExpandedState(path))
709: return UIManager.getIcon("Tree.openIcon");
710: else
711: return UIManager.getIcon("Tree.closedIcon");
712: }
713:
714:
721: public TreePath getPathForRow(JTree tree, int row)
722: {
723: return treeState.getPathForRow(row);
724: }
725:
726:
736: public int getRowForPath(JTree tree, TreePath path)
737: {
738: return treeState.getRowForPath(path);
739: }
740:
741:
747: public int getRowCount(JTree tree)
748: {
749: return treeState.getRowCount();
750: }
751:
752:
763: public TreePath getClosestPathForLocation(JTree tree, int x, int y)
764: {
765: return treeState.getPathClosestTo(x, y);
766: }
767:
768:
775: public boolean isEditing(JTree tree)
776: {
777: return isEditing;
778: }
779:
780:
788: public boolean stopEditing(JTree tree)
789: {
790: if (isEditing(tree))
791: {
792: completeEditing(false, false, true);
793: finish();
794: }
795: return ! isEditing(tree);
796: }
797:
798:
803: public void cancelEditing(JTree tree)
804: {
805:
806:
807:
808: completeEditing(false, false, false);
809: finish();
810: }
811:
812:
819: public void startEditingAtPath(JTree tree, TreePath path)
820: {
821: startEditing(path, null);
822: }
823:
824:
830: public TreePath getEditingPath(JTree tree)
831: {
832: return editingPath;
833: }
834:
835:
839: protected void prepareForUIInstall()
840: {
841: lastSelectedRow = -1;
842: preferredSize = new Dimension();
843: largeModel = tree.isLargeModel();
844: preferredSize = new Dimension();
845: setModel(tree.getModel());
846: }
847:
848:
852: protected void completeUIInstall()
853: {
854: setShowsRootHandles(tree.getShowsRootHandles());
855: updateRenderer();
856: updateDepthOffset();
857: setSelectionModel(tree.getSelectionModel());
858: configureLayoutCache();
859: treeState.setRootVisible(tree.isRootVisible());
860: treeSelectionModel.setRowMapper(treeState);
861: updateSize();
862: }
863:
864:
868: protected void completeUIUninstall()
869: {
870: tree = null;
871: }
872:
873:
876: protected void installComponents()
877: {
878: currentCellRenderer = createDefaultCellRenderer();
879: rendererPane = createCellRendererPane();
880: createdRenderer = true;
881: setCellRenderer(currentCellRenderer);
882: }
883:
884:
891: protected AbstractLayoutCache.NodeDimensions createNodeDimensions()
892: {
893: return new NodeDimensionsHandler();
894: }
895:
896:
902: protected PropertyChangeListener createPropertyChangeListener()
903: {
904: return new PropertyChangeHandler();
905: }
906:
907:
913: protected MouseListener createMouseListener()
914: {
915: return new MouseHandler();
916: }
917:
918:
924: protected FocusListener createFocusListener()
925: {
926: return new FocusHandler();
927: }
928:
929:
934: protected KeyListener createKeyListener()
935: {
936: return new KeyHandler();
937: }
938:
939:
946: protected PropertyChangeListener createSelectionModelPropertyChangeListener()
947: {
948: return new SelectionModelPropertyChangeHandler();
949: }
950:
951:
957: protected TreeSelectionListener createTreeSelectionListener()
958: {
959: return new TreeSelectionHandler();
960: }
961:
962:
967: protected CellEditorListener createCellEditorListener()
968: {
969: return new CellEditorHandler();
970: }
971:
972:
979: protected ComponentListener createComponentListener()
980: {
981: return new ComponentHandler();
982: }
983:
984:
990: protected TreeExpansionListener createTreeExpansionListener()
991: {
992: return new TreeExpansionHandler();
993: }
994:
995:
1001: protected AbstractLayoutCache createLayoutCache()
1002: {
1003: return new VariableHeightLayoutCache();
1004: }
1005:
1006:
1011: protected CellRendererPane createCellRendererPane()
1012: {
1013: return new CellRendererPane();
1014: }
1015:
1016:
1021: protected TreeCellEditor createDefaultCellEditor()
1022: {
1023: DefaultTreeCellEditor ed;
1024: if (currentCellRenderer != null
1025: && currentCellRenderer instanceof DefaultTreeCellRenderer)
1026: ed = new DefaultTreeCellEditor(tree,
1027: (DefaultTreeCellRenderer) currentCellRenderer);
1028: else
1029: ed = new DefaultTreeCellEditor(tree, null);
1030: return ed;
1031: }
1032:
1033:
1040: protected TreeCellRenderer createDefaultCellRenderer()
1041: {
1042: return new DefaultTreeCellRenderer();
1043: }
1044:
1045:
1050: protected TreeModelListener createTreeModelListener()
1051: {
1052: return new TreeModelHandler();
1053: }
1054:
1055:
1058: protected void uninstallListeners()
1059: {
1060: tree.removePropertyChangeListener(propertyChangeListener);
1061: tree.removeFocusListener(focusListener);
1062: tree.removeTreeSelectionListener(treeSelectionListener);
1063: tree.removeMouseListener(mouseListener);
1064: tree.removeKeyListener(keyListener);
1065: tree.removePropertyChangeListener(selectionModelPropertyChangeListener);
1066: tree.removeComponentListener(componentListener);
1067: tree.removeTreeExpansionListener(treeExpansionListener);
1068:
1069: TreeCellEditor tce = tree.getCellEditor();
1070: if (tce != null)
1071: tce.removeCellEditorListener(cellEditorListener);
1072: if (treeModel != null)
1073: treeModel.removeTreeModelListener(treeModelListener);
1074: }
1075:
1076:
1079: protected void uninstallKeyboardActions()
1080: {
1081: tree.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).setParent(
1082: null);
1083: tree.getActionMap().setParent(null);
1084: }
1085:
1086:
1089: protected void uninstallComponents()
1090: {
1091: currentCellRenderer = null;
1092: rendererPane = null;
1093: createdRenderer = false;
1094: setCellRenderer(currentCellRenderer);
1095: }
1096:
1097:
1103: protected int getVerticalLegBuffer()
1104: {
1105: return getRowHeight() / 2;
1106: }
1107:
1108:
1115: protected int getHorizontalLegBuffer()
1116: {
1117: return rightChildIndent / 2;
1118: }
1119:
1120:
1124: protected void updateLayoutCacheExpandedNodes()
1125: {
1126: if (treeModel != null && treeModel.getRoot() != null)
1127: updateExpandedDescendants(new TreePath(treeModel.getRoot()));
1128: }
1129:
1130:
1137: protected void updateExpandedDescendants(TreePath path)
1138: {
1139: Enumeration expanded = tree.getExpandedDescendants(path);
1140: while (expanded.hasMoreElements())
1141: treeState.setExpandedState((TreePath) expanded.nextElement(), true);
1142: }
1143:
1144:
1150: protected TreePath getLastChildPath(TreePath parent)
1151: {
1152: return (TreePath) parent.getLastPathComponent();
1153: }
1154:
1155:
1158: protected void updateDepthOffset()
1159: {
1160: depthOffset += getVerticalLegBuffer();
1161: }
1162:
1163:
1168: protected void updateCellEditor()
1169: {
1170: if (tree.isEditable() && cellEditor == null)
1171: setCellEditor(createDefaultCellEditor());
1172: createdCellEditor = true;
1173: }
1174:
1175:
1178: protected void updateRenderer()
1179: {
1180: if (tree != null)
1181: {
1182: TreeCellRenderer rend = tree.getCellRenderer();
1183: if (rend != null)
1184: {
1185: createdRenderer = false;
1186: currentCellRenderer = rend;
1187: if (createdCellEditor)
1188: tree.setCellEditor(null);
1189: }
1190: else
1191: {
1192: tree.setCellRenderer(createDefaultCellRenderer());
1193: createdRenderer = true;
1194: }
1195: }
1196: else
1197: {
1198: currentCellRenderer = null;
1199: createdRenderer = false;
1200: }
1201:
1202: updateCellEditor();
1203: }
1204:
1205:
1210: protected void configureLayoutCache()
1211: {
1212: treeState = createLayoutCache();
1213: treeState.setNodeDimensions(nodeDimensions);
1214: }
1215:
1216:
1220: protected void updateSize()
1221: {
1222: preferredSize = null;
1223: updateCachedPreferredSize();
1224: tree.treeDidChange();
1225: }
1226:
1227:
1231: protected void updateCachedPreferredSize()
1232: {
1233: validCachedPreferredSize = false;
1234: }
1235:
1236:
1241: protected void pathWasExpanded(TreePath path)
1242: {
1243: validCachedPreferredSize = false;
1244: treeState.setExpandedState(path, true);
1245: tree.repaint();
1246: }
1247:
1248:
1251: protected void pathWasCollapsed(TreePath path)
1252: {
1253: validCachedPreferredSize = false;
1254: treeState.setExpandedState(path, false);
1255: tree.repaint();
1256: }
1257:
1258:
1261: protected void installDefaults()
1262: {
1263: LookAndFeel.installColorsAndFont(tree, "Tree.background",
1264: "Tree.foreground", "Tree.font");
1265:
1266: hashColor = UIManager.getColor("Tree.hash");
1267: if (hashColor == null)
1268: hashColor = Color.black;
1269:
1270: tree.setOpaque(true);
1271:
1272: rightChildIndent = UIManager.getInt("Tree.rightChildIndent");
1273: leftChildIndent = UIManager.getInt("Tree.leftChildIndent");
1274: totalChildIndent = rightChildIndent + leftChildIndent;
1275: setRowHeight(UIManager.getInt("Tree.rowHeight"));
1276: tree.setRowHeight(getRowHeight());
1277: tree.setScrollsOnExpand(UIManager.getBoolean("Tree.scrollsOnExpand"));
1278: setExpandedIcon(UIManager.getIcon("Tree.expandedIcon"));
1279: setCollapsedIcon(UIManager.getIcon("Tree.collapsedIcon"));
1280: }
1281:
1282:
1285: protected void installKeyboardActions()
1286: {
1287: InputMap focusInputMap =
1288: (InputMap) SharedUIDefaults.get("Tree.focusInputMap");
1289: SwingUtilities.replaceUIInputMap(tree, JComponent.WHEN_FOCUSED,
1290: focusInputMap);
1291: InputMap ancestorInputMap =
1292: (InputMap) SharedUIDefaults.get("Tree.ancestorInputMap");
1293: SwingUtilities.replaceUIInputMap(tree,
1294: JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
1295: ancestorInputMap);
1296:
1297: SwingUtilities.replaceUIActionMap(tree, getActionMap());
1298: }
1299:
1300:
1305: private ActionMap getActionMap()
1306: {
1307: ActionMap am = (ActionMap) UIManager.get("Tree.actionMap");
1308: if (am == null)
1309: {
1310: am = createDefaultActions();
1311: UIManager.getLookAndFeelDefaults().put("Tree.actionMap", am);
1312: }
1313: return am;
1314: }
1315:
1316:
1321: private ActionMap createDefaultActions()
1322: {
1323: ActionMapUIResource am = new ActionMapUIResource();
1324: Action action;
1325:
1326:
1327: action = new TreeHomeAction(-1, "selectFirst");
1328: am.put(action.getValue(Action.NAME), action);
1329: action = new TreeHomeAction(-1, "selectFirstChangeLead");
1330: am.put(action.getValue(Action.NAME), action);
1331: action = new TreeHomeAction(-1, "selectFirstExtendSelection");
1332: am.put(action.getValue(Action.NAME), action);
1333: action = new TreeHomeAction(1, "selectLast");
1334: am.put(action.getValue(Action.NAME), action);
1335: action = new TreeHomeAction(1, "selectLastChangeLead");
1336: am.put(action.getValue(Action.NAME), action);
1337: action = new TreeHomeAction(1, "selectLastExtendSelection");
1338: am.put(action.getValue(Action.NAME), action);
1339:
1340:
1341: action = new TreeIncrementAction(-1, "selectPrevious");
1342: am.put(action.getValue(Action.NAME), action);
1343: action = new TreeIncrementAction(-1, "selectPreviousExtendSelection");
1344: am.put(action.getValue(Action.NAME), action);
1345: action = new TreeIncrementAction(-1, "selectPreviousChangeLead");
1346: am.put(action.getValue(Action.NAME), action);
1347: action = new TreeIncrementAction(1, "selectNext");
1348: am.put(action.getValue(Action.NAME), action);
1349: action = new TreeIncrementAction(1, "selectNextExtendSelection");
1350: am.put(action.getValue(Action.NAME), action);
1351: action = new TreeIncrementAction(1, "selectNextChangeLead");
1352: am.put(action.getValue(Action.NAME), action);
1353:
1354:
1355: action = new TreeTraverseAction(-1, "selectParent");
1356: am.put(action.getValue(Action.NAME), action);
1357: action = new TreeTraverseAction(1, "selectChild");
1358: am.put(action.getValue(Action.NAME), action);
1359:
1360:
1361: action = new TreeToggleAction("toggleAndAnchor");
1362: am.put(action.getValue(Action.NAME), action);
1363:
1364:
1365: action = new TreePageAction(-1, "scrollUpChangeSelection");
1366: am.put(action.getValue(Action.NAME), action);
1367: action = new TreePageAction(-1, "scrollUpExtendSelection");
1368: am.put(action.getValue(Action.NAME), action);
1369: action = new TreePageAction(-1, "scrollUpChangeLead");
1370: am.put(action.getValue(Action.NAME), action);
1371: action = new TreePageAction(1, "scrollDownChangeSelection");
1372: am.put(action.getValue(Action.NAME), action);
1373: action = new TreePageAction(1, "scrollDownExtendSelection");
1374: am.put(action.getValue(Action.NAME), action);
1375: action = new TreePageAction(1, "scrollDownChangeLead");
1376: am.put(action.getValue(Action.NAME), action);
1377:
1378:
1379: action = new TreeStartEditingAction("startEditing");
1380: am.put(action.getValue(Action.NAME), action);
1381: action = new TreeCancelEditingAction("cancel");
1382: am.put(action.getValue(Action.NAME), action);
1383:
1384:
1385: return am;
1386: }
1387:
1388:
1394: private int convertModifiers(int mod)
1395: {
1396: if ((mod & KeyEvent.SHIFT_DOWN_MASK) != 0)
1397: {
1398: mod |= KeyEvent.SHIFT_MASK;
1399: mod &= ~ KeyEvent.SHIFT_DOWN_MASK;
1400: }
1401: if ((mod & KeyEvent.CTRL_DOWN_MASK) != 0)
1402: {
1403: mod |= KeyEvent.CTRL_MASK;
1404: mod &= ~ KeyEvent.CTRL_DOWN_MASK;
1405: }
1406: if ((mod & KeyEvent.META_DOWN_MASK) != 0)
1407: {
1408: mod |= KeyEvent.META_MASK;
1409: mod &= ~ KeyEvent.META_DOWN_MASK;
1410: }
1411: if ((mod & KeyEvent.ALT_DOWN_MASK) != 0)
1412: {
1413: mod |= KeyEvent.ALT_MASK;
1414: mod &= ~ KeyEvent.ALT_DOWN_MASK;
1415: }
1416: if ((mod & KeyEvent.ALT_GRAPH_DOWN_MASK) != 0)
1417: {
1418: mod |= KeyEvent.ALT_GRAPH_MASK;
1419: mod &= ~ KeyEvent.ALT_GRAPH_DOWN_MASK;
1420: }
1421: return mod;
1422: }
1423:
1424:
1427: protected void installListeners()
1428: {
1429: propertyChangeListener = createPropertyChangeListener();
1430: tree.addPropertyChangeListener(propertyChangeListener);
1431:
1432: focusListener = createFocusListener();
1433: tree.addFocusListener(focusListener);
1434:
1435: treeSelectionListener = createTreeSelectionListener();
1436: tree.addTreeSelectionListener(treeSelectionListener);
1437:
1438: mouseListener = createMouseListener();
1439: tree.addMouseListener(mouseListener);
1440:
1441: keyListener = createKeyListener();
1442: tree.addKeyListener(keyListener);
1443:
1444: selectionModelPropertyChangeListener =
1445: createSelectionModelPropertyChangeListener();
1446: if (treeSelectionModel != null
1447: && selectionModelPropertyChangeListener != null)
1448: {
1449: treeSelectionModel.addPropertyChangeListener(
1450: selectionModelPropertyChangeListener);
1451: }
1452:
1453: componentListener = createComponentListener();
1454: tree.addComponentListener(componentListener);
1455:
1456: treeExpansionListener = createTreeExpansionListener();
1457: tree.addTreeExpansionListener(treeExpansionListener);
1458:
1459: treeModelListener = createTreeModelListener();
1460: if (treeModel != null)
1461: treeModel.addTreeModelListener(treeModelListener);
1462:
1463: cellEditorListener = createCellEditorListener();
1464: }
1465:
1466:
1471: public void installUI(JComponent c)
1472: {
1473: tree = (JTree) c;
1474:
1475: prepareForUIInstall();
1476: installDefaults();
1477: installComponents();
1478: installKeyboardActions();
1479: installListeners();
1480: completeUIInstall();
1481: }
1482:
1483:
1486: protected void uninstallDefaults()
1487: {
1488: tree.setFont(null);
1489: tree.setForeground(null);
1490: tree.setBackground(null);
1491: }
1492:
1493:
1498: public void uninstallUI(JComponent c)
1499: {
1500: completeEditing();
1501:
1502: prepareForUIUninstall();
1503: uninstallDefaults();
1504: uninstallKeyboardActions();
1505: uninstallListeners();
1506: uninstallComponents();
1507: completeUIUninstall();
1508: }
1509:
1510:
1521: public void paint(Graphics g, JComponent c)
1522: {
1523: JTree tree = (JTree) c;
1524:
1525: int rows = treeState.getRowCount();
1526:
1527: if (rows == 0)
1528:
1529: return;
1530:
1531: Rectangle clip = g.getClipBounds();
1532:
1533: Insets insets = tree.getInsets();
1534:
1535: if (clip != null && treeModel != null)
1536: {
1537: int startIndex = tree.getClosestRowForLocation(clip.x, clip.y);
1538: int endIndex = tree.getClosestRowForLocation(clip.x + clip.width,
1539: clip.y + clip.height);
1540:
1541:
1542:
1543:
1544: if (endIndex < rows)
1545: for (int i = endIndex + 1; i < rows; i++)
1546: {
1547: TreePath path = treeState.getPathForRow(i);
1548: if (isLastChild(path))
1549: paintVerticalPartOfLeg(g, clip, insets, path);
1550: }
1551:
1552:
1553:
1554:
1555: int n = endIndex - startIndex + 1;
1556: Rectangle[] bounds = new Rectangle[n];
1557: boolean[] isLeaf = new boolean[n];
1558: boolean[] isExpanded = new boolean[n];
1559: TreePath[] path = new TreePath[n];
1560: int k;
1561:
1562: k = 0;
1563: for (int i = startIndex; i <= endIndex; i++, k++)
1564: {
1565: path[k] = treeState.getPathForRow(i);
1566: isLeaf[k] = treeModel.isLeaf(path[k].getLastPathComponent());
1567: isExpanded[k] = tree.isExpanded(path[k]);
1568: bounds[k] = getPathBounds(tree, path[k]);
1569:
1570: paintHorizontalPartOfLeg(g, clip, insets, bounds[k], path[k], i,
1571: isExpanded[k], false, isLeaf[k]);
1572: if (isLastChild(path[k]))
1573: paintVerticalPartOfLeg(g, clip, insets, path[k]);
1574: }
1575:
1576: k = 0;
1577: for (int i = startIndex; i <= endIndex; i++, k++)
1578: {
1579: paintRow(g, clip, insets, bounds[k], path[k], i, isExpanded[k],
1580: false, isLeaf[k]);
1581: }
1582: }
1583: }
1584:
1585:
1588: private boolean isLastChild(TreePath path)
1589: {
1590: if (path instanceof GnuPath)
1591: {
1592:
1593:
1594: return ((GnuPath) path).isLastChild;
1595: }
1596: else
1597: {
1598:
1599: TreePath parent = path.getParentPath();
1600: if (parent == null)
1601: return false;
1602: int childCount = treeState.getVisibleChildCount(parent);
1603: int p = treeModel.getIndexOfChild(parent, path.getLastPathComponent());
1604: return p == childCount - 1;
1605: }
1606: }
1607:
1608:
1614: protected void ensureRowsAreVisible(int beginRow, int endRow)
1615: {
1616: if (beginRow < endRow)
1617: {
1618: int temp = endRow;
1619: endRow = beginRow;
1620: beginRow = temp;
1621: }
1622:
1623: for (int i = beginRow; i < endRow; i++)
1624: {
1625: TreePath path = getPathForRow(tree, i);
1626: if (! tree.isVisible(path))
1627: tree.makeVisible(path);
1628: }
1629: }
1630:
1631:
1636: public void setPreferredMinSize(Dimension newSize)
1637: {
1638: preferredMinSize = newSize;
1639: }
1640:
1641:
1646: public Dimension getPreferredMinSize()
1647: {
1648: if (preferredMinSize == null)
1649: return getPreferredSize(tree);
1650: else
1651: return preferredMinSize;
1652: }
1653:
1654:
1663: public Dimension getPreferredSize(JComponent c)
1664: {
1665: return getPreferredSize(c, false);
1666: }
1667:
1668:
1676: public Dimension getPreferredSize(JComponent c, boolean checkConsistancy)
1677: {
1678: if (! validCachedPreferredSize)
1679: {
1680: Rectangle size = tree.getBounds();
1681:
1682: preferredSize = new Dimension(treeState.getPreferredWidth(size),
1683: treeState.getPreferredHeight());
1684: validCachedPreferredSize = true;
1685: }
1686: return preferredSize;
1687: }
1688:
1689:
1696: public Dimension getMinimumSize(JComponent c)
1697: {
1698: return preferredMinSize = getPreferredSize(c);
1699: }
1700:
1701:
1708: public Dimension getMaximumSize(JComponent c)
1709: {
1710: return getPreferredSize(c);
1711: }
1712:
1713:
1720: protected void completeEditing()
1721: {
1722: completeEditing(false, true, false);
1723: }
1724:
1725:
1735: protected void completeEditing(boolean messageStop, boolean messageCancel,
1736: boolean messageTree)
1737: {
1738:
1739: if (!isEditing(tree))
1740: return;
1741:
1742: if (messageStop)
1743: {
1744: getCellEditor().stopCellEditing();
1745: stopEditingInCompleteEditing = true;
1746: }
1747:
1748: if (messageCancel)
1749: {
1750: getCellEditor().cancelCellEditing();
1751: stopEditingInCompleteEditing = true;
1752: }
1753:
1754: if (messageTree)
1755: {
1756: TreeCellEditor editor = getCellEditor();
1757: if (editor != null)
1758: {
1759: Object value = editor.getCellEditorValue();
1760: treeModel.valueForPathChanged(tree.getLeadSelectionPath(), value);
1761: }
1762: }
1763: }
1764:
1765:
1773: protected boolean startEditing(TreePath path, MouseEvent event)
1774: {
1775: updateCellEditor();
1776: TreeCellEditor ed = getCellEditor();
1777:
1778: if (ed != null && (event == EDIT || ed.shouldSelectCell(event))
1779: && ed.isCellEditable(event))
1780: {
1781: Rectangle bounds = getPathBounds(tree, path);
1782:
1783:
1784: bounds.width = tree.getWidth() - bounds.x;
1785:
1786: editingPath = path;
1787: editingRow = tree.getRowForPath(editingPath);
1788:
1789: Object value = editingPath.getLastPathComponent();
1790:
1791: stopEditingInCompleteEditing = false;
1792: boolean expanded = tree.isExpanded(editingPath);
1793: isEditing = true;
1794: editingComponent = ed.getTreeCellEditorComponent(tree, value, true,
1795: expanded,
1796: isLeaf(editingRow),
1797: editingRow);
1798:
1799:
1800:
1801: tree.removeAll();
1802:
1803:
1804:
1805: Component container = editingComponent.getParent();
1806: container.setBounds(bounds);
1807: tree.add(container);
1808: editingComponent.requestFocus();
1809:
1810: return true;
1811: }
1812: return false;
1813: }
1814:
1815:
1823: protected void checkForClickInExpandControl(TreePath path, int mouseX,
1824: int mouseY)
1825: {
1826: if (isLocationInExpandControl(path, mouseX, mouseY))
1827: handleExpandControlClick(path, mouseX, mouseY);
1828: }
1829:
1830:
1842: protected boolean isLocationInExpandControl(TreePath path, int mouseX,
1843: int mouseY)
1844: {
1845: boolean cntlClick = false;
1846: if (! treeModel.isLeaf(path.getLastPathComponent()))
1847: {
1848: int width;
1849: Icon expandedIcon = getExpandedIcon();
1850: if (expandedIcon != null)
1851: width = expandedIcon.getIconWidth();
1852: else
1853:
1854:
1855: width = 18;
1856:
1857: Insets i = tree.getInsets();
1858:
1859: int depth;
1860: if (isRootVisible())
1861: depth = path.getPathCount()-1;
1862: else
1863: depth = path.getPathCount()-2;
1864:
1865: int left = getRowX(tree.getRowForPath(path), depth)
1866: - width + i.left;
1867: cntlClick = mouseX >= left && mouseX <= left + width;
1868: }
1869: return cntlClick;
1870: }
1871:
1872:
1880: protected void handleExpandControlClick(TreePath path, int mouseX, int mouseY)
1881: {
1882: toggleExpandState(path);
1883: }
1884:
1885:
1893: protected void toggleExpandState(TreePath path)
1894: {
1895:
1896: if (treeState.isExpanded(path))
1897: tree.collapsePath(path);
1898: else
1899: tree.expandPath(path);
1900: }
1901:
1902:
1913: protected boolean isToggleSelectionEvent(MouseEvent event)
1914: {
1915: return
1916: (tree.getSelectionModel().getSelectionMode() !=
1917: TreeSelectionModel.SINGLE_TREE_SELECTION) &&
1918: ((event.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0);
1919: }
1920:
1921:
1932: protected boolean isMultiSelectEvent(MouseEvent event)
1933: {
1934: return
1935: (tree.getSelectionModel().getSelectionMode() !=
1936: TreeSelectionModel.SINGLE_TREE_SELECTION) &&
1937: ((event.getModifiersEx() & InputEvent.SHIFT_DOWN_MASK) != 0);
1938: }
1939:
1940:
1949: protected boolean isToggleEvent(MouseEvent event)
1950: {
1951: boolean toggle = false;
1952: if (SwingUtilities.isLeftMouseButton(event))
1953: {
1954: int clickCount = tree.getToggleClickCount();
1955: if (clickCount > 0 && event.getClickCount() == clickCount)
1956: toggle = true;
1957: }
1958: return toggle;
1959: }
1960:
1961:
1974: protected void selectPathForEvent(TreePath path, MouseEvent event)
1975: {
1976: if (isToggleSelectionEvent(event))
1977: {
1978:
1979: if (tree.isPathSelected(path))
1980: tree.removeSelectionPath(path);
1981: else
1982: {
1983: tree.addSelectionPath(path);
1984: tree.setAnchorSelectionPath(path);
1985: }
1986: }
1987: else if (isMultiSelectEvent(event))
1988: {
1989:
1990: TreePath anchor = tree.getAnchorSelectionPath();
1991: if (anchor != null)
1992: {
1993: int aRow = getRowForPath(tree, anchor);
1994: tree.addSelectionInterval(aRow, getRowForPath(tree, path));
1995: }
1996: else
1997: tree.addSelectionPath(path);
1998: }
1999: else
2000: {
2001:
2002: tree.setSelectionPath(path);
2003: if (isToggleEvent(event))
2004: toggleExpandState(path);
2005: }
2006: }
2007:
2008:
2014: protected boolean isLeaf(int row)
2015: {
2016: TreePath pathForRow = getPathForRow(tree, row);
2017: if (pathForRow == null)
2018: return true;
2019:
2020: Object node = pathForRow.getLastPathComponent();
2021: return treeModel.isLeaf(node);
2022: }
2023:
2024:
2027: class TreeStartEditingAction
2028: extends AbstractAction
2029: {
2030:
2035: public TreeStartEditingAction(String name)
2036: {
2037: super(name);
2038: }
2039:
2040:
2045: public void actionPerformed(ActionEvent e)
2046: {
2047: TreePath lead = tree.getLeadSelectionPath();
2048: if (!tree.isEditing())
2049: tree.startEditingAtPath(lead);
2050: }
2051: }
2052:
2053:
2056: public class ComponentHandler
2057: extends ComponentAdapter
2058: implements ActionListener
2059: {
2060:
2063: protected Timer timer;
2064:
2065:
2066: protected JScrollBar scrollBar;
2067:
2068:
2071: public ComponentHandler()
2072: {
2073:
2074: }
2075:
2076:
2081: public void componentMoved(ComponentEvent e)
2082: {
2083: if (timer == null)
2084: {
2085: JScrollPane scrollPane = getScrollPane();
2086: if (scrollPane == null)
2087: updateSize();
2088: else
2089: {
2090:
2091:
2092:
2093: scrollBar = scrollPane.getVerticalScrollBar();
2094: if (scrollBar == null || !scrollBar.getValueIsAdjusting())
2095: {
2096:
2097: scrollBar = scrollPane.getHorizontalScrollBar();
2098: if (scrollBar != null && scrollBar.getValueIsAdjusting())
2099: startTimer();
2100: else
2101: updateSize();
2102: }
2103: else
2104: {
2105: startTimer();
2106: }
2107: }
2108: }
2109: }
2110:
2111:
2115: protected void startTimer()
2116: {
2117: if (timer == null)
2118: {
2119: timer = new Timer(200, this);
2120: timer.setRepeats(true);
2121: }
2122: timer.start();
2123: }
2124:
2125:
2130: protected JScrollPane getScrollPane()
2131: {
2132: JScrollPane found = null;
2133: Component p = tree.getParent();
2134: while (p != null && !(p instanceof JScrollPane))
2135: p = p.getParent();
2136: if (p instanceof JScrollPane)
2137: found = (JScrollPane) p;
2138: return found;
2139: }
2140:
2141:
2147: public void actionPerformed(ActionEvent ae)
2148: {
2149: if (scrollBar == null || !scrollBar.getValueIsAdjusting())
2150: {
2151: if (timer != null)
2152: timer.stop();
2153: updateSize();
2154: timer = null;
2155: scrollBar = null;
2156: }
2157: }
2158: }
2159:
2160:
2164: public class CellEditorHandler
2165: implements CellEditorListener
2166: {
2167:
2170: public CellEditorHandler()
2171: {
2172:
2173: }
2174:
2175:
2181: public void editingStopped(ChangeEvent e)
2182: {
2183: stopEditing(tree);
2184: }
2185:
2186:
2192: public void editingCanceled(ChangeEvent e)
2193: {
2194: cancelEditing(tree);
2195: }
2196: }
2197:
2198:
2201: public class FocusHandler
2202: implements FocusListener
2203: {
2204:
2207: public FocusHandler()
2208: {
2209:
2210: }
2211:
2212:
2220: public void focusGained(FocusEvent e)
2221: {
2222: repaintLeadRow();
2223: }
2224:
2225:
2233: public void focusLost(FocusEvent e)
2234: {
2235: repaintLeadRow();
2236: }
2237:
2238:
2241: void repaintLeadRow()
2242: {
2243: TreePath lead = tree.getLeadSelectionPath();
2244: if (lead != null)
2245: tree.repaint(tree.getPathBounds(lead));
2246: }
2247: }
2248:
2249:
2253: public class KeyHandler
2254: extends KeyAdapter
2255: {
2256:
2257: protected Action repeatKeyAction;
2258:
2259:
2260: protected boolean isKeyDown;
2261:
2262:
2265: public KeyHandler()
2266: {
2267:
2268: }
2269:
2270:
2278: public void keyTyped(KeyEvent e)
2279: {
2280: char typed = Character.toLowerCase(e.getKeyChar());
2281: for (int row = tree.getLeadSelectionRow() + 1;
2282: row < tree.getRowCount(); row++)
2283: {
2284: if (checkMatch(row, typed))
2285: {
2286: tree.setSelectionRow(row);
2287: tree.scrollRowToVisible(row);
2288: return;
2289: }
2290: }
2291:
2292:
2293: for (int row = 0; row < tree.getLeadSelectionRow(); row++)
2294: {
2295: if (checkMatch(row, typed))
2296: {
2297: tree.setSelectionRow(row);
2298: tree.scrollRowToVisible(row);
2299: return;
2300: }
2301: }
2302: }
2303:
2304:
2311: boolean checkMatch(int row, char typed)
2312: {
2313: TreePath path = treeState.getPathForRow(row);
2314: String node = path.getLastPathComponent().toString();
2315: if (node.length() > 0)
2316: {
2317: char x = node.charAt(0);
2318: if (typed == Character.toLowerCase(x))
2319: return true;
2320: }
2321: return false;
2322: }
2323:
2324:
2329: public void keyPressed(KeyEvent e)
2330: {
2331:
2332: }
2333:
2334:
2339: public void keyReleased(KeyEvent e)
2340: {
2341:
2342: }
2343: }
2344:
2345:
2349: public class MouseHandler
2350: extends MouseAdapter
2351: implements MouseMotionListener
2352: {
2353:
2356: public MouseHandler()
2357: {
2358:
2359: }
2360:
2361:
2366: public void mousePressed(MouseEvent e)
2367: {
2368:
2369:
2370: if (startEditTimer != null)
2371: {
2372: startEditTimer.stop();
2373: startEditTimer = null;
2374: }
2375:
2376: if (tree != null && tree.isEnabled())
2377: {
2378:
2379:
2380: if (isEditing(tree))
2381: if (!stopEditing(tree))
2382:
2383: return;
2384:
2385: int x = e.getX();
2386: int y = e.getY();
2387: TreePath path = getClosestPathForLocation(tree, x, y);
2388:
2389: if (path != null)
2390: {
2391: Rectangle bounds = getPathBounds(tree, path);
2392: if (SwingUtilities.isLeftMouseButton(e))
2393: checkForClickInExpandControl(path, x, y);
2394:
2395: if (x > bounds.x && x <= (bounds.x + bounds.width))
2396: {
2397: TreePath currentLead = tree.getLeadSelectionPath();
2398: if (currentLead != null && currentLead.equals(path)
2399: && e.getClickCount() == 1 && tree.isEditable())
2400: {
2401:
2402: final TreePath editPath = path;
2403:
2404:
2405:
2406:
2407:
2408:
2409:
2410: if (startEditTimer != null)
2411: startEditTimer.stop();
2412:
2413: startEditTimer = new Timer(WAIT_TILL_EDITING,
2414: new ActionListener()
2415: {
2416: public void actionPerformed(ActionEvent e)
2417: {
2418: startEditing(editPath, EDIT);
2419: }
2420: });
2421:
2422: startEditTimer.setRepeats(false);
2423: startEditTimer.start();
2424: }
2425: else
2426: {
2427: if (e.getClickCount() == 2)
2428: toggleExpandState(path);
2429: else
2430: selectPathForEvent(path, e);
2431: }
2432: }
2433: }
2434: }
2435:
2436:
2437: tree.requestFocusInWindow();
2438: }
2439:
2440:
2448: public void mouseDragged(MouseEvent e)
2449: throws NotImplementedException
2450: {
2451:
2452: }
2453:
2454:
2460: public void mouseMoved(MouseEvent e)
2461: throws NotImplementedException
2462: {
2463:
2464: }
2465:
2466:
2471: public void mouseReleased(MouseEvent e)
2472: throws NotImplementedException
2473: {
2474:
2475: }
2476: }
2477:
2478:
2483: public class MouseInputHandler
2484: implements MouseInputListener
2485: {
2486:
2487: protected Component source;
2488:
2489:
2490: protected Component destination;
2491:
2492:
2499: public MouseInputHandler(Component source, Component destination,
2500: MouseEvent e)
2501: {
2502: this.source = source;
2503: this.destination = destination;
2504: }
2505:
2506:
2512: public void mouseClicked(MouseEvent e)
2513: throws NotImplementedException
2514: {
2515:
2516: }
2517:
2518:
2523: public void mousePressed(MouseEvent e)
2524: throws NotImplementedException
2525: {
2526:
2527: }
2528:
2529:
2534: public void mouseReleased(MouseEvent e)
2535: throws NotImplementedException
2536: {
2537:
2538: }
2539:
2540:
2545: public void mouseEntered(MouseEvent e)
2546: throws NotImplementedException
2547: {
2548:
2549: }
2550:
2551:
2556: public void mouseExited(MouseEvent e)
2557: throws NotImplementedException
2558: {
2559:
2560: }
2561:
2562:
2570: public void mouseDragged(MouseEvent e)
2571: throws NotImplementedException
2572: {
2573:
2574: }
2575:
2576:
2582: public void mouseMoved(MouseEvent e)
2583: throws NotImplementedException
2584: {
2585:
2586: }
2587:
2588:
2591: protected void removeFromSource()
2592: throws NotImplementedException
2593: {
2594:
2595: }
2596: }
2597:
2598:
2603: public class NodeDimensionsHandler
2604: extends AbstractLayoutCache.NodeDimensions
2605: {
2606:
2609: public NodeDimensionsHandler()
2610: {
2611:
2612: }
2613:
2614:
2627: public Rectangle getNodeDimensions(Object cell, int row, int depth,
2628: boolean expanded, Rectangle size)
2629: {
2630: if (size == null || cell == null)
2631: return null;
2632:
2633: String s = cell.toString();
2634: Font f = tree.getFont();
2635: FontMetrics fm = tree.getToolkit().getFontMetrics(f);
2636:
2637: if (s != null)
2638: {
2639: TreePath path = treeState.getPathForRow(row);
2640: size.x = getRowX(row, depth);
2641: size.width = SwingUtilities.computeStringWidth(fm, s);
2642: size.width = size.width + getCurrentControlIcon(path).getIconWidth()
2643: + gap + getNodeIcon(path).getIconWidth();
2644: size.height = getMaxHeight(tree);
2645: size.y = size.height * row;
2646: }
2647:
2648: return size;
2649: }
2650:
2651:
2656: protected int getRowX(int row, int depth)
2657: {
2658: return BasicTreeUI.this.getRowX(row, depth);
2659: }
2660: }
2661:
2662:
2666: public class PropertyChangeHandler
2667: implements PropertyChangeListener
2668: {
2669:
2670:
2673: public PropertyChangeHandler()
2674: {
2675:
2676: }
2677:
2678:
2684: public void propertyChange(PropertyChangeEvent event)
2685: {
2686: String property = event.getPropertyName();
2687: if (property.equals(JTree.ROOT_VISIBLE_PROPERTY))
2688: {
2689: validCachedPreferredSize = false;
2690: treeState.setRootVisible(tree.isRootVisible());
2691: tree.repaint();
2692: }
2693: else if (property.equals(JTree.SELECTION_MODEL_PROPERTY))
2694: {
2695: treeSelectionModel = tree.getSelectionModel();
2696: treeSelectionModel.setRowMapper(treeState);
2697: }
2698: else if (property.equals(JTree.TREE_MODEL_PROPERTY))
2699: {
2700: setModel(tree.getModel());
2701: }
2702: else if (property.equals(JTree.CELL_RENDERER_PROPERTY))
2703: {
2704: setCellRenderer(tree.getCellRenderer());
2705:
2706: if (treeState != null)
2707: treeState.invalidateSizes();
2708: }
2709: }
2710: }
2711:
2712:
2716: public class SelectionModelPropertyChangeHandler
2717: implements PropertyChangeListener
2718: {
2719:
2720:
2723: public SelectionModelPropertyChangeHandler()
2724: {
2725:
2726: }
2727:
2728:
2734: public void propertyChange(PropertyChangeEvent event)
2735: throws NotImplementedException
2736: {
2737:
2738: }
2739: }
2740:
2741:
2744: public class TreeCancelEditingAction
2745: extends AbstractAction
2746: {
2747:
2752: public TreeCancelEditingAction(String name)
2753: {
2754: super(name);
2755: }
2756:
2757:
2763: public void actionPerformed(ActionEvent e)
2764: {
2765: if (isEnabled() && tree.isEditing())
2766: tree.cancelEditing();
2767: }
2768: }
2769:
2770:
2773: public class TreeExpansionHandler
2774: implements TreeExpansionListener
2775: {
2776:
2777:
2780: public TreeExpansionHandler()
2781: {
2782:
2783: }
2784:
2785:
2790: public void treeExpanded(TreeExpansionEvent event)
2791: {
2792: validCachedPreferredSize = false;
2793: treeState.setExpandedState(event.getPath(), true);
2794:
2795: maxHeight = 0;
2796: tree.revalidate();
2797: tree.repaint();
2798: }
2799:
2800:
2805: public void treeCollapsed(TreeExpansionEvent event)
2806: {
2807: validCachedPreferredSize = false;
2808: treeState.setExpandedState(event.getPath(), false);
2809:
2810: maxHeight = 0;
2811: tree.revalidate();
2812: tree.repaint();
2813: }
2814: }
2815:
2816:
2820: public class TreeHomeAction
2821: extends AbstractAction
2822: {
2823:
2824:
2825: protected int direction;
2826:
2827:
2834: public TreeHomeAction(int dir, String name)
2835: {
2836: direction = dir;
2837: putValue(Action.NAME, name);
2838: }
2839:
2840:
2845: public void actionPerformed(ActionEvent e)
2846: {
2847: if (tree != null)
2848: {
2849: String command = (String) getValue(Action.NAME);
2850: if (command.equals("selectFirst"))
2851: {
2852: ensureRowsAreVisible(0, 0);
2853: tree.setSelectionInterval(0, 0);
2854: }
2855: if (command.equals("selectFirstChangeLead"))
2856: {
2857: ensureRowsAreVisible(0, 0);
2858: tree.setLeadSelectionPath(getPathForRow(tree, 0));
2859: }
2860: if (command.equals("selectFirstExtendSelection"))
2861: {
2862: ensureRowsAreVisible(0, 0);
2863: TreePath anchorPath = tree.getAnchorSelectionPath();
2864: if (anchorPath == null)
2865: tree.setSelectionInterval(0, 0);
2866: else
2867: {
2868: int anchorRow = getRowForPath(tree, anchorPath);
2869: tree.setSelectionInterval(0, anchorRow);
2870: tree.setAnchorSelectionPath(anchorPath);
2871: tree.setLeadSelectionPath(getPathForRow(tree, 0));
2872: }
2873: }
2874: else if (command.equals("selectLast"))
2875: {
2876: int end = getRowCount(tree) - 1;
2877: ensureRowsAreVisible(end, end);
2878: tree.setSelectionInterval(end, end);
2879: }
2880: else if (command.equals("selectLastChangeLead"))
2881: {
2882: int end = getRowCount(tree) - 1;
2883: ensureRowsAreVisible(end, end);
2884: tree.setLeadSelectionPath(getPathForRow(tree, end));
2885: }
2886: else if (command.equals("selectLastExtendSelection"))
2887: {
2888: int end = getRowCount(tree) - 1;
2889: ensureRowsAreVisible(end, end);
2890: TreePath anchorPath = tree.getAnchorSelectionPath();
2891: if (anchorPath == null)
2892: tree.setSelectionInterval(end, end);
2893: else
2894: {
2895: int anchorRow = getRowForPath(tree, anchorPath);
2896: tree.setSelectionInterval(end, anchorRow);
2897: tree.setAnchorSelectionPath(anchorPath);
2898: tree.setLeadSelectionPath(getPathForRow(tree, end));
2899: }
2900: }
2901: }
2902:
2903:
2904: tree.scrollPathToVisible(tree.getLeadSelectionPath());
2905: }
2906:
2907:
2912: public boolean isEnabled()
2913: {
2914: return (tree != null) && tree.isEnabled();
2915: }
2916: }
2917:
2918:
2922: public class TreeIncrementAction
2923: extends AbstractAction
2924: {
2925:
2926:
2929: protected int direction;
2930:
2931:
2937: public TreeIncrementAction(int dir, String name)
2938: {
2939: direction = dir;
2940: putValue(Action.NAME, name);
2941: }
2942:
2943:
2948: public void actionPerformed(ActionEvent e)
2949: {
2950: TreePath currentPath = tree.getLeadSelectionPath();
2951: int currentRow;
2952:
2953: if (currentPath != null)
2954: currentRow = treeState.getRowForPath(currentPath);
2955: else
2956: currentRow = 0;
2957:
2958: int rows = treeState.getRowCount();
2959:
2960: int nextRow = currentRow + 1;
2961: int prevRow = currentRow - 1;
2962: boolean hasNext = nextRow < rows;
2963: boolean hasPrev = prevRow >= 0 && rows > 0;
2964: TreePath newPath;
2965: String command = (String) getValue(Action.NAME);
2966:
2967: if (command.equals("selectPreviousChangeLead") && hasPrev)
2968: {
2969: newPath = treeState.getPathForRow(prevRow);
2970: tree.setSelectionPath(newPath);
2971: tree.setAnchorSelectionPath(newPath);
2972: tree.setLeadSelectionPath(newPath);
2973: }
2974: else if (command.equals("selectPreviousExtendSelection") && hasPrev)
2975: {
2976: newPath = treeState.getPathForRow(prevRow);
2977:
2978:
2979:
2980: if (tree.isPathSelected(newPath))
2981: tree.getSelectionModel().removeSelectionPath(currentPath);
2982:
2983:
2984:
2985: tree.addSelectionPath(newPath);
2986: tree.setLeadSelectionPath(newPath);
2987: }
2988: else if (command.equals("selectPrevious") && hasPrev)
2989: {
2990: newPath = treeState.getPathForRow(prevRow);
2991: tree.setSelectionPath(newPath);
2992: }
2993: else if (command.equals("selectNext") && hasNext)
2994: {
2995: newPath = treeState.getPathForRow(nextRow);
2996: tree.setSelectionPath(newPath);
2997: }
2998: else if (command.equals("selectNextExtendSelection") && hasNext)
2999: {
3000: newPath = treeState.getPathForRow(nextRow);
3001:
3002:
3003:
3004: if (tree.isPathSelected(newPath))
3005: tree.getSelectionModel().removeSelectionPath(currentPath);
3006:
3007:
3008:
3009: tree.addSelectionPath(newPath);
3010:
3011: tree.setLeadSelectionPath(newPath);
3012: }
3013: else if (command.equals("selectNextChangeLead") && hasNext)
3014: {
3015: newPath = treeState.getPathForRow(nextRow);
3016: tree.setSelectionPath(newPath);
3017: tree.setAnchorSelectionPath(newPath);
3018: tree.setLeadSelectionPath(newPath);
3019: }
3020:
3021:
3022: tree.scrollPathToVisible(tree.getLeadSelectionPath());
3023: }
3024:
3025:
3030: public boolean isEnabled()
3031: {
3032: return (tree != null) && tree.isEnabled();
3033: }
3034: }
3035:
3036:
3039: public class TreeModelHandler
3040: implements TreeModelListener
3041: {
3042:
3045: public TreeModelHandler()
3046: {
3047:
3048: }
3049:
3050:
3062: public void treeNodesChanged(TreeModelEvent e)
3063: {
3064: validCachedPreferredSize = false;
3065: treeState.treeNodesChanged(e);
3066: tree.repaint();
3067: }
3068:
3069:
3076: public void treeNodesInserted(TreeModelEvent e)
3077: {
3078: validCachedPreferredSize = false;
3079: treeState.treeNodesInserted(e);
3080: tree.repaint();
3081: }
3082:
3083:
3093: public void treeNodesRemoved(TreeModelEvent e)
3094: {
3095: validCachedPreferredSize = false;
3096: treeState.treeNodesRemoved(e);
3097: tree.repaint();
3098: }
3099:
3100:
3109: public void treeStructureChanged(TreeModelEvent e)
3110: {
3111: if (e.getPath().length == 1
3112: && ! e.getPath()[0].equals(treeModel.getRoot()))
3113: tree.expandPath(new TreePath(treeModel.getRoot()));
3114: validCachedPreferredSize = false;
3115: treeState.treeStructureChanged(e);
3116: tree.repaint();
3117: }
3118: }
3119:
3120:
3123: public class TreePageAction
3124: extends AbstractAction
3125: {
3126:
3127: protected int direction;
3128:
3129:
3135: public TreePageAction(int direction, String name)
3136: {
3137: this.direction = direction;
3138: putValue(Action.NAME, name);
3139: }
3140:
3141:
3146: public void actionPerformed(ActionEvent e)
3147: {
3148: String command = (String) getValue(Action.NAME);
3149: boolean extendSelection = command.equals("scrollUpExtendSelection")
3150: || command.equals("scrollDownExtendSelection");
3151: boolean changeSelection = command.equals("scrollUpChangeSelection")
3152: || command.equals("scrollDownChangeSelection");
3153:
3154:
3155: if (!extendSelection && !changeSelection
3156: && tree.getSelectionModel().getSelectionMode() !=
3157: TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION)
3158: {
3159: changeSelection = true;
3160: }
3161:
3162: int rowCount = getRowCount(tree);
3163: if (rowCount > 0 && treeSelectionModel != null)
3164: {
3165: Dimension maxSize = tree.getSize();
3166: TreePath lead = tree.getLeadSelectionPath();
3167: TreePath newPath = null;
3168: Rectangle visible = tree.getVisibleRect();
3169: if (direction == -1)
3170: {
3171: newPath = getClosestPathForLocation(tree, visible.x, visible.y);
3172: if (newPath.equals(lead))
3173: {
3174: visible.y = Math.max(0, visible.y - visible.height);
3175: newPath = getClosestPathForLocation(tree, visible.x,
3176: visible.y);
3177: }
3178: }
3179: else
3180: {
3181: visible.y = Math.min(maxSize.height,
3182: visible.y + visible.height - 1);
3183: newPath = getClosestPathForLocation(tree, visible.x, visible.y);
3184: if (newPath.equals(lead))
3185: {
3186: visible.y = Math.min(maxSize.height,
3187: visible.y + visible.height - 1);
3188: newPath = getClosestPathForLocation(tree, visible.x,
3189: visible.y);
3190: }
3191: }
3192:
3193:
3194: Rectangle newVisible = getPathBounds(tree, newPath);
3195: newVisible.x = visible.x;
3196: newVisible.width = visible.width;
3197: if (direction == -1)
3198: {
3199: newVisible.height = visible.height;
3200: }
3201: else
3202: {
3203: newVisible.y -= visible.height - newVisible.height;
3204: newVisible.height = visible.height;
3205: }
3206:
3207: if (extendSelection)
3208: {
3209:
3210: TreePath anchorPath = tree.getAnchorSelectionPath();
3211: if (anchorPath == null)
3212: {
3213: tree.setSelectionPath(newPath);
3214: }
3215: else
3216: {
3217: int newIndex = getRowForPath(tree, newPath);
3218: int anchorIndex = getRowForPath(tree, anchorPath);
3219: tree.setSelectionInterval(Math.min(anchorIndex, newIndex),
3220: Math.max(anchorIndex, newIndex));
3221: tree.setAnchorSelectionPath(anchorPath);
3222: tree.setLeadSelectionPath(newPath);
3223: }
3224: }
3225: else if (changeSelection)
3226: {
3227: tree.setSelectionPath(newPath);
3228: }
3229: else
3230: {
3231: tree.setLeadSelectionPath(newPath);
3232: }
3233:
3234: tree.scrollRectToVisible(newVisible);
3235: }
3236: }
3237:
3238:
3243: public boolean isEnabled()
3244: {
3245: return (tree != null) && tree.isEnabled();
3246: }
3247: }
3248:
3249:
3253: public class TreeSelectionHandler
3254: implements TreeSelectionListener
3255: {
3256:
3259: public TreeSelectionHandler()
3260: {
3261:
3262: }
3263:
3264:
3270: public void valueChanged(TreeSelectionEvent event)
3271: {
3272: if (tree.isEditing())
3273: tree.cancelEditing();
3274:
3275: TreePath op = event.getOldLeadSelectionPath();
3276: TreePath np = event.getNewLeadSelectionPath();
3277:
3278:
3279: if (op != np)
3280: {
3281: Rectangle o = treeState.getBounds(event.getOldLeadSelectionPath(),
3282: new Rectangle());
3283: Rectangle n = treeState.getBounds(event.getNewLeadSelectionPath(),
3284: new Rectangle());
3285:
3286: if (o != null)
3287: tree.repaint(o);
3288: if (n != null)
3289: tree.repaint(n);
3290: }
3291: }
3292: }
3293:
3294:
3297: public class TreeToggleAction
3298: extends AbstractAction
3299: {
3300:
3305: public TreeToggleAction(String name)
3306: {
3307: putValue(Action.NAME, name);
3308: }
3309:
3310:
3315: public void actionPerformed(ActionEvent e)
3316: {
3317: int selected = tree.getLeadSelectionRow();
3318: if (selected != -1 && isLeaf(selected))
3319: {
3320: TreePath anchorPath = tree.getAnchorSelectionPath();
3321: TreePath leadPath = tree.getLeadSelectionPath();
3322: toggleExpandState(getPathForRow(tree, selected));
3323:
3324:
3325: tree.setLeadSelectionPath(leadPath);
3326: tree.setAnchorSelectionPath(anchorPath);
3327:
3328:
3329: tree.scrollPathToVisible(tree.getLeadSelectionPath());
3330: }
3331: }
3332:
3333:
3338: public boolean isEnabled()
3339: {
3340: return (tree != null) && tree.isEnabled();
3341: }
3342: }
3343:
3344:
3348: public class TreeTraverseAction
3349: extends AbstractAction
3350: {
3351:
3354: protected int direction;
3355:
3356:
3362: public TreeTraverseAction(int direction, String name)
3363: {
3364: this.direction = direction;
3365: putValue(Action.NAME, name);
3366: }
3367:
3368:
3373: public void actionPerformed(ActionEvent e)
3374: {
3375: TreePath current = tree.getLeadSelectionPath();
3376: if (current == null)
3377: return;
3378:
3379: String command = (String) getValue(Action.NAME);
3380: if (command.equals("selectParent"))
3381: {
3382: if (current == null)
3383: return;
3384:
3385: if (tree.isExpanded(current))
3386: {
3387: tree.collapsePath(current);
3388: }
3389: else
3390: {
3391:
3392:
3393:
3394: TreePath parent = current.getParentPath();
3395: if (parent != null &&
3396: ! (parent.getPathCount() == 1 && ! tree.isRootVisible()))
3397: tree.setSelectionPath(parent);
3398: }
3399: }
3400: else if (command.equals("selectChild"))
3401: {
3402: Object node = current.getLastPathComponent();
3403: int nc = treeModel.getChildCount(node);
3404: if (nc == 0 || treeState.isExpanded(current))
3405: {
3406:
3407:
3408: int nextRow = tree.getLeadSelectionRow() + 1;
3409: if (nextRow <= tree.getRowCount())
3410: tree.setSelectionRow(nextRow);
3411: }
3412: else
3413: {
3414: tree.expandPath(current);
3415: }
3416: }
3417:
3418:
3419: tree.scrollPathToVisible(tree.getLeadSelectionPath());
3420: }
3421:
3422:
3427: public boolean isEnabled()
3428: {
3429: return (tree != null) && tree.isEnabled();
3430: }
3431: }
3432:
3433:
3439: boolean hasControlIcons()
3440: {
3441: if (expandedIcon != null || collapsedIcon != null)
3442: return true;
3443: return false;
3444: }
3445:
3446:
3452: Icon getCurrentControlIcon(TreePath path)
3453: {
3454: if (hasControlIcons())
3455: {
3456: if (tree.isExpanded(path))
3457: return expandedIcon;
3458: else
3459: return collapsedIcon;
3460: }
3461: else
3462: {
3463: if (nullIcon == null)
3464: nullIcon = new Icon()
3465: {
3466: public int getIconHeight()
3467: {
3468: return 0;
3469: }
3470:
3471: public int getIconWidth()
3472: {
3473: return 0;
3474: }
3475:
3476: public void paintIcon(Component c, Graphics g, int x, int y)
3477: {
3478:
3479: }
3480: };
3481: return nullIcon;
3482: }
3483: }
3484:
3485:
3492: Object getParent(Object root, Object node)
3493: {
3494: if (root == null || node == null || root.equals(node))
3495: return null;
3496:
3497: if (node instanceof TreeNode)
3498: return ((TreeNode) node).getParent();
3499: return findNode(root, node);
3500: }
3501:
3502:
3509: private Object findNode(Object root, Object node)
3510: {
3511: if (! treeModel.isLeaf(root) && ! root.equals(node))
3512: {
3513: int size = treeModel.getChildCount(root);
3514: for (int j = 0; j < size; j++)
3515: {
3516: Object child = treeModel.getChild(root, j);
3517: if (node.equals(child))
3518: return root;
3519:
3520: Object n = findNode(child, node);
3521: if (n != null)
3522: return n;
3523: }
3524: }
3525: return null;
3526: }
3527:
3528:
3535: void selectPath(JTree tree, TreePath path)
3536: {
3537: if (path != null)
3538: {
3539: tree.setSelectionPath(path);
3540: tree.setLeadSelectionPath(path);
3541: tree.makeVisible(path);
3542: tree.scrollPathToVisible(path);
3543: }
3544: }
3545:
3546:
3554: Object[] getPathToRoot(Object node, int depth)
3555: {
3556: if (node == null)
3557: {
3558: if (depth == 0)
3559: return null;
3560:
3561: return new Object[depth];
3562: }
3563:
3564: Object[] path = getPathToRoot(getParent(treeModel.getRoot(), node),
3565: depth + 1);
3566: path[path.length - depth - 1] = node;
3567: return path;
3568: }
3569:
3570:
3579: protected void paintVerticalLine(Graphics g, JComponent c, int x, int top,
3580: int bottom)
3581: {
3582:
3583: g.setColor(getHashColor());
3584: g.drawLine(x, top, x, bottom);
3585: }
3586:
3587:
3596: protected void paintHorizontalLine(Graphics g, JComponent c, int y, int left,
3597: int right)
3598: {
3599:
3600: g.setColor(getHashColor());
3601: g.drawLine(left, y, right, y);
3602: }
3603:
3604:
3613: protected void drawCentered(Component c, Graphics g, Icon icon, int x, int y)
3614: {
3615: x -= icon.getIconWidth() / 2;
3616: y -= icon.getIconHeight() / 2;
3617:
3618: if (x < 0)
3619: x = 0;
3620: if (y < 0)
3621: y = 0;
3622:
3623: icon.paintIcon(c, g, x, y);
3624: }
3625:
3626:
3634: protected void drawDashedHorizontalLine(Graphics g, int y, int x1, int x2)
3635: {
3636: g.setColor(getHashColor());
3637: for (int i = x1; i < x2; i += 2)
3638: g.drawLine(i, y, i + 1, y);
3639: }
3640:
3641:
3649: protected void drawDashedVerticalLine(Graphics g, int x, int y1, int y2)
3650: {
3651: g.setColor(getHashColor());
3652: for (int i = y1; i < y2; i += 2)
3653: g.drawLine(x, i, x, i + 1);
3654: }
3655:
3656:
3670: protected void paintExpandControl(Graphics g, Rectangle clipBounds,
3671: Insets insets, Rectangle bounds,
3672: TreePath path, int row, boolean isExpanded,
3673: boolean hasBeenExpanded, boolean isLeaf)
3674: {
3675: if (shouldPaintExpandControl(path, row, isExpanded, hasBeenExpanded, isLeaf))
3676: {
3677: Icon icon = getCurrentControlIcon(path);
3678: int iconW = icon.getIconWidth();
3679: int x = bounds.x - iconW - gap;
3680: icon.paintIcon(tree, g, x, bounds.y + bounds.height / 2
3681: - icon.getIconHeight() / 2);
3682: }
3683: }
3684:
3685:
3700: protected void paintHorizontalPartOfLeg(Graphics g, Rectangle clipBounds,
3701: Insets insets, Rectangle bounds,
3702: TreePath path, int row,
3703: boolean isExpanded,
3704: boolean hasBeenExpanded,
3705: boolean isLeaf)
3706: {
3707: if (row != 0)
3708: {
3709: paintHorizontalLine(g, tree, bounds.y + bounds.height / 2,
3710: bounds.x - leftChildIndent - gap, bounds.x - gap);
3711: }
3712: }
3713:
3714:
3723: protected void paintVerticalPartOfLeg(Graphics g, Rectangle clipBounds,
3724: Insets insets, TreePath path)
3725: {
3726: Rectangle bounds = getPathBounds(tree, path);
3727: TreePath parent = path.getParentPath();
3728:
3729: boolean paintLine;
3730: if (isRootVisible())
3731: paintLine = parent != null;
3732: else
3733: paintLine = parent != null && parent.getPathCount() > 1;
3734: if (paintLine)
3735: {
3736: Rectangle parentBounds = getPathBounds(tree, parent);
3737: paintVerticalLine(g, tree, parentBounds.x + 2 * gap,
3738: parentBounds.y + parentBounds.height / 2,
3739: bounds.y + bounds.height / 2);
3740: }
3741: }
3742:
3743:
3757: protected void paintRow(Graphics g, Rectangle clipBounds, Insets insets,
3758: Rectangle bounds, TreePath path, int row,
3759: boolean isExpanded, boolean hasBeenExpanded,
3760: boolean isLeaf)
3761: {
3762: boolean selected = tree.isPathSelected(path);
3763: boolean hasIcons = false;
3764: Object node = path.getLastPathComponent();
3765:
3766: paintExpandControl(g, clipBounds, insets, bounds, path, row, isExpanded,
3767: hasBeenExpanded, isLeaf);
3768:
3769: TreeCellRenderer dtcr = currentCellRenderer;
3770:
3771: boolean focused = false;
3772: if (treeSelectionModel != null)
3773: focused = treeSelectionModel.getLeadSelectionRow() == row
3774: && tree.isFocusOwner();
3775:
3776: Component c = dtcr.getTreeCellRendererComponent(tree, node, selected,
3777: isExpanded, isLeaf, row,
3778: focused);
3779:
3780: rendererPane.paintComponent(g, c, c.getParent(), bounds);
3781: }
3782:
3783:
3786: protected void prepareForUIUninstall()
3787: {
3788:
3789: }
3790:
3791:
3801: protected boolean shouldPaintExpandControl(TreePath path, int row,
3802: boolean isExpanded,
3803: boolean hasBeenExpanded,
3804: boolean isLeaf)
3805: {
3806: Object node = path.getLastPathComponent();
3807: return ! isLeaf && hasControlIcons();
3808: }
3809:
3810:
3813: void finish()
3814: {
3815: treeState.invalidatePathBounds(treeState.getPathForRow(editingRow));
3816: editingPath = null;
3817: editingRow = - 1;
3818: stopEditingInCompleteEditing = false;
3819: isEditing = false;
3820: Rectangle bounds = editingComponent.getParent().getBounds();
3821: tree.removeAll();
3822: validCachedPreferredSize = false;
3823:
3824: tree.repaint(bounds);
3825: editingComponent = null;
3826: tree.requestFocus();
3827: }
3828:
3829:
3834: protected int getRowX(int row, int depth)
3835: {
3836: return depth * totalChildIndent;
3837: }
3838: }