1. /*
  2. * @(#)BasicTableUI.java 1.102 00/02/02
  3. *
  4. * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package javax.swing.plaf.basic;
  11. import javax.swing.table.*;
  12. import javax.swing.*;
  13. import javax.swing.event.*;
  14. import java.util.Enumeration;
  15. import java.util.Hashtable;
  16. import java.awt.event.*;
  17. import java.awt.*;
  18. import javax.swing.plaf.*;
  19. import java.util.EventObject;
  20. import javax.swing.text.*;
  21. /**
  22. * BasicTableUI implementation
  23. *
  24. * @version 1.102 02/02/00
  25. * @author Philip Milne
  26. */
  27. public class BasicTableUI extends TableUI
  28. {
  29. //
  30. // Instance Variables
  31. //
  32. // The JTable that is delegating the painting to this UI.
  33. protected JTable table;
  34. protected CellRendererPane rendererPane;
  35. // Listeners that are attached to the JTable
  36. protected KeyListener keyListener;
  37. protected FocusListener focusListener;
  38. protected MouseInputListener mouseInputListener;
  39. //
  40. // Helper class for keyboard actions
  41. //
  42. private static class NavigationalAction extends AbstractAction {
  43. protected int dx;
  44. protected int dy;
  45. protected boolean toggle;
  46. protected boolean extend;
  47. protected boolean inSelection;
  48. protected int anchorRow;
  49. protected int anchorColumn;
  50. protected int leadRow;
  51. protected int leadColumn;
  52. protected NavigationalAction(int dx, int dy, boolean toggle, boolean extend,
  53. boolean inSelection) {
  54. this.dx = dx;
  55. this.dy = dy;
  56. this.toggle = toggle;
  57. this.extend = extend;
  58. this.inSelection = inSelection;
  59. }
  60. private int clipToRange(int i, int a, int b) {
  61. return Math.min(Math.max(i, a), b-1);
  62. }
  63. private void moveWithinTableRange(JTable table, int dx, int dy, boolean changeLead) {
  64. if (changeLead) {
  65. leadRow = clipToRange(leadRow+dy, 0, table.getRowCount());
  66. leadColumn = clipToRange(leadColumn+dx, 0, table.getColumnCount());
  67. }
  68. else {
  69. anchorRow = clipToRange(anchorRow+dy, 0, table.getRowCount());
  70. anchorColumn = clipToRange(anchorColumn+dx, 0, table.getColumnCount());
  71. }
  72. }
  73. private int selectionSpan(ListSelectionModel sm) {
  74. return sm.getMaxSelectionIndex() - sm.getMinSelectionIndex() + 1;
  75. }
  76. private int compare(int i, ListSelectionModel sm) {
  77. return compare(i, sm.getMinSelectionIndex(), sm.getMaxSelectionIndex()+1);
  78. }
  79. private int compare(int i, int a, int b) {
  80. return (i < a) ? -1 : (i >= b) ? 1 : 0 ;
  81. }
  82. private boolean moveWithinSelectedRange(JTable table, int dx, int dy, boolean ignoreCarry) {
  83. ListSelectionModel rsm = table.getSelectionModel();
  84. ListSelectionModel csm = table.getColumnModel().getSelectionModel();
  85. int newAnchorRow = anchorRow + dy;
  86. int newAnchorColumn = anchorColumn + dx;
  87. int rowSgn;
  88. int colSgn;
  89. int rowCount = selectionSpan(rsm);
  90. int columnCount = selectionSpan(csm);
  91. boolean canStayInSelection = (rowCount * columnCount > 1);
  92. if (canStayInSelection) {
  93. rowSgn = compare(newAnchorRow, rsm);
  94. colSgn = compare(newAnchorColumn, csm);
  95. }
  96. else {
  97. // If there is only one selected cell, there is no point
  98. // in trying to stay within the selected area. Move outside
  99. // the selection, wrapping at the table boundaries.
  100. rowCount = table.getRowCount();
  101. columnCount = table.getColumnCount();
  102. rowSgn = compare(newAnchorRow, 0, rowCount);
  103. colSgn = compare(newAnchorColumn, 0, columnCount);
  104. }
  105. anchorRow = newAnchorRow - rowCount * rowSgn;
  106. anchorColumn = newAnchorColumn - columnCount * colSgn;
  107. if (!ignoreCarry) {
  108. return moveWithinSelectedRange(table, rowSgn, colSgn, true);
  109. }
  110. return canStayInSelection;
  111. }
  112. public void actionPerformed(ActionEvent e) {
  113. JTable table = (JTable)e.getSource();
  114. ListSelectionModel rsm = table.getSelectionModel();
  115. anchorRow = rsm.getAnchorSelectionIndex();
  116. leadRow = rsm.getLeadSelectionIndex();
  117. ListSelectionModel csm = table.getColumnModel().getSelectionModel();
  118. anchorColumn = csm.getAnchorSelectionIndex();
  119. leadColumn = csm.getLeadSelectionIndex();
  120. int oldAnchorRow = anchorRow;
  121. int oldAnchorColumn = anchorColumn;
  122. if (table.isEditing() && !table.getCellEditor().stopCellEditing()) {
  123. return;
  124. }
  125. if (!inSelection) {
  126. moveWithinTableRange(table, dx, dy, extend);
  127. if (!extend) {
  128. table.changeSelection(anchorRow, anchorColumn, false, extend);
  129. }
  130. else {
  131. table.changeSelection(leadRow, leadColumn, false, extend);
  132. }
  133. }
  134. else {
  135. if (moveWithinSelectedRange(table, dx, dy, false)) {
  136. table.changeSelection(anchorRow, anchorColumn, true, true);
  137. }
  138. else {
  139. table.changeSelection(anchorRow, anchorColumn, false, false);
  140. }
  141. }
  142. }
  143. }
  144. private static class PagingAction extends NavigationalAction {
  145. private boolean forwards;
  146. private boolean vertically;
  147. private boolean toLimit;
  148. private PagingAction(boolean extend, boolean forwards,
  149. boolean vertically, boolean toLimit) {
  150. super(0, 0, false, extend, false);
  151. this.forwards = forwards;
  152. this.vertically = vertically;
  153. this.toLimit = toLimit;
  154. }
  155. public void actionPerformed(ActionEvent e) {
  156. JTable table = (JTable)e.getSource();
  157. if (toLimit) {
  158. if (vertically) {
  159. int rowCount = table.getRowCount();
  160. this.dx = 0;
  161. this.dy = forwards ? rowCount : -rowCount;
  162. }
  163. else {
  164. int colCount = table.getColumnCount();
  165. this.dx = forwards ? colCount : -colCount;
  166. this.dy = 0;
  167. }
  168. }
  169. else {
  170. if (!(table.getParent().getParent() instanceof JScrollPane)) {
  171. return;
  172. }
  173. Dimension delta = table.getParent().getSize();
  174. ListSelectionModel sm = (vertically)
  175. ? table.getSelectionModel()
  176. : table.getColumnModel().getSelectionModel();
  177. int start = (extend) ? sm.getLeadSelectionIndex()
  178. : sm.getAnchorSelectionIndex();
  179. if (vertically) {
  180. Rectangle r = table.getCellRect(start, 0, true);
  181. r.y += forwards ? delta.height : -delta.height;
  182. this.dx = 0;
  183. int newRow = table.rowAtPoint(r.getLocation());
  184. if (newRow == -1 && forwards) {
  185. newRow = table.getRowCount();
  186. }
  187. this.dy = newRow - start;
  188. }
  189. else {
  190. Rectangle r = table.getCellRect(0, start, true);
  191. r.x += forwards ? delta.width : -delta.width;
  192. int newColumn = table.columnAtPoint(r.getLocation());
  193. if (newColumn == -1 && forwards) {
  194. newColumn = table.getColumnCount();
  195. }
  196. this.dx = newColumn - start;
  197. this.dy = 0;
  198. }
  199. }
  200. super.actionPerformed(e);
  201. }
  202. }
  203. /**
  204. * Action to invoke <code>selectAll</code> on the table.
  205. */
  206. private static class SelectAllAction extends AbstractAction {
  207. public void actionPerformed(ActionEvent e) {
  208. JTable table = (JTable)e.getSource();
  209. table.selectAll();
  210. }
  211. }
  212. /**
  213. * Action to invoke <code>removeEditor</code> on the table.
  214. */
  215. private static class CancelEditingAction extends AbstractAction {
  216. public void actionPerformed(ActionEvent e) {
  217. JTable table = (JTable)e.getSource();
  218. table.removeEditor();
  219. }
  220. }
  221. /**
  222. * Action to start editing, and pass focus to the editor.
  223. */
  224. private static class StartEditingAction extends AbstractAction {
  225. public void actionPerformed(ActionEvent e) {
  226. JTable table = (JTable)e.getSource();
  227. if (!table.hasFocus()) {
  228. CellEditor cellEditor = table.getCellEditor();
  229. if (cellEditor != null && !cellEditor.stopCellEditing()) {
  230. return;
  231. }
  232. table.requestFocus();
  233. return;
  234. }
  235. ListSelectionModel rsm = table.getSelectionModel();
  236. int anchorRow = rsm.getAnchorSelectionIndex();
  237. ListSelectionModel csm = table.getColumnModel().getSelectionModel();
  238. int anchorColumn = csm.getAnchorSelectionIndex();
  239. table.editCellAt(anchorRow, anchorColumn);
  240. Component editorComp = table.getEditorComponent();
  241. if (editorComp != null) {
  242. editorComp.requestFocus();
  243. }
  244. }
  245. }
  246. //
  247. // The Table's Key listener
  248. //
  249. /**
  250. * This inner class is marked "public" due to a compiler bug.
  251. * This class should be treated as a "protected" inner class.
  252. * Instantiate it only within subclasses of BasicTableUI.
  253. * <p>As of Java 2 platform v1.3 this class is no longer used.
  254. * Instead <code>JTable</code>
  255. * overrides <code>processKeyBinding</code> to dispatch the event to
  256. * the current <code>TableCellEditor</code>.
  257. */
  258. public class KeyHandler implements KeyListener {
  259. public void keyPressed(KeyEvent e) { }
  260. public void keyReleased(KeyEvent e) { }
  261. public void keyTyped(KeyEvent e) {
  262. KeyStroke keyStroke = KeyStroke.getKeyStroke(e.getKeyChar(), e.getModifiers());
  263. // We register all actions using ANCESTOR_OF_FOCUSED_COMPONENT
  264. // which means that we might perform the appropriate action
  265. // in the table and then forward it to the editor if the editor
  266. // had focus. Make sure this doesn't happen by checking our
  267. // InputMaps.
  268. InputMap map = table.getInputMap(JComponent.WHEN_FOCUSED);
  269. if (map != null && map.get(keyStroke) != null) {
  270. return;
  271. }
  272. map = table.getInputMap(JComponent.
  273. WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  274. if (map != null && map.get(keyStroke) != null) {
  275. return;
  276. }
  277. keyStroke = KeyStroke.getKeyStrokeForEvent(e);
  278. // The AWT seems to generate an unconsumed \r event when
  279. // ENTER (\n) is pressed.
  280. if (e.getKeyChar() == '\r') {
  281. return;
  282. }
  283. int anchorRow = table.getSelectionModel().getAnchorSelectionIndex();
  284. int anchorColumn =
  285. table.getColumnModel().getSelectionModel().getAnchorSelectionIndex();
  286. if (anchorRow != -1 && anchorColumn != -1 && !table.isEditing()) {
  287. if (!table.editCellAt(anchorRow, anchorColumn)) {
  288. return;
  289. }
  290. }
  291. // Forwarding events this way seems to put the component
  292. // in a state where it believes it has focus. In reality
  293. // the table retains focus - though it is difficult for
  294. // a user to tell, since the caret is visible and flashing.
  295. // Calling table.requestFocus() here, to get the focus back to
  296. // the table, seems to have no effect.
  297. Component editorComp = table.getEditorComponent();
  298. if (table.isEditing() && editorComp != null) {
  299. if (editorComp instanceof JComponent) {
  300. JComponent component = (JComponent)editorComp;
  301. map = component.getInputMap(JComponent.WHEN_FOCUSED);
  302. Object binding = (map != null) ? map.get(keyStroke) : null;
  303. if (binding == null) {
  304. map = component.getInputMap(JComponent.
  305. WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  306. binding = (map != null) ? map.get(keyStroke) : null;
  307. }
  308. if (binding != null) {
  309. ActionMap am = component.getActionMap();
  310. Action action = (am != null) ? am.get(binding) : null;
  311. if (action != null && SwingUtilities.
  312. notifyAction(action, keyStroke, e, component,
  313. e.getModifiers())) {
  314. e.consume();
  315. }
  316. }
  317. }
  318. }
  319. }
  320. }
  321. //
  322. // The Table's focus listener
  323. //
  324. /**
  325. * This inner class is marked "public" due to a compiler bug.
  326. * This class should be treated as a "protected" inner class.
  327. * Instantiate it only within subclasses of BasicTableUI.
  328. */
  329. public class FocusHandler implements FocusListener {
  330. private void repaintAnchorCell( ) {
  331. int rc = table.getRowCount();
  332. int cc = table.getColumnCount();
  333. int ar = table.getSelectionModel().getAnchorSelectionIndex();
  334. int ac = table.getColumnModel().getSelectionModel().getAnchorSelectionIndex();
  335. if (ar < 0 || ar >= rc || ac < 0 || ac >= cc) {
  336. return;
  337. }
  338. Rectangle dirtyRect = table.getCellRect(ar, ac, false);
  339. table.repaint(dirtyRect);
  340. }
  341. public void focusGained(FocusEvent e) {
  342. repaintAnchorCell();
  343. }
  344. public void focusLost(FocusEvent e) {
  345. repaintAnchorCell();
  346. }
  347. }
  348. //
  349. // The Table's mouse and mouse motion listeners
  350. //
  351. /**
  352. * This inner class is marked "public" due to a compiler bug.
  353. * This class should be treated as a "protected" inner class.
  354. * Instantiate it only within subclasses of BasicTableUI.
  355. */
  356. public class MouseInputHandler implements MouseInputListener {
  357. // Component recieving mouse events during editing. May not be editorComponent.
  358. private Component dispatchComponent;
  359. // The Table's mouse listener methods.
  360. public void mouseClicked(MouseEvent e) {}
  361. private void setDispatchComponent(MouseEvent e) {
  362. Component editorComponent = table.getEditorComponent();
  363. Point p = e.getPoint();
  364. Point p2 = SwingUtilities.convertPoint(table, p, editorComponent);
  365. dispatchComponent = SwingUtilities.getDeepestComponentAt(editorComponent,
  366. p2.x, p2.y);
  367. }
  368. private boolean repostEvent(MouseEvent e) {
  369. if (dispatchComponent == null) {
  370. return false;
  371. }
  372. MouseEvent e2 = SwingUtilities.convertMouseEvent(table, e, dispatchComponent);
  373. dispatchComponent.dispatchEvent(e2);
  374. return true;
  375. }
  376. private void setValueIsAdjusting(boolean flag) {
  377. table.getSelectionModel().setValueIsAdjusting(flag);
  378. table.getColumnModel().getSelectionModel().setValueIsAdjusting(flag);
  379. }
  380. private boolean shouldIgnore(MouseEvent e) {
  381. return !(SwingUtilities.isLeftMouseButton(e) && table.isEnabled());
  382. }
  383. public void mousePressed(MouseEvent e) {
  384. if (shouldIgnore(e)) {
  385. return;
  386. }
  387. Point p = e.getPoint();
  388. int row = table.rowAtPoint(p);
  389. int column = table.columnAtPoint(p);
  390. // The autoscroller can generate drag events outside the Table's range.
  391. if ((column == -1) || (row == -1)) {
  392. return;
  393. }
  394. if (table.editCellAt(row, column, e)) {
  395. setDispatchComponent(e);
  396. repostEvent(e);
  397. }
  398. else {
  399. table.requestFocus();
  400. }
  401. CellEditor editor = table.getCellEditor();
  402. if (editor == null || editor.shouldSelectCell(e)) {
  403. setValueIsAdjusting(true);
  404. table.changeSelection(row, column, e.isControlDown(), e.isShiftDown());
  405. }
  406. }
  407. public void mouseReleased(MouseEvent e) {
  408. if (shouldIgnore(e)) {
  409. return;
  410. }
  411. repostEvent(e);
  412. dispatchComponent = null;
  413. setValueIsAdjusting(false);
  414. }
  415. public void mouseEntered(MouseEvent e) {}
  416. public void mouseExited(MouseEvent e) {}
  417. // The Table's mouse motion listener methods.
  418. public void mouseMoved(MouseEvent e) {}
  419. public void mouseDragged(MouseEvent e) {
  420. if (shouldIgnore(e)) {
  421. return;
  422. }
  423. repostEvent(e);
  424. CellEditor editor = table.getCellEditor();
  425. if (editor == null || editor.shouldSelectCell(e)) {
  426. Point p = e.getPoint();
  427. int row = table.rowAtPoint(p);
  428. int column = table.columnAtPoint(p);
  429. // The autoscroller can generate drag events outside the Table's range.
  430. if ((column == -1) || (row == -1)) {
  431. return;
  432. }
  433. table.changeSelection(row, column, false, true);
  434. }
  435. }
  436. }
  437. //
  438. // Factory methods for the Listeners
  439. //
  440. /**
  441. * Creates the key listener for handling keyboard navigation in the JTable.
  442. */
  443. protected KeyListener createKeyListener() {
  444. return null;
  445. }
  446. /**
  447. * Creates the focus listener for handling keyboard navigation in the JTable.
  448. */
  449. protected FocusListener createFocusListener() {
  450. return new FocusHandler();
  451. }
  452. /**
  453. * Creates the mouse listener for the JTable.
  454. */
  455. protected MouseInputListener createMouseInputListener() {
  456. return new MouseInputHandler();
  457. }
  458. //
  459. // The installation/uninstall procedures and support
  460. //
  461. public static ComponentUI createUI(JComponent c) {
  462. return new BasicTableUI();
  463. }
  464. // Installation
  465. public void installUI(JComponent c) {
  466. table = (JTable)c;
  467. rendererPane = new CellRendererPane();
  468. table.add(rendererPane);
  469. installDefaults();
  470. installListeners();
  471. installKeyboardActions();
  472. }
  473. /**
  474. * Initialize JTable properties, e.g. font, foreground, and background.
  475. * The font, foreground, and background properties are only set if their
  476. * current value is either null or a UIResource, other properties are set
  477. * if the current value is null.
  478. *
  479. * @see #installUI
  480. */
  481. protected void installDefaults() {
  482. LookAndFeel.installColorsAndFont(table, "Table.background",
  483. "Table.foreground", "Table.font");
  484. Color sbg = table.getSelectionBackground();
  485. if (sbg == null || sbg instanceof UIResource) {
  486. table.setSelectionBackground(UIManager.getColor("Table.selectionBackground"));
  487. }
  488. Color sfg = table.getSelectionForeground();
  489. if (sfg == null || sfg instanceof UIResource) {
  490. table.setSelectionForeground(UIManager.getColor("Table.selectionForeground"));
  491. }
  492. Color gridColor = table.getGridColor();
  493. if (gridColor == null || gridColor instanceof UIResource) {
  494. table.setGridColor(UIManager.getColor("Table.gridColor"));
  495. }
  496. // install the scrollpane border
  497. Container parent = table.getParent(); // should be viewport
  498. if (parent != null) {
  499. parent = parent.getParent(); // should be the scrollpane
  500. if (parent != null && parent instanceof JScrollPane) {
  501. LookAndFeel.installBorder((JScrollPane)parent, "Table.scrollPaneBorder");
  502. }
  503. }
  504. }
  505. /**
  506. * Attaches listeners to the JTable.
  507. */
  508. protected void installListeners() {
  509. focusListener = createFocusListener();
  510. keyListener = createKeyListener();
  511. mouseInputListener = createMouseInputListener();
  512. table.addFocusListener(focusListener);
  513. table.addKeyListener(keyListener);
  514. table.addMouseListener(mouseInputListener);
  515. table.addMouseMotionListener(mouseInputListener);
  516. }
  517. /**
  518. * Register all keyboard actions on the JTable.
  519. */
  520. protected void installKeyboardActions() {
  521. ActionMap map = getActionMap();
  522. SwingUtilities.replaceUIActionMap(table, map);
  523. InputMap inputMap = getInputMap(JComponent.
  524. WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  525. SwingUtilities.replaceUIInputMap(table, JComponent.
  526. WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
  527. inputMap);
  528. }
  529. InputMap getInputMap(int condition) {
  530. if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
  531. return (InputMap)UIManager.get("Table.ancestorInputMap");
  532. }
  533. return null;
  534. }
  535. ActionMap getActionMap() {
  536. ActionMap map = (ActionMap)UIManager.get("Table.actionMap");
  537. if (map == null) {
  538. map = createActionMap();
  539. if (map != null) {
  540. UIManager.put("Table.actionMap", map);
  541. }
  542. }
  543. return map;
  544. }
  545. ActionMap createActionMap() {
  546. ActionMap map = new ActionMapUIResource();
  547. map.put("selectNextColumn", new NavigationalAction
  548. (1, 0, false, false, false));
  549. map.put("selectPreviousColumn", new NavigationalAction
  550. (-1, 0, false, false, false));
  551. map.put("selectNextRow", new NavigationalAction
  552. (0, 1, false, false, false));
  553. map.put("selectPreviousRow", new NavigationalAction
  554. (0, -1, false, false, false));
  555. map.put("selectNextColumnExtendSelection", new NavigationalAction
  556. (1, 0, false, true, false));
  557. map.put("selectPreviousColumnExtendSelection", new NavigationalAction
  558. (-1, 0, false, true, false));
  559. map.put("selectNextRowExtendSelection", new NavigationalAction
  560. (0, 1, false, true, false));
  561. map.put("selectPreviousRowExtendSelection", new NavigationalAction
  562. (0, -1, false, true, false));
  563. map.put("scrollUpChangeSelection",
  564. new PagingAction(false, false, true, false));
  565. map.put("scrollDownChangeSelection",
  566. new PagingAction(false, true, true, false));
  567. map.put("selectFirstColumn",
  568. new PagingAction(false, false, false, true));
  569. map.put("selectLastColumn",
  570. new PagingAction(false, true, false, false));
  571. map.put("scrollUpExtendSelection",
  572. new PagingAction(true, false, true, false));
  573. map.put("scrollDownExtendSelection",
  574. new PagingAction(true, true, true, false));
  575. map.put("selectFirstColumnExtendSelection",
  576. new PagingAction(true, false, false, true));
  577. map.put("selectLastColumnExtendSelection",
  578. new PagingAction(true, true, false, false));
  579. map.put("scrollLeftChangeSelection",
  580. new PagingAction(false, false, false, false));
  581. map.put("scrollRightChangeSelection",
  582. new PagingAction(false, true, false, false));
  583. map.put("selectFirstRow",
  584. new PagingAction(false, false, true, true));
  585. map.put("selectLastRow",
  586. new PagingAction(false, true, true, true));
  587. map.put("scrollRightExtendSelection",
  588. new PagingAction(true, false, false, false));
  589. map.put("scrollLeftExtendSelection",
  590. new PagingAction(true, true, false, false));
  591. map.put("selectFirstRowExtendSelection",
  592. new PagingAction(true, false, true, true));
  593. map.put("selectLastRowExtendSelection",
  594. new PagingAction(true, true, true, true));
  595. map.put("selectNextColumnCell",
  596. new NavigationalAction(1, 0, true, false, true));
  597. map.put("selectPreviousColumnCell",
  598. new NavigationalAction(-1, 0, true, false, true));
  599. map.put("selectNextRowCell",
  600. new NavigationalAction(0, 1, true, false, true));
  601. map.put("selectPreviousRowCell",
  602. new NavigationalAction(0, -1, true, false, true));
  603. map.put("selectAll", new SelectAllAction());
  604. map.put("cancel", new CancelEditingAction());
  605. map.put("startEditing", new StartEditingAction());
  606. return map;
  607. }
  608. // Uninstallation
  609. public void uninstallUI(JComponent c) {
  610. uninstallDefaults();
  611. uninstallListeners();
  612. uninstallKeyboardActions();
  613. table.remove(rendererPane);
  614. rendererPane = null;
  615. table = null;
  616. }
  617. protected void uninstallDefaults() {}
  618. protected void uninstallListeners() {
  619. table.removeFocusListener(focusListener);
  620. table.removeKeyListener(keyListener);
  621. table.removeMouseListener(mouseInputListener);
  622. table.removeMouseMotionListener(mouseInputListener);
  623. focusListener = null;
  624. keyListener = null;
  625. mouseInputListener = null;
  626. }
  627. protected void uninstallKeyboardActions() {
  628. SwingUtilities.replaceUIInputMap(table, JComponent.
  629. WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
  630. SwingUtilities.replaceUIActionMap(table, null);
  631. }
  632. //
  633. // Size Methods
  634. //
  635. private Dimension createTableSize(long width) {
  636. int height = 0;
  637. int rowCount = table.getRowCount();
  638. if (rowCount > 0 && table.getColumnCount() > 0) {
  639. Rectangle r = table.getCellRect(rowCount-1, 0, true);
  640. height = r.y + r.height;
  641. }
  642. // Width is always positive. The call to abs() is a workaround for
  643. // a bug in the 1.1.6 JIT on Windows.
  644. long tmp = Math.abs(width);
  645. if (tmp > Integer.MAX_VALUE) {
  646. tmp = Integer.MAX_VALUE;
  647. }
  648. return new Dimension((int)tmp, height);
  649. }
  650. /**
  651. * Return the minimum size of the table. The minimum height is the
  652. * row height times the number of rows.
  653. * The minimum width is the sum of the minimum widths of each column.
  654. */
  655. public Dimension getMinimumSize(JComponent c) {
  656. long width = 0;
  657. Enumeration enumeration = table.getColumnModel().getColumns();
  658. while (enumeration.hasMoreElements()) {
  659. TableColumn aColumn = (TableColumn)enumeration.nextElement();
  660. width = width + aColumn.getMinWidth();
  661. }
  662. return createTableSize(width);
  663. }
  664. /**
  665. * Return the preferred size of the table. The preferred height is the
  666. * row height times the number of rows.
  667. * The preferred width is the sum of the preferred widths of each column.
  668. */
  669. public Dimension getPreferredSize(JComponent c) {
  670. long width = 0;
  671. Enumeration enumeration = table.getColumnModel().getColumns();
  672. while (enumeration.hasMoreElements()) {
  673. TableColumn aColumn = (TableColumn)enumeration.nextElement();
  674. width = width + aColumn.getPreferredWidth();
  675. }
  676. return createTableSize(width);
  677. }
  678. /**
  679. * Return the maximum size of the table. The maximum height is the
  680. * row heighttimes the number of rows.
  681. * The maximum width is the sum of the maximum widths of each column.
  682. */
  683. public Dimension getMaximumSize(JComponent c) {
  684. long width = 0;
  685. Enumeration enumeration = table.getColumnModel().getColumns();
  686. while (enumeration.hasMoreElements()) {
  687. TableColumn aColumn = (TableColumn)enumeration.nextElement();
  688. width = width + aColumn.getMaxWidth();
  689. }
  690. return createTableSize(width);
  691. }
  692. //
  693. // Paint methods and support
  694. //
  695. /** Paint a representation of the <code>table</code> instance
  696. * that was set in installUI().
  697. */
  698. public void paint(Graphics g, JComponent c) {
  699. if (table.getRowCount() <= 0 || table.getColumnCount() <= 0) {
  700. return;
  701. }
  702. Rectangle clip = g.getClipBounds();
  703. Point minLocation = clip.getLocation();
  704. Point maxLocation = new Point(clip.x + clip.width - 1, clip.y + clip.height - 1);
  705. int rMin = table.rowAtPoint(minLocation);
  706. int rMax = table.rowAtPoint(maxLocation);
  707. // This should never happen.
  708. if (rMin == -1) {
  709. rMin = 0;
  710. }
  711. // If the table does not have enough rows to fill the view we'll get -1.
  712. // Replace this with the index of the last row.
  713. if (rMax == -1) {
  714. rMax = table.getRowCount()-1;
  715. }
  716. int cMin = table.columnAtPoint(minLocation);
  717. int cMax = table.columnAtPoint(maxLocation);
  718. // This should never happen.
  719. if (cMin == -1) {
  720. cMin = 0;
  721. }
  722. // If the table does not have enough columns to fill the view we'll get -1.
  723. // Replace this with the index of the last column.
  724. if (cMax == -1) {
  725. cMax = table.getColumnCount()-1;
  726. }
  727. // Paint the grid.
  728. paintGrid(g, rMin, rMax, cMin, cMax);
  729. // Paint the cells.
  730. paintCells(g, rMin, rMax, cMin, cMax);
  731. }
  732. /*
  733. * Paints the grid lines within <I>aRect</I>, using the grid
  734. * color set with <I>setGridColor</I>. Paints vertical lines
  735. * if <code>getShowVerticalLines()</code> returns true and paints
  736. * horizontal lines if <code>getShowHorizontalLines()</code>
  737. * returns true.
  738. */
  739. private void paintGrid(Graphics g, int rMin, int rMax, int cMin, int cMax) {
  740. g.setColor(table.getGridColor());
  741. Rectangle minCell = table.getCellRect(rMin, cMin, true);
  742. Rectangle maxCell = table.getCellRect(rMax, cMax, true);
  743. if (table.getShowHorizontalLines()) {
  744. int tableWidth = maxCell.x + maxCell.width;
  745. int y = minCell.y;
  746. for (int row = rMin; row <= rMax; row++) {
  747. y += table.getRowHeight(row);
  748. g.drawLine(0, y - 1, tableWidth - 1, y - 1);
  749. }
  750. }
  751. if (table.getShowVerticalLines()) {
  752. TableColumnModel cm = table.getColumnModel();
  753. int tableHeight = maxCell.y + maxCell.height;
  754. int x = minCell.x;
  755. for (int column = cMin; column <= cMax ; column++) {
  756. x += cm.getColumn(column).getWidth();
  757. g.drawLine(x - 1, 0, x - 1, tableHeight - 1);
  758. }
  759. }
  760. }
  761. private int viewIndexForColumn(TableColumn aColumn) {
  762. TableColumnModel cm = table.getColumnModel();
  763. for (int column = 0; column < cm.getColumnCount(); column++) {
  764. if (cm.getColumn(column) == aColumn) {
  765. return column;
  766. }
  767. }
  768. return -1;
  769. }
  770. private void paintCells(Graphics g, int rMin, int rMax, int cMin, int cMax) {
  771. JTableHeader header = table.getTableHeader();
  772. TableColumn draggedColumn = (header == null) ? null : header.getDraggedColumn();
  773. TableColumnModel cm = table.getColumnModel();
  774. int columnMargin = cm.getColumnMargin();
  775. for(int row = rMin; row <= rMax; row++) {
  776. Rectangle cellRect = table.getCellRect(row, cMin, false);
  777. for(int column = cMin; column <= cMax ; column++) {
  778. TableColumn aColumn = cm.getColumn(column);
  779. int columnWidth = aColumn.getWidth();
  780. cellRect.width = columnWidth - columnMargin;
  781. if (aColumn != draggedColumn) {
  782. paintCell(g, cellRect, row, column);
  783. }
  784. cellRect.x += columnWidth;
  785. }
  786. }
  787. // Paint the dragged column if we are dragging.
  788. if (draggedColumn != null) {
  789. paintDraggedArea(g, rMin, rMax, draggedColumn, header.getDraggedDistance());
  790. }
  791. // Remove any renderers that may be left in the rendererPane.
  792. rendererPane.removeAll();
  793. }
  794. private void paintDraggedArea(Graphics g, int rMin, int rMax, TableColumn draggedColumn, int distance) {
  795. int draggedColumnIndex = viewIndexForColumn(draggedColumn);
  796. Rectangle minCell = table.getCellRect(rMin, draggedColumnIndex, true);
  797. Rectangle maxCell = table.getCellRect(rMax, draggedColumnIndex, true);
  798. Rectangle vacatedColumnRect = minCell.union(maxCell);
  799. // Paint a gray well in place of the moving column.
  800. g.setColor(table.getParent().getBackground());
  801. g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,
  802. vacatedColumnRect.width, vacatedColumnRect.height);
  803. // Move to the where the cell has been dragged.
  804. vacatedColumnRect.x += distance;
  805. // Fill the background.
  806. g.setColor(table.getBackground());
  807. g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,
  808. vacatedColumnRect.width, vacatedColumnRect.height);
  809. // Paint the vertical grid lines if necessary.
  810. if (table.getShowVerticalLines()) {
  811. g.setColor(table.getGridColor());
  812. int x1 = vacatedColumnRect.x;
  813. int y1 = vacatedColumnRect.y;
  814. int x2 = x1 + vacatedColumnRect.width - 1;
  815. int y2 = y1 + vacatedColumnRect.height - 1;
  816. // Left
  817. g.drawLine(x1-1, y1, x1-1, y2);
  818. // Right
  819. g.drawLine(x2, y1, x2, y2);
  820. }
  821. for(int row = rMin; row <= rMax; row++) {
  822. // Render the cell value
  823. Rectangle r = table.getCellRect(row, draggedColumnIndex, false);
  824. r.x += distance;
  825. paintCell(g, r, row, draggedColumnIndex);
  826. // Paint the (lower) horizontal grid line if necessary.
  827. if (table.getShowHorizontalLines()) {
  828. g.setColor(table.getGridColor());
  829. Rectangle rcr = table.getCellRect(row, draggedColumnIndex, true);
  830. rcr.x += distance;
  831. int x1 = rcr.x;
  832. int y1 = rcr.y;
  833. int x2 = x1 + rcr.width - 1;
  834. int y2 = y1 + rcr.height - 1;
  835. g.drawLine(x1, y2, x2, y2);
  836. }
  837. }
  838. }
  839. private void paintCell(Graphics g, Rectangle cellRect, int row, int column) {
  840. if (table.isEditing() && table.getEditingRow()==row &&
  841. table.getEditingColumn()==column) {
  842. Component component = table.getEditorComponent();
  843. component.setBounds(cellRect);
  844. component.validate();
  845. }
  846. else {
  847. TableCellRenderer renderer = table.getCellRenderer(row, column);
  848. Component component = table.prepareRenderer(renderer, row, column);
  849. rendererPane.paintComponent(g, component, table, cellRect.x, cellRect.y,
  850. cellRect.width, cellRect.height, true);
  851. }
  852. }
  853. } // End of Class BasicTableUI