1. /*
  2. * @(#)SynthTableUI.java 1.12 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.java.swing.plaf.gtk;
  8. import javax.swing.table.*;
  9. import javax.swing.*;
  10. import javax.swing.event.*;
  11. import java.util.Enumeration;
  12. import java.util.Hashtable;
  13. import java.util.TooManyListenersException;
  14. import java.awt.event.*;
  15. import java.awt.*;
  16. import java.awt.datatransfer.*;
  17. import java.awt.dnd.*;
  18. import javax.swing.plaf.*;
  19. import java.util.EventObject;
  20. import javax.swing.text.*;
  21. import java.beans.PropertyChangeEvent;
  22. import java.beans.PropertyChangeListener;
  23. /**
  24. * BasicTableUI implementation
  25. *
  26. * @version 1.12, 01/23/03 (based on BasicTableUI v 1.122)
  27. * @author Philip Milne
  28. */
  29. class SynthTableUI extends TableUI implements SynthUI {
  30. //
  31. // Instance Variables
  32. //
  33. private SynthStyle style;
  34. // The JTable that is delegating the painting to this UI.
  35. protected JTable table;
  36. protected CellRendererPane rendererPane;
  37. // Listeners that are attached to the JTable
  38. protected KeyListener keyListener;
  39. protected FocusListener focusListener;
  40. protected MouseInputListener mouseInputListener;
  41. private PropertyChangeListener propertyChangeListener;
  42. //
  43. // Helper class for keyboard actions
  44. //
  45. private static class NavigationalAction extends AbstractAction {
  46. protected int dx;
  47. protected int dy;
  48. protected boolean toggle;
  49. protected boolean extend;
  50. protected boolean inSelection;
  51. protected int anchorRow;
  52. protected int anchorColumn;
  53. protected int leadRow;
  54. protected int leadColumn;
  55. protected NavigationalAction(int dx, int dy, boolean toggle, boolean extend,
  56. boolean inSelection) {
  57. this.dx = dx;
  58. this.dy = dy;
  59. this.toggle = toggle;
  60. this.extend = extend;
  61. this.inSelection = inSelection;
  62. }
  63. private int clipToRange(int i, int a, int b) {
  64. return Math.min(Math.max(i, a), b-1);
  65. }
  66. private void moveWithinTableRange(JTable table, int dx, int dy, boolean changeLead) {
  67. if (changeLead) {
  68. leadRow = clipToRange(leadRow+dy, 0, table.getRowCount());
  69. leadColumn = clipToRange(leadColumn+dx, 0, table.getColumnCount());
  70. }
  71. else {
  72. anchorRow = clipToRange(anchorRow+dy, 0, table.getRowCount());
  73. anchorColumn = clipToRange(anchorColumn+dx, 0, table.getColumnCount());
  74. }
  75. }
  76. private int selectionSpan(ListSelectionModel sm) {
  77. return sm.getMaxSelectionIndex() - sm.getMinSelectionIndex() + 1;
  78. }
  79. private int compare(int i, ListSelectionModel sm) {
  80. return compare(i, sm.getMinSelectionIndex(), sm.getMaxSelectionIndex()+1);
  81. }
  82. private int compare(int i, int a, int b) {
  83. return (i < a) ? -1 : (i >= b) ? 1 : 0 ;
  84. }
  85. private boolean moveWithinSelectedRange(JTable table, int dx, int dy, boolean ignoreCarry) {
  86. ListSelectionModel rsm = table.getSelectionModel();
  87. ListSelectionModel csm = table.getColumnModel().getSelectionModel();
  88. int newAnchorRow = anchorRow + dy;
  89. int newAnchorColumn = anchorColumn + dx;
  90. int rowSgn;
  91. int colSgn;
  92. int rowCount = selectionSpan(rsm);
  93. int columnCount = selectionSpan(csm);
  94. boolean canStayInSelection = (rowCount * columnCount > 1);
  95. if (canStayInSelection) {
  96. rowSgn = compare(newAnchorRow, rsm);
  97. colSgn = compare(newAnchorColumn, csm);
  98. }
  99. else {
  100. // If there is only one selected cell, there is no point
  101. // in trying to stay within the selected area. Move outside
  102. // the selection, wrapping at the table boundaries.
  103. rowCount = table.getRowCount();
  104. columnCount = table.getColumnCount();
  105. rowSgn = compare(newAnchorRow, 0, rowCount);
  106. colSgn = compare(newAnchorColumn, 0, columnCount);
  107. }
  108. anchorRow = newAnchorRow - rowCount * rowSgn;
  109. anchorColumn = newAnchorColumn - columnCount * colSgn;
  110. if (!ignoreCarry) {
  111. return moveWithinSelectedRange(table, rowSgn, colSgn, true);
  112. }
  113. return canStayInSelection;
  114. }
  115. public void actionPerformed(ActionEvent e) {
  116. JTable table = (JTable)e.getSource();
  117. ListSelectionModel rsm = table.getSelectionModel();
  118. anchorRow = rsm.getAnchorSelectionIndex();
  119. leadRow = rsm.getLeadSelectionIndex();
  120. ListSelectionModel csm = table.getColumnModel().getSelectionModel();
  121. anchorColumn = csm.getAnchorSelectionIndex();
  122. leadColumn = csm.getLeadSelectionIndex();
  123. int oldAnchorRow = anchorRow;
  124. int oldAnchorColumn = anchorColumn;
  125. if (table.isEditing() && !table.getCellEditor().stopCellEditing()) {
  126. return;
  127. }
  128. // Unfortunately, this strategy introduces bugs because
  129. // of the asynchronous nature of requestFocus() call below.
  130. // Introducing a delay with invokeLater() makes this work
  131. // in the typical case though race conditions then allow
  132. // focus to disappear altogether. The right solution appears
  133. // to be to fix requestFocus() so that it queues a request
  134. // for the focus regardless of who owns the focus at the
  135. // time the call to requestFocus() is made. The optimisation
  136. // to ignore the call to requestFocus() when the component
  137. // already has focus may ligitimately be made as the
  138. // request focus event is dequeued, not before.
  139. // boolean wasEditingWithFocus = table.isEditing() && table.getEditorComponent().isFocusOwner();
  140. if (!inSelection) {
  141. moveWithinTableRange(table, dx, dy, extend);
  142. if (!extend) {
  143. table.changeSelection(anchorRow, anchorColumn, false, extend);
  144. }
  145. else {
  146. table.changeSelection(leadRow, leadColumn, false, extend);
  147. }
  148. }
  149. else {
  150. if (moveWithinSelectedRange(table, dx, dy, false)) {
  151. table.changeSelection(anchorRow, anchorColumn, true, true);
  152. }
  153. else {
  154. table.changeSelection(anchorRow, anchorColumn, false, false);
  155. }
  156. }
  157. /*
  158. if (wasEditingWithFocus) {
  159. table.editCellAt(anchorRow, anchorColumn);
  160. final Component editorComp = table.getEditorComponent();
  161. if (editorComp != null) {
  162. SwingUtilities.invokeLater(new Runnable() {
  163. public void run() {
  164. editorComp.requestFocus();
  165. }
  166. });
  167. }
  168. }
  169. */
  170. }
  171. }
  172. private static class PagingAction extends NavigationalAction {
  173. private boolean forwards;
  174. private boolean vertically;
  175. private boolean toLimit;
  176. private PagingAction(boolean extend, boolean forwards,
  177. boolean vertically, boolean toLimit) {
  178. super(0, 0, false, extend, false);
  179. this.forwards = forwards;
  180. this.vertically = vertically;
  181. this.toLimit = toLimit;
  182. }
  183. public void actionPerformed(ActionEvent e) {
  184. JTable table = (JTable)e.getSource();
  185. if (toLimit) {
  186. if (vertically) {
  187. int rowCount = table.getRowCount();
  188. this.dx = 0;
  189. this.dy = forwards ? rowCount : -rowCount;
  190. }
  191. else {
  192. int colCount = table.getColumnCount();
  193. this.dx = forwards ? colCount : -colCount;
  194. this.dy = 0;
  195. }
  196. }
  197. else {
  198. if (!(table.getParent().getParent() instanceof JScrollPane)) {
  199. return;
  200. }
  201. Dimension delta = table.getParent().getSize();
  202. ListSelectionModel sm = (vertically)
  203. ? table.getSelectionModel()
  204. : table.getColumnModel().getSelectionModel();
  205. int start = (extend) ? sm.getLeadSelectionIndex()
  206. : sm.getAnchorSelectionIndex();
  207. if (vertically) {
  208. Rectangle r = table.getCellRect(start, 0, true);
  209. r.y += forwards ? delta.height : -delta.height;
  210. this.dx = 0;
  211. int newRow = table.rowAtPoint(r.getLocation());
  212. if (newRow == -1 && forwards) {
  213. newRow = table.getRowCount();
  214. }
  215. this.dy = newRow - start;
  216. }
  217. else {
  218. Rectangle r = table.getCellRect(0, start, true);
  219. r.x += forwards ? delta.width : -delta.width;
  220. int newColumn = table.columnAtPoint(r.getLocation());
  221. if (newColumn == -1 && forwards) {
  222. newColumn = table.getColumnCount();
  223. }
  224. this.dx = newColumn - start;
  225. this.dy = 0;
  226. }
  227. }
  228. super.actionPerformed(e);
  229. }
  230. }
  231. /**
  232. * Action to invoke <code>selectAll</code> on the table.
  233. */
  234. private static class SelectAllAction extends AbstractAction {
  235. public void actionPerformed(ActionEvent e) {
  236. JTable table = (JTable)e.getSource();
  237. table.selectAll();
  238. }
  239. }
  240. /**
  241. * Action to invoke <code>removeEditor</code> on the table.
  242. */
  243. private static class CancelEditingAction extends AbstractAction {
  244. public void actionPerformed(ActionEvent e) {
  245. JTable table = (JTable)e.getSource();
  246. table.removeEditor();
  247. }
  248. }
  249. /**
  250. * Action to start editing, and pass focus to the editor.
  251. */
  252. private static class StartEditingAction extends AbstractAction {
  253. public void actionPerformed(ActionEvent e) {
  254. JTable table = (JTable)e.getSource();
  255. if (!table.hasFocus()) {
  256. CellEditor cellEditor = table.getCellEditor();
  257. if (cellEditor != null && !cellEditor.stopCellEditing()) {
  258. return;
  259. }
  260. table.requestFocus();
  261. return;
  262. }
  263. ListSelectionModel rsm = table.getSelectionModel();
  264. int anchorRow = rsm.getAnchorSelectionIndex();
  265. ListSelectionModel csm = table.getColumnModel().getSelectionModel();
  266. int anchorColumn = csm.getAnchorSelectionIndex();
  267. table.editCellAt(anchorRow, anchorColumn);
  268. Component editorComp = table.getEditorComponent();
  269. if (editorComp != null) {
  270. editorComp.requestFocus();
  271. }
  272. }
  273. }
  274. //
  275. // The Table's Key listener
  276. //
  277. /**
  278. * This inner class is marked "public" due to a compiler bug.
  279. * This class should be treated as a "protected" inner class.
  280. * Instantiate it only within subclasses of BasicTableUI.
  281. * <p>As of Java 2 platform v1.3 this class is no longer used.
  282. * Instead <code>JTable</code>
  283. * overrides <code>processKeyBinding</code> to dispatch the event to
  284. * the current <code>TableCellEditor</code>.
  285. */
  286. class KeyHandler implements KeyListener {
  287. public void keyPressed(KeyEvent e) { }
  288. public void keyReleased(KeyEvent e) { }
  289. public void keyTyped(KeyEvent e) {
  290. KeyStroke keyStroke = KeyStroke.getKeyStroke(e.getKeyChar(), e.getModifiers());
  291. // We register all actions using ANCESTOR_OF_FOCUSED_COMPONENT
  292. // which means that we might perform the appropriate action
  293. // in the table and then forward it to the editor if the editor
  294. // had focus. Make sure this doesn't happen by checking our
  295. // InputMaps.
  296. InputMap map = table.getInputMap(JComponent.WHEN_FOCUSED);
  297. if (map != null && map.get(keyStroke) != null) {
  298. return;
  299. }
  300. map = table.getInputMap(JComponent.
  301. WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  302. if (map != null && map.get(keyStroke) != null) {
  303. return;
  304. }
  305. keyStroke = KeyStroke.getKeyStrokeForEvent(e);
  306. // The AWT seems to generate an unconsumed \r event when
  307. // ENTER (\n) is pressed.
  308. if (e.getKeyChar() == '\r') {
  309. return;
  310. }
  311. int anchorRow = table.getSelectionModel().getAnchorSelectionIndex();
  312. int anchorColumn =
  313. table.getColumnModel().getSelectionModel().getAnchorSelectionIndex();
  314. if (anchorRow != -1 && anchorColumn != -1 && !table.isEditing()) {
  315. if (!table.editCellAt(anchorRow, anchorColumn)) {
  316. return;
  317. }
  318. }
  319. // Forwarding events this way seems to put the component
  320. // in a state where it believes it has focus. In reality
  321. // the table retains focus - though it is difficult for
  322. // a user to tell, since the caret is visible and flashing.
  323. // Calling table.requestFocus() here, to get the focus back to
  324. // the table, seems to have no effect.
  325. Component editorComp = table.getEditorComponent();
  326. if (table.isEditing() && editorComp != null) {
  327. if (editorComp instanceof JComponent) {
  328. JComponent component = (JComponent)editorComp;
  329. map = component.getInputMap(JComponent.WHEN_FOCUSED);
  330. Object binding = (map != null) ? map.get(keyStroke) : null;
  331. if (binding == null) {
  332. map = component.getInputMap(JComponent.
  333. WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  334. binding = (map != null) ? map.get(keyStroke) : null;
  335. }
  336. if (binding != null) {
  337. ActionMap am = component.getActionMap();
  338. Action action = (am != null) ? am.get(binding) : null;
  339. if (action != null && SwingUtilities.
  340. notifyAction(action, keyStroke, e, component,
  341. e.getModifiers())) {
  342. e.consume();
  343. }
  344. }
  345. }
  346. }
  347. }
  348. }
  349. //
  350. // The Table's focus listener
  351. //
  352. /**
  353. * This inner class is marked "public" due to a compiler bug.
  354. * This class should be treated as a "protected" inner class.
  355. * Instantiate it only within subclasses of BasicTableUI.
  356. */
  357. class FocusHandler implements FocusListener {
  358. private void repaintAnchorCell( ) {
  359. int rc = table.getRowCount();
  360. int cc = table.getColumnCount();
  361. int ar = table.getSelectionModel().getAnchorSelectionIndex();
  362. int ac = table.getColumnModel().getSelectionModel().getAnchorSelectionIndex();
  363. if (ar < 0 || ar >= rc || ac < 0 || ac >= cc) {
  364. return;
  365. }
  366. Rectangle dirtyRect = table.getCellRect(ar, ac, false);
  367. table.repaint(dirtyRect);
  368. }
  369. public void focusGained(FocusEvent e) {
  370. repaintAnchorCell();
  371. }
  372. public void focusLost(FocusEvent e) {
  373. repaintAnchorCell();
  374. }
  375. }
  376. //
  377. // The Table's mouse and mouse motion listeners
  378. //
  379. /**
  380. * This inner class is marked "public" due to a compiler bug.
  381. * This class should be treated as a "protected" inner class.
  382. * Instantiate it only within subclasses of BasicTableUI.
  383. */
  384. class MouseInputHandler implements MouseInputListener {
  385. // Component receiving mouse events during editing.
  386. // May not be editorComponent.
  387. private Component dispatchComponent;
  388. private boolean selectedOnPress;
  389. // The Table's mouse listener methods.
  390. public void mouseClicked(MouseEvent e) {}
  391. private void setDispatchComponent(MouseEvent e) {
  392. Component editorComponent = table.getEditorComponent();
  393. Point p = e.getPoint();
  394. Point p2 = SwingUtilities.convertPoint(table, p, editorComponent);
  395. dispatchComponent = SwingUtilities.getDeepestComponentAt(editorComponent,
  396. p2.x, p2.y);
  397. }
  398. private boolean repostEvent(MouseEvent e) {
  399. // Check for isEditing() in case another event has
  400. // caused the editor to be removed. See bug #4306499.
  401. if (dispatchComponent == null || !table.isEditing()) {
  402. return false;
  403. }
  404. MouseEvent e2 = SwingUtilities.convertMouseEvent(table, e, dispatchComponent);
  405. dispatchComponent.dispatchEvent(e2);
  406. return true;
  407. }
  408. private void setValueIsAdjusting(boolean flag) {
  409. table.getSelectionModel().setValueIsAdjusting(flag);
  410. table.getColumnModel().getSelectionModel().setValueIsAdjusting(flag);
  411. }
  412. private boolean shouldIgnore(MouseEvent e) {
  413. return e.isConsumed() || (!(SwingUtilities.isLeftMouseButton(e) && table.isEnabled()));
  414. }
  415. public void mousePressed(MouseEvent e) {
  416. if (e.isConsumed()) {
  417. selectedOnPress = false;
  418. return;
  419. }
  420. selectedOnPress = true;
  421. adjustFocusAndSelection(e);
  422. }
  423. void adjustFocusAndSelection(MouseEvent e) {
  424. if (shouldIgnore(e)) {
  425. return;
  426. }
  427. Point p = e.getPoint();
  428. int row = table.rowAtPoint(p);
  429. int column = table.columnAtPoint(p);
  430. // The autoscroller can generate drag events outside the Table's range.
  431. if ((column == -1) || (row == -1)) {
  432. return;
  433. }
  434. if (table.editCellAt(row, column, e)) {
  435. setDispatchComponent(e);
  436. repostEvent(e);
  437. }
  438. else if (table.isRequestFocusEnabled()) {
  439. table.requestFocus();
  440. }
  441. CellEditor editor = table.getCellEditor();
  442. if (editor == null || editor.shouldSelectCell(e)) {
  443. boolean adjusting = (e.getID() == MouseEvent.MOUSE_PRESSED) ? true : false;
  444. setValueIsAdjusting(adjusting);
  445. table.changeSelection(row, column, e.isControlDown(), e.isShiftDown());
  446. }
  447. }
  448. public void mouseReleased(MouseEvent e) {
  449. if (selectedOnPress) {
  450. if (shouldIgnore(e)) {
  451. return;
  452. }
  453. repostEvent(e);
  454. dispatchComponent = null;
  455. setValueIsAdjusting(false);
  456. } else {
  457. adjustFocusAndSelection(e);
  458. }
  459. }
  460. public void mouseEntered(MouseEvent e) {}
  461. public void mouseExited(MouseEvent e) {}
  462. // The Table's mouse motion listener methods.
  463. public void mouseMoved(MouseEvent e) {}
  464. public void mouseDragged(MouseEvent e) {
  465. if (shouldIgnore(e)) {
  466. return;
  467. }
  468. repostEvent(e);
  469. CellEditor editor = table.getCellEditor();
  470. if (editor == null || editor.shouldSelectCell(e)) {
  471. Point p = e.getPoint();
  472. int row = table.rowAtPoint(p);
  473. int column = table.columnAtPoint(p);
  474. // The autoscroller can generate drag events outside the Table's range.
  475. if ((column == -1) || (row == -1)) {
  476. return;
  477. }
  478. table.changeSelection(row, column, false, true);
  479. }
  480. }
  481. }
  482. //
  483. // Factory methods for the Listeners
  484. //
  485. /**
  486. * Creates the key listener for handling keyboard navigation in the JTable.
  487. */
  488. protected KeyListener createKeyListener() {
  489. return null;
  490. }
  491. /**
  492. * Creates the focus listener for handling keyboard navigation in the JTable.
  493. */
  494. protected FocusListener createFocusListener() {
  495. return new FocusHandler();
  496. }
  497. /**
  498. * Creates the mouse listener for the JTable.
  499. */
  500. protected MouseInputListener createMouseInputListener() {
  501. return new MouseInputHandler();
  502. }
  503. /**
  504. * Creates the property change listener for the JTable.
  505. */
  506. private PropertyChangeListener createPropertyChangeListener() {
  507. return new PropertyChangeHandler();
  508. }
  509. public static void loadActionMap(ActionMap map) {
  510. // NOTE: this needs to remain static. If you have a need to
  511. // have Actions that reference the UI in the ActionMap,
  512. // then you'll also need to change the registeration of the
  513. // ActionMap.
  514. map.put("selectNextColumn", new NavigationalAction
  515. (1, 0, false, false, false));
  516. map.put("selectPreviousColumn", new NavigationalAction
  517. (-1, 0, false, false, false));
  518. map.put("selectNextRow", new NavigationalAction
  519. (0, 1, false, false, false));
  520. map.put("selectPreviousRow", new NavigationalAction
  521. (0, -1, false, false, false));
  522. map.put("selectNextColumnExtendSelection", new NavigationalAction
  523. (1, 0, false, true, false));
  524. map.put("selectPreviousColumnExtendSelection", new NavigationalAction
  525. (-1, 0, false, true, false));
  526. map.put("selectNextRowExtendSelection", new NavigationalAction
  527. (0, 1, false, true, false));
  528. map.put("selectPreviousRowExtendSelection", new NavigationalAction
  529. (0, -1, false, true, false));
  530. map.put("scrollUpChangeSelection",
  531. new PagingAction(false, false, true, false));
  532. map.put("scrollDownChangeSelection",
  533. new PagingAction(false, true, true, false));
  534. map.put("selectFirstColumn",
  535. new PagingAction(false, false, false, true));
  536. map.put("selectLastColumn",
  537. new PagingAction(false, true, false, true));
  538. map.put("scrollUpExtendSelection",
  539. new PagingAction(true, false, true, false));
  540. map.put("scrollDownExtendSelection",
  541. new PagingAction(true, true, true, false));
  542. map.put("selectFirstColumnExtendSelection",
  543. new PagingAction(true, false, false, true));
  544. map.put("selectLastColumnExtendSelection",
  545. new PagingAction(true, true, false, true));
  546. map.put("selectFirstRow",
  547. new PagingAction(false, false, true, true));
  548. map.put("selectLastRow",
  549. new PagingAction(false, true, true, true));
  550. map.put("selectFirstRowExtendSelection",
  551. new PagingAction(true, false, true, true));
  552. map.put("selectLastRowExtendSelection",
  553. new PagingAction(true, true, true, true));
  554. map.put("selectNextColumnCell",
  555. new NavigationalAction(1, 0, true, false, true));
  556. map.put("selectPreviousColumnCell",
  557. new NavigationalAction(-1, 0, true, false, true));
  558. map.put("selectNextRowCell",
  559. new NavigationalAction(0, 1, true, false, true));
  560. map.put("selectPreviousRowCell",
  561. new NavigationalAction(0, -1, true, false, true));
  562. map.put("selectAll", new SelectAllAction());
  563. map.put("cancel", new CancelEditingAction());
  564. map.put("startEditing", new StartEditingAction());
  565. map.put(TransferHandler.getCutAction().getValue(Action.NAME),
  566. TransferHandler.getCutAction());
  567. map.put(TransferHandler.getCopyAction().getValue(Action.NAME),
  568. TransferHandler.getCopyAction());
  569. map.put(TransferHandler.getPasteAction().getValue(Action.NAME),
  570. TransferHandler.getPasteAction());
  571. // PENDING: this is currently broke, the actions should do
  572. // the necessary mapping and not require us to reregister the actions.
  573. // In order to reregister actions we would have to make this
  574. // a per component action map.
  575. map.put("scrollLeftChangeSelection",
  576. new PagingAction(false, false, false, false));
  577. map.put("scrollRightChangeSelection",
  578. new PagingAction(false, true, false, false));
  579. map.put("scrollLeftExtendSelection",
  580. new PagingAction(true, false, false, false));
  581. map.put("scrollRightExtendSelection",
  582. new PagingAction(true, true, false, false));
  583. }
  584. //
  585. // The installation/uninstall procedures and support
  586. //
  587. public static ComponentUI createUI(JComponent c) {
  588. return new SynthTableUI();
  589. }
  590. // Installation
  591. public void installUI(JComponent c) {
  592. table = (JTable)c;
  593. rendererPane = new CellRendererPane();
  594. table.add(rendererPane);
  595. installDefaults();
  596. installListeners();
  597. installKeyboardActions();
  598. }
  599. /**
  600. * Initialize JTable properties, e.g. font, foreground, and background.
  601. * The font, foreground, and background properties are only set if their
  602. * current value is either null or a UIResource, other properties are set
  603. * if the current value is null.
  604. *
  605. * @see #installUI
  606. */
  607. protected void installDefaults() {
  608. fetchStyle(table);
  609. TransferHandler th = table.getTransferHandler();
  610. if (th == null || th instanceof UIResource) {
  611. table.setTransferHandler(defaultTransferHandler);
  612. }
  613. DropTarget dropTarget = table.getDropTarget();
  614. if (dropTarget instanceof UIResource) {
  615. if (defaultDropTargetListener == null) {
  616. defaultDropTargetListener = new TableDropTargetListener();
  617. }
  618. try {
  619. dropTarget.addDropTargetListener(defaultDropTargetListener);
  620. } catch (TooManyListenersException tmle) {
  621. // should not happen... swing drop target is multicast
  622. }
  623. }
  624. }
  625. private void fetchStyle(JTable c) {
  626. SynthContext context = getContext(c, ENABLED);
  627. SynthStyle oldStyle = style;
  628. style = SynthLookAndFeel.updateStyle(context, this);
  629. if (style != oldStyle) {
  630. context.setComponentState(ENABLED | SELECTED);
  631. Color sbg = table.getSelectionBackground();
  632. if (sbg == null || sbg instanceof UIResource) {
  633. table.setSelectionBackground(style.getColor(
  634. context, ColorType.TEXT_BACKGROUND));
  635. }
  636. Color sfg = table.getSelectionForeground();
  637. if (sfg == null || sfg instanceof UIResource) {
  638. table.setSelectionForeground(style.getColor(
  639. context, ColorType.TEXT_FOREGROUND));
  640. }
  641. context.setComponentState(ENABLED);
  642. Color gridColor = table.getGridColor();
  643. if (gridColor == null || gridColor instanceof UIResource) {
  644. gridColor = (Color)style.get(context, "Table.gridColor");
  645. if (gridColor == null) {
  646. gridColor = style.getColor(context, ColorType.FOREGROUND);
  647. }
  648. table.setGridColor(gridColor);
  649. }
  650. }
  651. context.dispose();
  652. }
  653. /**
  654. * Attaches listeners to the JTable.
  655. */
  656. protected void installListeners() {
  657. focusListener = createFocusListener();
  658. keyListener = createKeyListener();
  659. mouseInputListener = createMouseInputListener();
  660. propertyChangeListener = createPropertyChangeListener();
  661. table.addFocusListener(focusListener);
  662. table.addKeyListener(keyListener);
  663. table.addMouseListener(defaultDragRecognizer);
  664. table.addMouseMotionListener(defaultDragRecognizer);
  665. table.addMouseListener(mouseInputListener);
  666. table.addMouseMotionListener(mouseInputListener);
  667. table.addPropertyChangeListener(propertyChangeListener);
  668. }
  669. /**
  670. * Register all keyboard actions on the JTable.
  671. */
  672. protected void installKeyboardActions() {
  673. LazyActionMap.installLazyActionMap(table, SynthTableUI.class,
  674. "Table.actionMap");
  675. InputMap inputMap = getInputMap(JComponent.
  676. WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  677. SwingUtilities.replaceUIInputMap(table,
  678. JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
  679. inputMap);
  680. }
  681. InputMap getInputMap(int condition) {
  682. if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
  683. SynthContext context = getContext(table, ENABLED);
  684. InputMap keyMap = (InputMap)style.get(context,
  685. "Table.ancestorInputMap");
  686. InputMap rtlKeyMap;
  687. if (!table.getComponentOrientation().isLeftToRight() &&
  688. ((rtlKeyMap = (InputMap)style.get(context,
  689. "Table.ancestorInputMap.RightToLeft")) == null)) {
  690. rtlKeyMap.setParent(keyMap);
  691. keyMap = rtlKeyMap;
  692. }
  693. context.dispose();
  694. return keyMap;
  695. }
  696. return null;
  697. }
  698. // Uninstallation
  699. public void uninstallUI(JComponent c) {
  700. uninstallDefaults();
  701. uninstallListeners();
  702. uninstallKeyboardActions();
  703. table.remove(rendererPane);
  704. rendererPane = null;
  705. table = null;
  706. }
  707. protected void uninstallDefaults() {
  708. if (table.getTransferHandler() instanceof UIResource) {
  709. table.setTransferHandler(null);
  710. }
  711. SynthContext context = getContext(table, ENABLED);
  712. style.uninstallDefaults(context);
  713. context.dispose();
  714. style = null;
  715. }
  716. protected void uninstallListeners() {
  717. table.removeFocusListener(focusListener);
  718. table.removeKeyListener(keyListener);
  719. table.removeMouseListener(defaultDragRecognizer);
  720. table.removeMouseMotionListener(defaultDragRecognizer);
  721. table.removeMouseListener(mouseInputListener);
  722. table.removeMouseMotionListener(mouseInputListener);
  723. table.removePropertyChangeListener(propertyChangeListener);
  724. focusListener = null;
  725. keyListener = null;
  726. mouseInputListener = null;
  727. propertyChangeListener = null;
  728. }
  729. protected void uninstallKeyboardActions() {
  730. SwingUtilities.replaceUIInputMap(table, JComponent.
  731. WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
  732. SwingUtilities.replaceUIActionMap(table, null);
  733. }
  734. //
  735. // SynthUI
  736. //
  737. public SynthContext getContext(JComponent c) {
  738. return getContext(c, getComponentState(c));
  739. }
  740. private SynthContext getContext(JComponent c, int state) {
  741. return SynthContext.getContext(SynthContext.class, c,
  742. SynthLookAndFeel.getRegion(c), style, state);
  743. }
  744. private Region getRegion(JComponent c) {
  745. return SynthLookAndFeel.getRegion(c);
  746. }
  747. private int getComponentState(JComponent c) {
  748. return SynthLookAndFeel.getComponentState(c);
  749. }
  750. //
  751. // Size Methods
  752. //
  753. private Dimension createTableSize(long width) {
  754. int height = 0;
  755. int rowCount = table.getRowCount();
  756. if (rowCount > 0 && table.getColumnCount() > 0) {
  757. Rectangle r = table.getCellRect(rowCount-1, 0, true);
  758. height = r.y + r.height;
  759. }
  760. // Width is always positive. The call to abs() is a workaround for
  761. // a bug in the 1.1.6 JIT on Windows.
  762. long tmp = Math.abs(width);
  763. if (tmp > Integer.MAX_VALUE) {
  764. tmp = Integer.MAX_VALUE;
  765. }
  766. return new Dimension((int)tmp, height);
  767. }
  768. /**
  769. * Return the minimum size of the table. The minimum height is the
  770. * row height times the number of rows.
  771. * The minimum width is the sum of the minimum widths of each column.
  772. */
  773. public Dimension getMinimumSize(JComponent c) {
  774. long width = 0;
  775. Enumeration enumeration = table.getColumnModel().getColumns();
  776. while (enumeration.hasMoreElements()) {
  777. TableColumn aColumn = (TableColumn)enumeration.nextElement();
  778. width = width + aColumn.getMinWidth();
  779. }
  780. return createTableSize(width);
  781. }
  782. /**
  783. * Return the preferred size of the table. The preferred height is the
  784. * row height times the number of rows.
  785. * The preferred width is the sum of the preferred widths of each column.
  786. */
  787. public Dimension getPreferredSize(JComponent c) {
  788. long width = 0;
  789. Enumeration enumeration = table.getColumnModel().getColumns();
  790. while (enumeration.hasMoreElements()) {
  791. TableColumn aColumn = (TableColumn)enumeration.nextElement();
  792. width = width + aColumn.getPreferredWidth();
  793. }
  794. return createTableSize(width);
  795. }
  796. /**
  797. * Return the maximum size of the table. The maximum height is the
  798. * row heighttimes the number of rows.
  799. * The maximum width is the sum of the maximum widths of each column.
  800. */
  801. public Dimension getMaximumSize(JComponent c) {
  802. long width = 0;
  803. Enumeration enumeration = table.getColumnModel().getColumns();
  804. while (enumeration.hasMoreElements()) {
  805. TableColumn aColumn = (TableColumn)enumeration.nextElement();
  806. width = width + aColumn.getMaxWidth();
  807. }
  808. return createTableSize(width);
  809. }
  810. //
  811. // Paint methods and support
  812. //
  813. public void update(Graphics g, JComponent c) {
  814. SynthContext context = getContext(c);
  815. SynthLookAndFeel.update(context, g);
  816. paint(context, g);
  817. context.dispose();
  818. }
  819. public void paint(Graphics g, JComponent c) {
  820. SynthContext context = getContext(c);
  821. paint(context, g);
  822. context.dispose();
  823. }
  824. protected void paint(SynthContext context, Graphics g) {
  825. if (table.getRowCount() <= 0 || table.getColumnCount() <= 0) {
  826. return;
  827. }
  828. Rectangle clip = g.getClipBounds();
  829. Point upperLeft = clip.getLocation();
  830. Point lowerRight = new Point(clip.x + clip.width - 1, clip.y + clip.height - 1);
  831. int rMin = table.rowAtPoint(upperLeft);
  832. int rMax = table.rowAtPoint(lowerRight);
  833. // This should never happen.
  834. if (rMin == -1) {
  835. rMin = 0;
  836. }
  837. // If the table does not have enough rows to fill the view we'll get -1.
  838. // Replace this with the index of the last row.
  839. if (rMax == -1) {
  840. rMax = table.getRowCount()-1;
  841. }
  842. boolean ltr = table.getComponentOrientation().isLeftToRight();
  843. int cMin = table.columnAtPoint(ltr ? upperLeft : lowerRight);
  844. int cMax = table.columnAtPoint(ltr ? lowerRight : upperLeft);
  845. // This should never happen.
  846. if (cMin == -1) {
  847. cMin = 0;
  848. }
  849. // If the table does not have enough columns to fill the view we'll get -1.
  850. // Replace this with the index of the last column.
  851. if (cMax == -1) {
  852. cMax = table.getColumnCount()-1;
  853. }
  854. // Paint the grid.
  855. paintGrid(context, g, rMin, rMax, cMin, cMax);
  856. // Paint the cells.
  857. paintCells(context, g, rMin, rMax, cMin, cMax);
  858. // PENDING: We may want to add a special Renderer for painting
  859. // the background of the selected cells.
  860. }
  861. /*
  862. * Paints the grid lines within <I>aRect</I>, using the grid
  863. * color set with <I>setGridColor</I>. Paints vertical lines
  864. * if <code>getShowVerticalLines()</code> returns true and paints
  865. * horizontal lines if <code>getShowHorizontalLines()</code>
  866. * returns true.
  867. */
  868. private void paintGrid(SynthContext context, Graphics g, int rMin,
  869. int rMax, int cMin, int cMax) {
  870. g.setColor(table.getGridColor());
  871. Rectangle minCell = table.getCellRect(rMin, cMin, true);
  872. Rectangle maxCell = table.getCellRect(rMax, cMax, true);
  873. Rectangle damagedArea = minCell.union( maxCell );
  874. SynthGraphics synthG = context.getStyle().getSynthGraphics(context);
  875. if (table.getShowHorizontalLines()) {
  876. int tableWidth = damagedArea.x + damagedArea.width;
  877. int y = damagedArea.y;
  878. for (int row = rMin; row <= rMax; row++) {
  879. y += table.getRowHeight(row);
  880. synthG.drawLine(context, "Table.grid",
  881. g, damagedArea.x, y - 1, tableWidth - 1,y - 1);
  882. }
  883. }
  884. if (table.getShowVerticalLines()) {
  885. TableColumnModel cm = table.getColumnModel();
  886. int tableHeight = damagedArea.y + damagedArea.height;
  887. int x;
  888. if (table.getComponentOrientation().isLeftToRight()) {
  889. x = damagedArea.x;
  890. for (int column = cMin; column <= cMax; column++) {
  891. int w = cm.getColumn(column).getWidth();
  892. x += w;
  893. synthG.drawLine(context, "Table.grid", g, x - 1, 0,
  894. x - 1, tableHeight - 1);
  895. }
  896. } else {
  897. x = damagedArea.x + damagedArea.width;
  898. for (int column = cMin; column < cMax; column++) {
  899. int w = cm.getColumn(column).getWidth();
  900. x -= w;
  901. synthG.drawLine(context, "Table.grid", g, x - 1, 0, x - 1,
  902. tableHeight - 1);
  903. }
  904. x -= cm.getColumn(cMax).getWidth();
  905. synthG.drawLine(context, "Table.grid", g, x, 0, x,
  906. tableHeight - 1);
  907. }
  908. }
  909. }
  910. private int viewIndexForColumn(TableColumn aColumn) {
  911. TableColumnModel cm = table.getColumnModel();
  912. for (int column = 0; column < cm.getColumnCount(); column++) {
  913. if (cm.getColumn(column) == aColumn) {
  914. return column;
  915. }
  916. }
  917. return -1;
  918. }
  919. private void paintCells(SynthContext context, Graphics g, int rMin,
  920. int rMax, int cMin, int cMax) {
  921. JTableHeader header = table.getTableHeader();
  922. TableColumn draggedColumn = (header == null) ? null : header.getDraggedColumn();
  923. TableColumnModel cm = table.getColumnModel();
  924. int columnMargin = cm.getColumnMargin();
  925. Rectangle cellRect;
  926. TableColumn aColumn;
  927. int columnWidth;
  928. if (table.getComponentOrientation().isLeftToRight()) {
  929. for(int row = rMin; row <= rMax; row++) {
  930. cellRect = table.getCellRect(row, cMin, false);
  931. for(int column = cMin; column <= cMax; column++) {
  932. aColumn = cm.getColumn(column);
  933. columnWidth = aColumn.getWidth();
  934. cellRect.width = columnWidth - columnMargin;
  935. if (aColumn != draggedColumn) {
  936. paintCell(g, cellRect, row, column);
  937. }
  938. cellRect.x += columnWidth;
  939. }
  940. }
  941. } else {
  942. for(int row = rMin; row <= rMax; row++) {
  943. cellRect = table.getCellRect(row, cMin, false);
  944. aColumn = cm.getColumn(cMin);
  945. if (aColumn != draggedColumn) {
  946. columnWidth = aColumn.getWidth();
  947. cellRect.width = columnWidth - columnMargin;
  948. paintCell(g, cellRect, row, cMin);
  949. }
  950. for(int column = cMin+1; column <= cMax; column++) {
  951. aColumn = cm.getColumn(column);
  952. columnWidth = aColumn.getWidth();
  953. cellRect.width = columnWidth - columnMargin;
  954. cellRect.x -= columnWidth;
  955. if (aColumn != draggedColumn) {
  956. paintCell(g, cellRect, row, column);
  957. }
  958. }
  959. }
  960. }
  961. // Paint the dragged column if we are dragging.
  962. if (draggedColumn != null) {
  963. paintDraggedArea(context, g, rMin, rMax, draggedColumn, header.getDraggedDistance());
  964. }
  965. // Remove any renderers that may be left in the rendererPane.
  966. rendererPane.removeAll();
  967. }
  968. private void paintDraggedArea(SynthContext context, Graphics g, int rMin, int rMax, TableColumn draggedColumn, int distance) {
  969. int draggedColumnIndex = viewIndexForColumn(draggedColumn);
  970. Rectangle minCell = table.getCellRect(rMin, draggedColumnIndex, true);
  971. Rectangle maxCell = table.getCellRect(rMax, draggedColumnIndex, true);
  972. Rectangle vacatedColumnRect = minCell.union(maxCell);
  973. // Paint a gray well in place of the moving column.
  974. g.setColor(table.getParent().getBackground());
  975. g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,
  976. vacatedColumnRect.width, vacatedColumnRect.height);
  977. // Move to the where the cell has been dragged.
  978. vacatedColumnRect.x += distance;
  979. // Fill the background.
  980. g.setColor(context.getStyle().getColor(context, ColorType.BACKGROUND));
  981. g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,
  982. vacatedColumnRect.width, vacatedColumnRect.height);
  983. SynthGraphics synthG = context.getStyle().getSynthGraphics(context);
  984. // Paint the vertical grid lines if necessary.
  985. if (table.getShowVerticalLines()) {
  986. g.setColor(table.getGridColor());
  987. int x1 = vacatedColumnRect.x;
  988. int y1 = vacatedColumnRect.y;
  989. int x2 = x1 + vacatedColumnRect.width - 1;
  990. int y2 = y1 + vacatedColumnRect.height - 1;
  991. // Left
  992. synthG.drawLine(context, "Table.grid", g, x1-1, y1, x1-1, y2);
  993. // Right
  994. synthG.drawLine(context, "Table.grid", g, x2, y1, x2, y2);
  995. }
  996. for(int row = rMin; row <= rMax; row++) {
  997. // Render the cell value
  998. Rectangle r = table.getCellRect(row, draggedColumnIndex, false);
  999. r.x += distance;
  1000. paintCell(g, r, row, draggedColumnIndex);
  1001. // Paint the (lower) horizontal grid line if necessary.
  1002. if (table.getShowHorizontalLines()) {
  1003. g.setColor(table.getGridColor());
  1004. Rectangle rcr = table.getCellRect(row, draggedColumnIndex, true);
  1005. rcr.x += distance;
  1006. int x1 = rcr.x;
  1007. int y1 = rcr.y;
  1008. int x2 = x1 + rcr.width - 1;
  1009. int y2 = y1 + rcr.height - 1;
  1010. synthG.drawLine(context, "Table.grid", g, x1, y2, x2, y2);
  1011. }
  1012. }
  1013. }
  1014. private void paintCell(Graphics g, Rectangle cellRect, int row, int column) {
  1015. if (table.isEditing() && table.getEditingRow()==row &&
  1016. table.getEditingColumn()==column) {
  1017. Component component = table.getEditorComponent();
  1018. component.setBounds(cellRect);
  1019. component.validate();
  1020. }
  1021. else {
  1022. TableCellRenderer renderer = table.getCellRenderer(row, column);
  1023. Component component = table.prepareRenderer(renderer, row, column);
  1024. rendererPane.paintComponent(g, component, table, cellRect.x, cellRect.y,
  1025. cellRect.width, cellRect.height, true);
  1026. }
  1027. }
  1028. private static final TableDragGestureRecognizer defaultDragRecognizer = new TableDragGestureRecognizer();
  1029. /**
  1030. * Drag gesture recognizer for JTable components
  1031. */
  1032. static class TableDragGestureRecognizer extends SynthDragGestureRecognizer {
  1033. /**
  1034. * Determines if the following are true:
  1035. * <ul>
  1036. * <li>the press event is located over a selection
  1037. * <li>the dragEnabled property is true
  1038. * <li>A TranferHandler is installed
  1039. * </ul>
  1040. * <p>
  1041. * This is implemented to perform the superclass behavior
  1042. * followed by a check if the dragEnabled
  1043. * property is set and if the location picked is selected.
  1044. */
  1045. protected boolean isDragPossible(MouseEvent e) {
  1046. if (super.isDragPossible(e)) {
  1047. JTable table = (JTable) this.getComponent(e);
  1048. if (table.getDragEnabled()) {
  1049. Point p = e.getPoint();
  1050. int row = table.rowAtPoint(p);
  1051. int column = table.columnAtPoint(p);
  1052. if ((column != -1) && (row != -1) && table.isCellSelected(row, column)) {
  1053. return true;
  1054. }
  1055. }
  1056. }
  1057. return false;
  1058. }
  1059. }
  1060. private static DropTargetListener defaultDropTargetListener = null;
  1061. /**
  1062. * A DropTargetListener to extend the default Swing handling of drop operations
  1063. * by moving the tree selection to the nearest location to the mouse pointer.
  1064. * Also adds autoscroll capability.
  1065. */
  1066. static class TableDropTargetListener extends SynthDropTargetListener {
  1067. /**
  1068. * called to save the state of a component in case it needs to
  1069. * be restored because a drop is not performed.
  1070. */
  1071. protected void saveComponentState(JComponent comp) {
  1072. JTable table = (JTable) comp;
  1073. rows = table.getSelectedRows();
  1074. cols = table.getSelectedColumns();
  1075. }
  1076. /**
  1077. * called to restore the state of a component
  1078. * because a drop was not performed.
  1079. */
  1080. protected void restoreComponentState(JComponent comp) {
  1081. JTable table = (JTable) comp;
  1082. table.clearSelection();
  1083. for (int i = 0; i < rows.length; i++) {
  1084. table.addRowSelectionInterval(rows[i], rows[i]);
  1085. }
  1086. for (int i = 0; i < cols.length; i++) {
  1087. table.addColumnSelectionInterval(cols[i], cols[i]);
  1088. }
  1089. }
  1090. /**
  1091. * called to set the insertion location to match the current
  1092. * mouse pointer coordinates.
  1093. */
  1094. protected void updateInsertionLocation(JComponent comp, Point p) {
  1095. JTable table = (JTable) comp;
  1096. int row = table.rowAtPoint(p);
  1097. int col = table.columnAtPoint(p);
  1098. if (row != -1) {
  1099. table.setRowSelectionInterval(row, row);
  1100. }
  1101. if (col != -1) {
  1102. table.setColumnSelectionInterval(col, col);
  1103. }
  1104. }
  1105. private int[] rows;
  1106. private int[] cols;
  1107. }
  1108. private static final TransferHandler defaultTransferHandler = new TableTransferHandler();
  1109. static class TableTransferHandler extends TransferHandler implements UIResource {
  1110. /**
  1111. * Create a Transferable to use as the source for a data transfer.
  1112. *
  1113. * @param c The component holding the data to be transfered. This
  1114. * argument is provided to enable sharing of TransferHandlers by
  1115. * multiple components.
  1116. * @return The representation of the data to be transfered.
  1117. *
  1118. */
  1119. protected Transferable createTransferable(JComponent c) {
  1120. if (c instanceof JTable) {
  1121. JTable table = (JTable) c;
  1122. int[] rows;
  1123. int[] cols;
  1124. if (!table.getRowSelectionAllowed() && !table.getColumnSelectionAllowed()) {
  1125. return null;
  1126. }
  1127. if (!table.getRowSelectionAllowed()) {
  1128. int rowCount = table.getRowCount();
  1129. rows = new int[rowCount];
  1130. for (int counter = 0; counter < rowCount; counter++) {
  1131. rows[counter] = counter;
  1132. }
  1133. } else {
  1134. rows = table.getSelectedRows();
  1135. }
  1136. if (!table.getColumnSelectionAllowed()) {
  1137. int colCount = table.getColumnCount();
  1138. cols = new int[colCount];
  1139. for (int counter = 0; counter < colCount; counter++) {
  1140. cols[counter] = counter;
  1141. }
  1142. } else {
  1143. cols = table.getSelectedColumns();
  1144. }
  1145. if (rows == null || cols == null || rows.length == 0 || cols.length == 0) {
  1146. return null;
  1147. }
  1148. StringBuffer plainBuf = new StringBuffer();
  1149. StringBuffer htmlBuf = new StringBuffer();
  1150. htmlBuf.append("<html>\n<body>\n<table>\n");
  1151. for (int row = 0; row < rows.length; row++) {
  1152. htmlBuf.append("<tr>\n");
  1153. for (int col = 0; col < cols.length; col++) {
  1154. Object obj = table.getValueAt(rows[row], cols[col]);
  1155. String val = ((obj == null) ? "" : obj.toString());
  1156. plainBuf.append(val + "\t");
  1157. htmlBuf.append(" <td>" + val + "</td>\n");
  1158. }
  1159. // we want a newline at the end of each line and not a tab
  1160. plainBuf.deleteCharAt(plainBuf.length() - 1).append("\n");
  1161. htmlBuf.append("</tr>\n");
  1162. }
  1163. // remove the last newline
  1164. plainBuf.deleteCharAt(plainBuf.length() - 1);
  1165. htmlBuf.append("</table>\n</body>\n</html>");
  1166. return new SynthTransferable(plainBuf.toString(), htmlBuf.toString());
  1167. }
  1168. return null;
  1169. }
  1170. public int getSourceActions(JComponent c) {
  1171. return COPY;
  1172. }
  1173. }
  1174. /**
  1175. * PropertyChangeListener for the table. Updates the appropriate
  1176. * varaible based on what changes.
  1177. */
  1178. private class PropertyChangeHandler implements
  1179. PropertyChangeListener {
  1180. public void propertyChange(PropertyChangeEvent event) {
  1181. String changeName = event.getPropertyName();
  1182. if (SynthLookAndFeel.shouldUpdateStyle(event)) {
  1183. fetchStyle((JTable)event.getSource());
  1184. }
  1185. if (changeName.equals("componentOrientation")) {
  1186. InputMap inputMap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  1187. SwingUtilities.replaceUIInputMap(table,
  1188. JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
  1189. inputMap);
  1190. JTableHeader header = table.getTableHeader();
  1191. if (header != null) {
  1192. header.setComponentOrientation((ComponentOrientation)event.getNewValue());
  1193. }
  1194. } else if ("transferHandler".equals(changeName)) {
  1195. DropTarget dropTarget = table.getDropTarget();
  1196. if (dropTarget instanceof UIResource) {
  1197. if (defaultDropTargetListener == null) {
  1198. defaultDropTargetListener = new TableDropTargetListener();
  1199. }
  1200. try {
  1201. dropTarget.addDropTargetListener(defaultDropTargetListener);
  1202. } catch (TooManyListenersException tmle) {
  1203. // should not happen... swing drop target is multicast
  1204. }
  1205. }
  1206. }
  1207. }
  1208. } // End of BasicTableUI.PropertyChangeHandler
  1209. } // End of Class BasicTableUI