1. /*
  2. * @(#)JTableHeader.java 1.66 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.table;
  8. import java.util.*;
  9. import java.awt.*;
  10. import java.awt.event.*;
  11. import javax.swing.*;
  12. import javax.swing.event.*;
  13. import javax.swing.plaf.*;
  14. import javax.accessibility.*;
  15. import java.beans.PropertyChangeListener;
  16. import java.io.ObjectOutputStream;
  17. import java.io.ObjectInputStream;
  18. import java.io.IOException;
  19. /**
  20. * This is the object which manages the header of the <code>JTable</code>.
  21. * <p>
  22. * <strong>Warning:</strong>
  23. * Serialized objects of this class will not be compatible with
  24. * future Swing releases. The current serialization support is
  25. * appropriate for short term storage or RMI between applications running
  26. * the same version of Swing. As of 1.4, support for long term storage
  27. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  28. * has been added to the <code>java.beans</code> package.
  29. * Please see {@link java.beans.XMLEncoder}.
  30. *
  31. * @version 1.66 12/19/03
  32. * @author Alan Chung
  33. * @author Philip Milne
  34. * @see javax.swing.JTable
  35. */
  36. public class JTableHeader extends JComponent implements TableColumnModelListener, Accessible
  37. {
  38. /**
  39. * @see #getUIClassID
  40. * @see #readObject
  41. */
  42. private static final String uiClassID = "TableHeaderUI";
  43. //
  44. // Instance Variables
  45. //
  46. /**
  47. * The table for which this object is the header;
  48. * the default is <code>null</code>.
  49. */
  50. protected JTable table;
  51. /**
  52. * The <code>TableColumnModel</code> of the table header.
  53. */
  54. protected TableColumnModel columnModel;
  55. /**
  56. * If true, reordering of columns are allowed by the user;
  57. * the default is true.
  58. */
  59. protected boolean reorderingAllowed;
  60. /**
  61. * If true, resizing of columns are allowed by the user;
  62. * the default is true.
  63. */
  64. protected boolean resizingAllowed;
  65. /**
  66. * Obsolete as of Java 2 platform v1.3. Real time repaints, in response
  67. * to column dragging or resizing, are now unconditional.
  68. */
  69. /*
  70. * If this flag is true, then the header will repaint the table as
  71. * a column is dragged or resized; the default is true.
  72. */
  73. protected boolean updateTableInRealTime;
  74. /** The index of the column being resized. <code>null</code> if not resizing. */
  75. transient protected TableColumn resizingColumn;
  76. /** The index of the column being dragged. <code>null</code> if not dragging. */
  77. transient protected TableColumn draggedColumn;
  78. /** The distance from its original position the column has been dragged. */
  79. transient protected int draggedDistance;
  80. /**
  81. * The default renderer to be used when a <code>TableColumn</code>
  82. * does not define a <code>headerRenderer</code>.
  83. */
  84. private TableCellRenderer defaultRenderer;
  85. //
  86. // Constructors
  87. //
  88. /**
  89. * Constructs a <code>JTableHeader</code> with a default
  90. * <code>TableColumnModel</code>.
  91. *
  92. * @see #createDefaultColumnModel
  93. */
  94. public JTableHeader() {
  95. this(null);
  96. }
  97. /**
  98. * Constructs a <code>JTableHeader</code> which is initialized with
  99. * <code>cm</code> as the column model. If <code>cm</code> is
  100. * <code>null</code> this method will initialize the table header
  101. * with a default <code>TableColumnModel</code>.
  102. *
  103. * @param cm the column model for the table
  104. * @see #createDefaultColumnModel
  105. */
  106. public JTableHeader(TableColumnModel cm) {
  107. super();
  108. setFocusable(false);
  109. if (cm == null)
  110. cm = createDefaultColumnModel();
  111. setColumnModel(cm);
  112. // Initialize local ivars
  113. initializeLocalVars();
  114. // Get UI going
  115. updateUI();
  116. }
  117. //
  118. // Local behavior attributes
  119. //
  120. /**
  121. * Sets the table associated with this header.
  122. * @param table the new table
  123. * @beaninfo
  124. * bound: true
  125. * description: The table associated with this header.
  126. */
  127. public void setTable(JTable table) {
  128. JTable old = this.table;
  129. this.table = table;
  130. firePropertyChange("table", old, table);
  131. }
  132. /**
  133. * Returns the table associated with this header.
  134. * @return the <code>table</code> property
  135. */
  136. public JTable getTable() {
  137. return table;
  138. }
  139. /**
  140. * Sets whether the user can drag column headers to reorder columns.
  141. *
  142. * @param reorderingAllowed true if the table view should allow
  143. * reordering; otherwise false
  144. * @see #getReorderingAllowed
  145. * @beaninfo
  146. * bound: true
  147. * description: Whether the user can drag column headers to reorder columns.
  148. */
  149. public void setReorderingAllowed(boolean reorderingAllowed) {
  150. boolean old = this.reorderingAllowed;
  151. this.reorderingAllowed = reorderingAllowed;
  152. firePropertyChange("reorderingAllowed", old, reorderingAllowed);
  153. }
  154. /**
  155. * Returns true if the user is allowed to rearrange columns by
  156. * dragging their headers, false otherwise. The default is true. You can
  157. * rearrange columns programmatically regardless of this setting.
  158. *
  159. * @return the <code>reorderingAllowed</code> property
  160. * @see #setReorderingAllowed
  161. */
  162. public boolean getReorderingAllowed() {
  163. return reorderingAllowed;
  164. }
  165. /**
  166. * Sets whether the user can resize columns by dragging between headers.
  167. *
  168. * @param resizingAllowed true if table view should allow
  169. * resizing
  170. * @see #getResizingAllowed
  171. * @beaninfo
  172. * bound: true
  173. * description: Whether the user can resize columns by dragging between headers.
  174. */
  175. public void setResizingAllowed(boolean resizingAllowed) {
  176. boolean old = this.resizingAllowed;
  177. this.resizingAllowed = resizingAllowed;
  178. firePropertyChange("resizingAllowed", old, resizingAllowed);
  179. }
  180. /**
  181. * Returns true if the user is allowed to resize columns by dragging
  182. * between their headers, false otherwise. The default is true. You can
  183. * resize columns programmatically regardless of this setting.
  184. *
  185. * @return the <code>resizingAllowed</code> property
  186. * @see #setResizingAllowed
  187. */
  188. public boolean getResizingAllowed() {
  189. return resizingAllowed;
  190. }
  191. /**
  192. * Returns the the dragged column, if and only if, a drag is in
  193. * process, otherwise returns <code>null</code>.
  194. *
  195. * @return the dragged column, if a drag is in
  196. * process, otherwise returns <code>null</code>
  197. * @see #getDraggedDistance
  198. */
  199. public TableColumn getDraggedColumn() {
  200. return draggedColumn;
  201. }
  202. /**
  203. * Returns the column's horizontal distance from its original
  204. * position, if and only if, a drag is in process. Otherwise, the
  205. * the return value is meaningless.
  206. *
  207. * @return the column's horizontal distance from its original
  208. * position, if a drag is in process, otherwise the return
  209. * value is meaningless
  210. * @see #getDraggedColumn
  211. */
  212. public int getDraggedDistance() {
  213. return draggedDistance;
  214. }
  215. /**
  216. * Returns the resizing column. If no column is being
  217. * resized this method returns <code>null</code>.
  218. *
  219. * @return the resizing column, if a resize is in process, otherwise
  220. * returns <code>null</code>
  221. */
  222. public TableColumn getResizingColumn() {
  223. return resizingColumn;
  224. }
  225. /**
  226. * Obsolete as of Java 2 platform v1.3. Real time repaints, in response to
  227. * column dragging or resizing, are now unconditional.
  228. */
  229. /*
  230. * Sets whether the body of the table updates in real time when
  231. * a column is resized or dragged.
  232. *
  233. * @param flag true if tableView should update
  234. * the body of the table in real time
  235. * @see #getUpdateTableInRealTime
  236. */
  237. public void setUpdateTableInRealTime(boolean flag) {
  238. updateTableInRealTime = flag;
  239. }
  240. /**
  241. * Obsolete as of Java 2 platform v1.3. Real time repaints, in response to
  242. * column dragging or resizing, are now unconditional.
  243. */
  244. /*
  245. * Returns true if the body of the table view updates in real
  246. * time when a column is resized or dragged. User can set this flag to
  247. * false to speed up the table's response to user resize or drag actions.
  248. * The default is true.
  249. *
  250. * @return true if the table updates in real time
  251. * @see #setUpdateTableInRealTime
  252. */
  253. public boolean getUpdateTableInRealTime() {
  254. return updateTableInRealTime;
  255. }
  256. /**
  257. * Sets the default renderer to be used when no <code>headerRenderer</code>
  258. * is defined by a <code>TableColumn</code>.
  259. * @param defaultRenderer the default renderer
  260. */
  261. public void setDefaultRenderer(TableCellRenderer defaultRenderer) {
  262. this.defaultRenderer = defaultRenderer;
  263. }
  264. /**
  265. * Returns the default renderer used when no <code>headerRenderer</code>
  266. * is defined by a <code>TableColumn</code>.
  267. * @return the default renderer
  268. */
  269. public TableCellRenderer getDefaultRenderer() {
  270. return defaultRenderer;
  271. }
  272. /**
  273. * Returns the index of the column that <code>point</code> lies in, or -1 if it
  274. * lies out of bounds.
  275. *
  276. * @return the index of the column that <code>point</code> lies in, or -1 if it
  277. * lies out of bounds
  278. */
  279. public int columnAtPoint(Point point) {
  280. int x = point.x;
  281. if (!getComponentOrientation().isLeftToRight()) {
  282. x = getWidthInRightToLeft() - x;
  283. }
  284. return getColumnModel().getColumnIndexAtX(x);
  285. }
  286. /**
  287. * Returns the rectangle containing the header tile at <code>column</code>.
  288. * When the <code>column</code> parameter is out of bounds this method uses the
  289. * same conventions as the <code>JTable</code> method <code>getCellRect</code>.
  290. *
  291. * @return the rectangle containing the header tile at <code>column</code>
  292. * @see JTable#getCellRect
  293. */
  294. public Rectangle getHeaderRect(int column) {
  295. Rectangle r = new Rectangle();
  296. TableColumnModel cm = getColumnModel();
  297. r.height = getHeight();
  298. if (column < 0) {
  299. // x = width = 0;
  300. if( !getComponentOrientation().isLeftToRight() ) {
  301. r.x = getWidthInRightToLeft();
  302. }
  303. }
  304. else if (column >= cm.getColumnCount()) {
  305. if( getComponentOrientation().isLeftToRight() ) {
  306. r.x = getWidth();
  307. }
  308. }
  309. else {
  310. for(int i = 0; i < column; i++) {
  311. r.x += cm.getColumn(i).getWidth();
  312. }
  313. if( !getComponentOrientation().isLeftToRight() ) {
  314. r.x = getWidthInRightToLeft() - r.x - cm.getColumn(column).getWidth();
  315. }
  316. r.width = cm.getColumn(column).getWidth();
  317. }
  318. return r;
  319. }
  320. /**
  321. * Allows the renderer's tips to be used if there is text set.
  322. * @param event the location of the event identifies the proper
  323. * renderer and, therefore, the proper tip
  324. * @return the tool tip for this component
  325. */
  326. public String getToolTipText(MouseEvent event) {
  327. String tip = null;
  328. Point p = event.getPoint();
  329. int column;
  330. // Locate the renderer under the event location
  331. if ((column = columnAtPoint(p)) != -1) {
  332. TableColumn aColumn = columnModel.getColumn(column);
  333. TableCellRenderer renderer = aColumn.getHeaderRenderer();
  334. if (renderer == null) {
  335. renderer = defaultRenderer;
  336. }
  337. Component component = renderer.getTableCellRendererComponent(
  338. getTable(), aColumn.getHeaderValue(), false, false,
  339. -1, column);
  340. // Now have to see if the component is a JComponent before
  341. // getting the tip
  342. if (component instanceof JComponent) {
  343. // Convert the event to the renderer's coordinate system
  344. MouseEvent newEvent;
  345. Rectangle cellRect = getHeaderRect(column);
  346. p.translate(-cellRect.x, -cellRect.y);
  347. newEvent = new MouseEvent(component, event.getID(),
  348. event.getWhen(), event.getModifiers(),
  349. p.x, p.y, event.getClickCount(),
  350. event.isPopupTrigger());
  351. tip = ((JComponent)component).getToolTipText(newEvent);
  352. }
  353. }
  354. // No tip from the renderer get our own tip
  355. if (tip == null)
  356. tip = getToolTipText();
  357. return tip;
  358. }
  359. //
  360. // Managing TableHeaderUI
  361. //
  362. /**
  363. * Returns the look and feel (L&F) object that renders this component.
  364. *
  365. * @return the <code>TableHeaderUI</code> object that renders this component
  366. */
  367. public TableHeaderUI getUI() {
  368. return (TableHeaderUI)ui;
  369. }
  370. /**
  371. * Sets the look and feel (L&F) object that renders this component.
  372. *
  373. * @param ui the <code>TableHeaderUI</code> L&F object
  374. * @see UIDefaults#getUI
  375. */
  376. public void setUI(TableHeaderUI ui){
  377. if (this.ui != ui) {
  378. super.setUI(ui);
  379. repaint();
  380. }
  381. }
  382. /**
  383. * Notification from the <code>UIManager</code> that the look and feel
  384. * (L&F) has changed.
  385. * Replaces the current UI object with the latest version from the
  386. * <code>UIManager</code>.
  387. *
  388. * @see JComponent#updateUI
  389. */
  390. public void updateUI(){
  391. setUI((TableHeaderUI)UIManager.getUI(this));
  392. resizeAndRepaint();
  393. invalidate();//PENDING
  394. }
  395. /**
  396. * Returns the suffix used to construct the name of the look and feel
  397. * (L&F) class used to render this component.
  398. * @return the string "TableHeaderUI"
  399. *
  400. * @return "TableHeaderUI"
  401. * @see JComponent#getUIClassID
  402. * @see UIDefaults#getUI
  403. */
  404. public String getUIClassID() {
  405. return uiClassID;
  406. }
  407. //
  408. // Managing models
  409. //
  410. /**
  411. * Sets the column model for this table to <code>newModel</code> and registers
  412. * for listener notifications from the new column model.
  413. *
  414. * @param columnModel the new data source for this table
  415. * @exception IllegalArgumentException
  416. * if <code>newModel</code> is <code>null</code>
  417. * @see #getColumnModel
  418. * @beaninfo
  419. * bound: true
  420. * description: The object governing the way columns appear in the view.
  421. */
  422. public void setColumnModel(TableColumnModel columnModel) {
  423. if (columnModel == null) {
  424. throw new IllegalArgumentException("Cannot set a null ColumnModel");
  425. }
  426. TableColumnModel old = this.columnModel;
  427. if (columnModel != old) {
  428. if (old != null) {
  429. old.removeColumnModelListener(this);
  430. }
  431. this.columnModel = columnModel;
  432. columnModel.addColumnModelListener(this);
  433. firePropertyChange("columnModel", old, columnModel);
  434. resizeAndRepaint();
  435. }
  436. }
  437. /**
  438. * Returns the <code>TableColumnModel</code> that contains all column information
  439. * of this table header.
  440. *
  441. * @return the <code>columnModel</code> property
  442. * @see #setColumnModel
  443. */
  444. public TableColumnModel getColumnModel() {
  445. return columnModel;
  446. }
  447. //
  448. // Implementing TableColumnModelListener interface
  449. //
  450. /**
  451. * Invoked when a column is added to the table column model.
  452. * <p>
  453. * Application code will not use these methods explicitly, they
  454. * are used internally by <code>JTable</code>.
  455. *
  456. * @param e the event received
  457. * @see TableColumnModelListener
  458. */
  459. public void columnAdded(TableColumnModelEvent e) { resizeAndRepaint(); }
  460. /**
  461. * Invoked when a column is removed from the table column model.
  462. * <p>
  463. * Application code will not use these methods explicitly, they
  464. * are used internally by <code>JTable</code>.
  465. *
  466. * @param e the event received
  467. * @see TableColumnModelListener
  468. */
  469. public void columnRemoved(TableColumnModelEvent e) { resizeAndRepaint(); }
  470. /**
  471. * Invoked when a column is repositioned.
  472. * <p>
  473. * Application code will not use these methods explicitly, they
  474. * are used internally by <code>JTable</code>.
  475. *
  476. * @param e the event received
  477. * @see TableColumnModelListener
  478. */
  479. public void columnMoved(TableColumnModelEvent e) { repaint(); }
  480. /**
  481. * Invoked when a column is moved due to a margin change.
  482. * <p>
  483. * Application code will not use these methods explicitly, they
  484. * are used internally by <code>JTable</code>.
  485. *
  486. * @param e the event received
  487. * @see TableColumnModelListener
  488. */
  489. public void columnMarginChanged(ChangeEvent e) { resizeAndRepaint(); }
  490. // --Redrawing the header is slow in cell selection mode.
  491. // --Since header selection is ugly and it is always clear from the
  492. // --view which columns are selected, don't redraw the header.
  493. /**
  494. * Invoked when the selection model of the <code>TableColumnModel</code>
  495. * is changed. This method currently has no effect (the header is not
  496. * redrawn).
  497. * <p>
  498. * Application code will not use these methods explicitly, they
  499. * are used internally by <code>JTable</code>.
  500. *
  501. * @param e the event received
  502. * @see TableColumnModelListener
  503. */
  504. public void columnSelectionChanged(ListSelectionEvent e) { } // repaint(); }
  505. //
  506. // Package Methods
  507. //
  508. /**
  509. * Returns the default column model object which is
  510. * a <code>DefaultTableColumnModel</code>. A subclass can override this
  511. * method to return a different column model object
  512. *
  513. * @return the default column model object
  514. */
  515. protected TableColumnModel createDefaultColumnModel() {
  516. return new DefaultTableColumnModel();
  517. }
  518. /**
  519. * Returns a default renderer to be used when no header renderer
  520. * is defined by a <code>TableColumn</code>.
  521. *
  522. * @return the default table column renderer
  523. */
  524. protected TableCellRenderer createDefaultRenderer() {
  525. DefaultTableCellRenderer label = new UIResourceTableCellRenderer();
  526. label.setHorizontalAlignment(JLabel.CENTER);
  527. return label;
  528. }
  529. private static class UIResourceTableCellRenderer extends DefaultTableCellRenderer implements UIResource {
  530. public Component getTableCellRendererComponent(JTable table, Object value,
  531. boolean isSelected, boolean hasFocus, int row, int column) {
  532. if (table != null) {
  533. JTableHeader header = table.getTableHeader();
  534. if (header != null) {
  535. setForeground(header.getForeground());
  536. setBackground(header.getBackground());
  537. setFont(header.getFont());
  538. }
  539. }
  540. setText((value == null) ? "" : value.toString());
  541. setBorder(UIManager.getBorder("TableHeader.cellBorder"));
  542. return this;
  543. }
  544. }
  545. /**
  546. * Initializes the local variables and properties with default values.
  547. * Used by the constructor methods.
  548. */
  549. protected void initializeLocalVars() {
  550. setOpaque(true);
  551. table = null;
  552. reorderingAllowed = true;
  553. resizingAllowed = true;
  554. draggedColumn = null;
  555. draggedDistance = 0;
  556. resizingColumn = null;
  557. updateTableInRealTime = true;
  558. // I'm registered to do tool tips so we can draw tips for the
  559. // renderers
  560. ToolTipManager toolTipManager = ToolTipManager.sharedInstance();
  561. toolTipManager.registerComponent(this);
  562. setDefaultRenderer(createDefaultRenderer());
  563. }
  564. /**
  565. * Sizes the header and marks it as needing display. Equivalent
  566. * to <code>revalidate</code> followed by <code>repaint</code>.
  567. */
  568. public void resizeAndRepaint() {
  569. revalidate();
  570. repaint();
  571. }
  572. /**
  573. * Sets the header's <code>draggedColumn</code> to <code>aColumn</code>.
  574. * <p>
  575. * Application code will not use this method explicitly, it is used
  576. * internally by the column dragging mechanism.
  577. *
  578. * @param aColumn the column being dragged, or <code>null</code> if
  579. * no column is being dragged
  580. */
  581. public void setDraggedColumn(TableColumn aColumn) {
  582. draggedColumn = aColumn;
  583. }
  584. /**
  585. * Sets the header's <code>draggedDistance</code> to <code>distance</code>.
  586. * @param distance the distance dragged
  587. */
  588. public void setDraggedDistance(int distance) {
  589. draggedDistance = distance;
  590. }
  591. /**
  592. * Sets the header's <code>resizingColumn</code> to <code>aColumn</code>.
  593. * <p>
  594. * Application code will not use this method explicitly, it
  595. * is used internally by the column sizing mechanism.
  596. *
  597. * @param aColumn the column being resized, or <code>null</code> if
  598. * no column is being resized
  599. */
  600. public void setResizingColumn(TableColumn aColumn) {
  601. resizingColumn = aColumn;
  602. }
  603. /**
  604. * See <code>readObject</code> and <code>writeObject</code> in
  605. * <code>JComponent</code> for more
  606. * information about serialization in Swing.
  607. */
  608. private void writeObject(ObjectOutputStream s) throws IOException {
  609. s.defaultWriteObject();
  610. if ((ui != null) && (getUIClassID().equals(uiClassID))) {
  611. ui.installUI(this);
  612. }
  613. }
  614. private int getWidthInRightToLeft() {
  615. if ((table != null) &&
  616. (table.getAutoResizeMode() != JTable.AUTO_RESIZE_OFF)) {
  617. return table.getWidth();
  618. }
  619. return super.getWidth();
  620. }
  621. /**
  622. * Returns a string representation of this <code>JTableHeader</code>. This method
  623. * is intended to be used only for debugging purposes, and the
  624. * content and format of the returned string may vary between
  625. * implementations. The returned string may be empty but may not
  626. * be <code>null</code>.
  627. * <P>
  628. * Overriding <code>paramString</code> to provide information about the
  629. * specific new aspects of the JFC components.
  630. *
  631. * @return a string representation of this <code>JTableHeader</code>
  632. */
  633. protected String paramString() {
  634. String reorderingAllowedString = (reorderingAllowed ?
  635. "true" : "false");
  636. String resizingAllowedString = (resizingAllowed ?
  637. "true" : "false");
  638. String updateTableInRealTimeString = (updateTableInRealTime ?
  639. "true" : "false");
  640. return super.paramString() +
  641. ",draggedDistance=" + draggedDistance +
  642. ",reorderingAllowed=" + reorderingAllowedString +
  643. ",resizingAllowed=" + resizingAllowedString +
  644. ",updateTableInRealTime=" + updateTableInRealTimeString;
  645. }
  646. /////////////////
  647. // Accessibility support
  648. ////////////////
  649. /**
  650. * Gets the AccessibleContext associated with this JTableHeader.
  651. * For JTableHeaders, the AccessibleContext takes the form of an
  652. * AccessibleJTableHeader.
  653. * A new AccessibleJTableHeader instance is created if necessary.
  654. *
  655. * @return an AccessibleJTableHeader that serves as the
  656. * AccessibleContext of this JTableHeader
  657. */
  658. public AccessibleContext getAccessibleContext() {
  659. if (accessibleContext == null) {
  660. accessibleContext = new AccessibleJTableHeader();
  661. }
  662. return accessibleContext;
  663. }
  664. //
  665. // *** should also implement AccessibleSelection?
  666. // *** and what's up with keyboard navigation/manipulation?
  667. //
  668. /**
  669. * This class implements accessibility support for the
  670. * <code>JTableHeader</code> class. It provides an implementation of the
  671. * Java Accessibility API appropriate to table header user-interface
  672. * elements.
  673. * <p>
  674. * <strong>Warning:</strong>
  675. * Serialized objects of this class will not be compatible with
  676. * future Swing releases. The current serialization support is
  677. * appropriate for short term storage or RMI between applications running
  678. * the same version of Swing. As of 1.4, support for long term storage
  679. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  680. * has been added to the <code>java.beans</code> package.
  681. * Please see {@link java.beans.XMLEncoder}.
  682. */
  683. protected class AccessibleJTableHeader extends AccessibleJComponent {
  684. /**
  685. * Get the role of this object.
  686. *
  687. * @return an instance of AccessibleRole describing the role of the
  688. * object
  689. * @see AccessibleRole
  690. */
  691. public AccessibleRole getAccessibleRole() {
  692. return AccessibleRole.PANEL;
  693. }
  694. /**
  695. * Returns the Accessible child, if one exists, contained at the local
  696. * coordinate Point.
  697. *
  698. * @param p The point defining the top-left corner of the Accessible,
  699. * given in the coordinate space of the object's parent.
  700. * @return the Accessible, if it exists, at the specified location;
  701. * else null
  702. */
  703. public Accessible getAccessibleAt(Point p) {
  704. int column;
  705. // Locate the renderer under the Point
  706. if ((column = JTableHeader.this.columnAtPoint(p)) != -1) {
  707. TableColumn aColumn = JTableHeader.this.columnModel.getColumn(column);
  708. TableCellRenderer renderer = aColumn.getHeaderRenderer();
  709. if (renderer == null) {
  710. if (defaultRenderer != null) {
  711. renderer = defaultRenderer;
  712. } else {
  713. return null;
  714. }
  715. }
  716. Component component = renderer.getTableCellRendererComponent(
  717. JTableHeader.this.getTable(),
  718. aColumn.getHeaderValue(), false, false,
  719. -1, column);
  720. return new AccessibleJTableHeaderEntry(column, JTableHeader.this, JTableHeader.this.table);
  721. } else {
  722. return null;
  723. }
  724. }
  725. /**
  726. * Returns the number of accessible children in the object. If all
  727. * of the children of this object implement Accessible, than this
  728. * method should return the number of children of this object.
  729. *
  730. * @return the number of accessible children in the object.
  731. */
  732. public int getAccessibleChildrenCount() {
  733. return JTableHeader.this.columnModel.getColumnCount();
  734. }
  735. /**
  736. * Return the nth Accessible child of the object.
  737. *
  738. * @param i zero-based index of child
  739. * @return the nth Accessible child of the object
  740. */
  741. public Accessible getAccessibleChild(int i) {
  742. if (i < 0 || i >= getAccessibleChildrenCount()) {
  743. return null;
  744. } else {
  745. TableColumn aColumn = JTableHeader.this.columnModel.getColumn(i)
  746. ;
  747. TableCellRenderer renderer = aColumn.getHeaderRenderer();
  748. if (renderer == null) {
  749. if (defaultRenderer != null) {
  750. renderer = defaultRenderer;
  751. } else {
  752. return null;
  753. }
  754. }
  755. Component component = renderer.getTableCellRendererComponent(
  756. JTableHeader.this.getTable(),
  757. aColumn.getHeaderValue(), false, false,
  758. -1, i);
  759. return new AccessibleJTableHeaderEntry(i, JTableHeader.this, JTableHeader.this.table);
  760. }
  761. }
  762. /**
  763. * This class provides an implementation of the Java Accessibility
  764. * API appropropriate for JTableHeader entries.
  765. */
  766. protected class AccessibleJTableHeaderEntry extends AccessibleContext
  767. implements Accessible, AccessibleComponent {
  768. private JTableHeader parent;
  769. private int column;
  770. private JTable table;
  771. /**
  772. * Constructs an AccessiblJTableHeaaderEntry
  773. */
  774. public AccessibleJTableHeaderEntry(int c, JTableHeader p, JTable t) {
  775. parent = p;
  776. column = c;
  777. table = t;
  778. this.setAccessibleParent(parent);
  779. }
  780. /**
  781. * Get the AccessibleContext associated with this object.
  782. * In the implementation of the Java Accessibility API
  783. * for this class, returns this object, which serves as
  784. * its own AccessibleContext.
  785. *
  786. * @return this object
  787. */
  788. public AccessibleContext getAccessibleContext() {
  789. return this;
  790. }
  791. private AccessibleContext getCurrentAccessibleContext() {
  792. TableColumnModel tcm = table.getColumnModel();
  793. if (tcm != null) {
  794. // Fixes 4772355 - ArrayOutOfBoundsException in
  795. // JTableHeader
  796. if (column < 0 || column >= tcm.getColumnCount()) {
  797. return null;
  798. }
  799. TableColumn aColumn = tcm.getColumn(column);
  800. TableCellRenderer renderer = aColumn.getHeaderRenderer();
  801. if (renderer == null) {
  802. if (defaultRenderer != null) {
  803. renderer = defaultRenderer;
  804. } else {
  805. return null;
  806. }
  807. }
  808. Component c = renderer.getTableCellRendererComponent(
  809. JTableHeader.this.getTable(),
  810. aColumn.getHeaderValue(), false, false,
  811. -1, column);
  812. if (c instanceof Accessible) {
  813. return ((Accessible) c).getAccessibleContext();
  814. }
  815. }
  816. return null;
  817. }
  818. private Component getCurrentComponent() {
  819. TableColumnModel tcm = table.getColumnModel();
  820. if (tcm != null) {
  821. // Fixes 4772355 - ArrayOutOfBoundsException in
  822. // JTableHeader
  823. if (column < 0 || column >= tcm.getColumnCount()) {
  824. return null;
  825. }
  826. TableColumn aColumn = tcm.getColumn(column);
  827. TableCellRenderer renderer = aColumn.getHeaderRenderer();
  828. if (renderer == null) {
  829. if (defaultRenderer != null) {
  830. renderer = defaultRenderer;
  831. } else {
  832. return null;
  833. }
  834. }
  835. return renderer.getTableCellRendererComponent(
  836. JTableHeader.this.getTable(),
  837. aColumn.getHeaderValue(), false, false,
  838. -1, column);
  839. } else {
  840. return null;
  841. }
  842. }
  843. // AccessibleContext methods
  844. public String getAccessibleName() {
  845. AccessibleContext ac = getCurrentAccessibleContext();
  846. if (ac != null) {
  847. String name = ac.getAccessibleName();
  848. if ((name != null) && (name != "")) {
  849. return ac.getAccessibleName();
  850. }
  851. }
  852. if ((accessibleName != null) && (accessibleName != "")) {
  853. return accessibleName;
  854. } else {
  855. return table.getColumnName(column);
  856. }
  857. }
  858. public void setAccessibleName(String s) {
  859. AccessibleContext ac = getCurrentAccessibleContext();
  860. if (ac != null) {
  861. ac.setAccessibleName(s);
  862. } else {
  863. super.setAccessibleName(s);
  864. }
  865. }
  866. //
  867. // *** should check toolTip text for desc. (needs MouseEvent)
  868. //
  869. public String getAccessibleDescription() {
  870. AccessibleContext ac = getCurrentAccessibleContext();
  871. if (ac != null) {
  872. return ac.getAccessibleDescription();
  873. } else {
  874. return super.getAccessibleDescription();
  875. }
  876. }
  877. public void setAccessibleDescription(String s) {
  878. AccessibleContext ac = getCurrentAccessibleContext();
  879. if (ac != null) {
  880. ac.setAccessibleDescription(s);
  881. } else {
  882. super.setAccessibleDescription(s);
  883. }
  884. }
  885. public AccessibleRole getAccessibleRole() {
  886. AccessibleContext ac = getCurrentAccessibleContext();
  887. if (ac != null) {
  888. return ac.getAccessibleRole();
  889. } else {
  890. return AccessibleRole.COLUMN_HEADER;
  891. }
  892. }
  893. public AccessibleStateSet getAccessibleStateSet() {
  894. AccessibleContext ac = getCurrentAccessibleContext();
  895. if (ac != null) {
  896. AccessibleStateSet states = ac.getAccessibleStateSet();
  897. if (isShowing()) {
  898. states.add(AccessibleState.SHOWING);
  899. }
  900. return states;
  901. } else {
  902. return new AccessibleStateSet(); // must be non null?
  903. }
  904. }
  905. public int getAccessibleIndexInParent() {
  906. return column;
  907. }
  908. public int getAccessibleChildrenCount() {
  909. AccessibleContext ac = getCurrentAccessibleContext();
  910. if (ac != null) {
  911. return ac.getAccessibleChildrenCount();
  912. } else {
  913. return 0;
  914. }
  915. }
  916. public Accessible getAccessibleChild(int i) {
  917. AccessibleContext ac = getCurrentAccessibleContext();
  918. if (ac != null) {
  919. Accessible accessibleChild = ac.getAccessibleChild(i);
  920. ac.setAccessibleParent(this);
  921. return accessibleChild;
  922. } else {
  923. return null;
  924. }
  925. }
  926. public Locale getLocale() {
  927. AccessibleContext ac = getCurrentAccessibleContext();
  928. if (ac != null) {
  929. return ac.getLocale();
  930. } else {
  931. return null;
  932. }
  933. }
  934. public void addPropertyChangeListener(PropertyChangeListener l) {
  935. AccessibleContext ac = getCurrentAccessibleContext();
  936. if (ac != null) {
  937. ac.addPropertyChangeListener(l);
  938. } else {
  939. super.addPropertyChangeListener(l);
  940. }
  941. }
  942. public void removePropertyChangeListener(PropertyChangeListener l) {
  943. AccessibleContext ac = getCurrentAccessibleContext();
  944. if (ac != null) {
  945. ac.removePropertyChangeListener(l);
  946. } else {
  947. super.removePropertyChangeListener(l);
  948. }
  949. }
  950. public AccessibleAction getAccessibleAction() {
  951. return getCurrentAccessibleContext().getAccessibleAction();
  952. }
  953. /**
  954. * Get the AccessibleComponent associated with this object. In the
  955. * implementation of the Java Accessibility API for this class,
  956. * return this object, which is responsible for implementing the
  957. * AccessibleComponent interface on behalf of itself.
  958. *
  959. * @return this object
  960. */
  961. public AccessibleComponent getAccessibleComponent() {
  962. return this; // to override getBounds()
  963. }
  964. public AccessibleSelection getAccessibleSelection() {
  965. return getCurrentAccessibleContext().getAccessibleSelection();
  966. }
  967. public AccessibleText getAccessibleText() {
  968. return getCurrentAccessibleContext().getAccessibleText();
  969. }
  970. public AccessibleValue getAccessibleValue() {
  971. return getCurrentAccessibleContext().getAccessibleValue();
  972. }
  973. // AccessibleComponent methods
  974. public Color getBackground() {
  975. AccessibleContext ac = getCurrentAccessibleContext();
  976. if (ac instanceof AccessibleComponent) {
  977. return ((AccessibleComponent) ac).getBackground();
  978. } else {
  979. Component c = getCurrentComponent();
  980. if (c != null) {
  981. return c.getBackground();
  982. } else {
  983. return null;
  984. }
  985. }
  986. }
  987. public void setBackground(Color c) {
  988. AccessibleContext ac = getCurrentAccessibleContext();
  989. if (ac instanceof AccessibleComponent) {
  990. ((AccessibleComponent) ac).setBackground(c);
  991. } else {
  992. Component cp = getCurrentComponent();
  993. if (cp != null) {
  994. cp.setBackground(c);
  995. }
  996. }
  997. }
  998. public Color getForeground() {
  999. AccessibleContext ac = getCurrentAccessibleContext();
  1000. if (ac instanceof AccessibleComponent) {
  1001. return ((AccessibleComponent) ac).getForeground();
  1002. } else {
  1003. Component c = getCurrentComponent();
  1004. if (c != null) {
  1005. return c.getForeground();
  1006. } else {
  1007. return null;
  1008. }
  1009. }
  1010. }
  1011. public void setForeground(Color c) {
  1012. AccessibleContext ac = getCurrentAccessibleContext();
  1013. if (ac instanceof AccessibleComponent) {
  1014. ((AccessibleComponent) ac).setForeground(c);
  1015. } else {
  1016. Component cp = getCurrentComponent();
  1017. if (cp != null) {
  1018. cp.setForeground(c);
  1019. }
  1020. }
  1021. }
  1022. public Cursor getCursor() {
  1023. AccessibleContext ac = getCurrentAccessibleContext();
  1024. if (ac instanceof AccessibleComponent) {
  1025. return ((AccessibleComponent) ac).getCursor();
  1026. } else {
  1027. Component c = getCurrentComponent();
  1028. if (c != null) {
  1029. return c.getCursor();
  1030. } else {
  1031. Accessible ap = getAccessibleParent();
  1032. if (ap instanceof AccessibleComponent) {
  1033. return ((AccessibleComponent) ap).getCursor();
  1034. } else {
  1035. return null;
  1036. }
  1037. }
  1038. }
  1039. }
  1040. public void setCursor(Cursor c) {
  1041. AccessibleContext ac = getCurrentAccessibleContext();
  1042. if (ac instanceof AccessibleComponent) {
  1043. ((AccessibleComponent) ac).setCursor(c);
  1044. } else {
  1045. Component cp = getCurrentComponent();
  1046. if (cp != null) {
  1047. cp.setCursor(c);
  1048. }
  1049. }
  1050. }
  1051. public Font getFont() {
  1052. AccessibleContext ac = getCurrentAccessibleContext();
  1053. if (ac instanceof AccessibleComponent) {
  1054. return ((AccessibleComponent) ac).getFont();
  1055. } else {
  1056. Component c = getCurrentComponent();
  1057. if (c != null) {
  1058. return c.getFont();
  1059. } else {
  1060. return null;
  1061. }
  1062. }
  1063. }
  1064. public void setFont(Font f) {
  1065. AccessibleContext ac = getCurrentAccessibleContext();
  1066. if (ac instanceof AccessibleComponent) {
  1067. ((AccessibleComponent) ac).setFont(f);
  1068. } else {
  1069. Component c = getCurrentComponent();
  1070. if (c != null) {
  1071. c.setFont(f);
  1072. }
  1073. }
  1074. }
  1075. public FontMetrics getFontMetrics(Font f) {
  1076. AccessibleContext ac = getCurrentAccessibleContext();
  1077. if (ac instanceof AccessibleComponent) {
  1078. return ((AccessibleComponent) ac).getFontMetrics(f);
  1079. } else {
  1080. Component c = getCurrentComponent();
  1081. if (c != null) {
  1082. return c.getFontMetrics(f);
  1083. } else {
  1084. return null;
  1085. }
  1086. }
  1087. }
  1088. public boolean isEnabled() {
  1089. AccessibleContext ac = getCurrentAccessibleContext();
  1090. if (ac instanceof AccessibleComponent) {
  1091. return ((AccessibleComponent) ac).isEnabled();
  1092. } else {
  1093. Component c = getCurrentComponent();
  1094. if (c != null) {
  1095. return c.isEnabled();
  1096. } else {
  1097. return false;
  1098. }
  1099. }
  1100. }
  1101. public void setEnabled(boolean b) {
  1102. AccessibleContext ac = getCurrentAccessibleContext();
  1103. if (ac instanceof AccessibleComponent) {
  1104. ((AccessibleComponent) ac).setEnabled(b);
  1105. } else {
  1106. Component c = getCurrentComponent();
  1107. if (c != null) {
  1108. c.setEnabled(b);
  1109. }
  1110. }
  1111. }
  1112. public boolean isVisible() {
  1113. AccessibleContext ac = getCurrentAccessibleContext();
  1114. if (ac instanceof AccessibleComponent) {
  1115. return ((AccessibleComponent) ac).isVisible();
  1116. } else {
  1117. Component c = getCurrentComponent();
  1118. if (c != null) {
  1119. return c.isVisible();
  1120. } else {
  1121. return false;
  1122. }
  1123. }
  1124. }
  1125. public void setVisible(boolean b) {
  1126. AccessibleContext ac = getCurrentAccessibleContext();
  1127. if (ac instanceof AccessibleComponent) {
  1128. ((AccessibleComponent) ac).setVisible(b);
  1129. } else {
  1130. Component c = getCurrentComponent();
  1131. if (c != null) {
  1132. c.setVisible(b);
  1133. }
  1134. }
  1135. }
  1136. public boolean isShowing() {
  1137. if (isVisible() && JTableHeader.this.isShowing()) {
  1138. return true;
  1139. } else {
  1140. return false;
  1141. }
  1142. }
  1143. public boolean contains(Point p) {
  1144. AccessibleContext ac = getCurrentAccessibleContext();
  1145. if (ac instanceof AccessibleComponent) {
  1146. Rectangle r = ((AccessibleComponent) ac).getBounds();
  1147. return r.contains(p);
  1148. } else {
  1149. Component c = getCurrentComponent();
  1150. if (c != null) {
  1151. Rectangle r = c.getBounds();
  1152. return r.contains(p);
  1153. } else {
  1154. return getBounds().contains(p);
  1155. }
  1156. }
  1157. }
  1158. public Point getLocationOnScreen() {
  1159. if (parent != null) {
  1160. Point parentLocation = parent.getLocationOnScreen();
  1161. Point componentLocation = getLocation();
  1162. componentLocation.translate(parentLocation.x, parentLocation.y);
  1163. return componentLocation;
  1164. } else {
  1165. return null;
  1166. }
  1167. }
  1168. public Point getLocation() {
  1169. AccessibleContext ac = getCurrentAccessibleContext();
  1170. if (ac instanceof AccessibleComponent) {
  1171. Rectangle r = ((AccessibleComponent) ac).getBounds();
  1172. return r.getLocation();
  1173. } else {
  1174. Component c = getCurrentComponent();
  1175. if (c != null) {
  1176. Rectangle r = c.getBounds();
  1177. return r.getLocation();
  1178. } else {
  1179. return getBounds().getLocation();
  1180. }
  1181. }
  1182. }
  1183. public void setLocation(Point p) {
  1184. // if ((parent != null) && (parent.contains(p))) {
  1185. // ensureIndexIsVisible(indexInParent);
  1186. // }
  1187. }
  1188. public Rectangle getBounds() {
  1189. Rectangle r = table.getCellRect(-1, column, false);
  1190. r.y = 0;
  1191. return r;
  1192. // AccessibleContext ac = getCurrentAccessibleContext();
  1193. // if (ac instanceof AccessibleComponent) {
  1194. // return ((AccessibleComponent) ac).getBounds();
  1195. // } else {
  1196. // Component c = getCurrentComponent();
  1197. // if (c != null) {
  1198. // return c.getBounds();
  1199. // } else {
  1200. // Rectangle r = table.getCellRect(-1, column, false);
  1201. // r.y = 0;
  1202. // return r;
  1203. // }
  1204. // }
  1205. }
  1206. public void setBounds(Rectangle r) {
  1207. AccessibleContext ac = getCurrentAccessibleContext();
  1208. if (ac instanceof AccessibleComponent) {
  1209. ((AccessibleComponent) ac).setBounds(r);
  1210. } else {
  1211. Component c = getCurrentComponent();
  1212. if (c != null) {
  1213. c.setBounds(r);
  1214. }
  1215. }
  1216. }
  1217. public Dimension getSize() {
  1218. return getBounds().getSize();
  1219. // AccessibleContext ac = getCurrentAccessibleContext();
  1220. // if (ac instanceof AccessibleComponent) {
  1221. // Rectangle r = ((AccessibleComponent) ac).getBounds();
  1222. // return r.getSize();
  1223. // } else {
  1224. // Component c = getCurrentComponent();
  1225. // if (c != null) {
  1226. // Rectangle r = c.getBounds();
  1227. // return r.getSize();
  1228. // } else {
  1229. // return getBounds().getSize();
  1230. // }
  1231. // }
  1232. }
  1233. public void setSize (Dimension d) {
  1234. AccessibleContext ac = getCurrentAccessibleContext();
  1235. if (ac instanceof AccessibleComponent) {
  1236. ((AccessibleComponent) ac).setSize(d);
  1237. } else {
  1238. Component c = getCurrentComponent();
  1239. if (c != null) {
  1240. c.setSize(d);
  1241. }
  1242. }
  1243. }
  1244. public Accessible getAccessibleAt(Point p) {
  1245. AccessibleContext ac = getCurrentAccessibleContext();
  1246. if (ac instanceof AccessibleComponent) {
  1247. return ((AccessibleComponent) ac).getAccessibleAt(p);
  1248. } else {
  1249. return null;
  1250. }
  1251. }
  1252. public boolean isFocusTraversable() {
  1253. AccessibleContext ac = getCurrentAccessibleContext();
  1254. if (ac instanceof AccessibleComponent) {
  1255. return ((AccessibleComponent) ac).isFocusTraversable();
  1256. } else {
  1257. Component c = getCurrentComponent();
  1258. if (c != null) {
  1259. return c.isFocusTraversable();
  1260. } else {
  1261. return false;
  1262. }
  1263. }
  1264. }
  1265. public void requestFocus() {
  1266. AccessibleContext ac = getCurrentAccessibleContext();
  1267. if (ac instanceof AccessibleComponent) {
  1268. ((AccessibleComponent) ac).requestFocus();
  1269. } else {
  1270. Component c = getCurrentComponent();
  1271. if (c != null) {
  1272. c.requestFocus();
  1273. }
  1274. }
  1275. }
  1276. public void addFocusListener(FocusListener l) {
  1277. AccessibleContext ac = getCurrentAccessibleContext();
  1278. if (ac instanceof AccessibleComponent) {
  1279. ((AccessibleComponent) ac).addFocusListener(l);
  1280. } else {
  1281. Component c = getCurrentComponent();
  1282. if (c != null) {
  1283. c.addFocusListener(l);
  1284. }
  1285. }
  1286. }
  1287. public void removeFocusListener(FocusListener l) {
  1288. AccessibleContext ac = getCurrentAccessibleContext();
  1289. if (ac instanceof AccessibleComponent) {
  1290. ((AccessibleComponent) ac).removeFocusListener(l);
  1291. } else {
  1292. Component c = getCurrentComponent();
  1293. if (c != null) {
  1294. c.removeFocusListener(l);
  1295. }
  1296. }
  1297. }
  1298. } // inner class AccessibleJTableHeaderElement
  1299. } // inner class AccessibleJTableHeader
  1300. } // End of Class JTableHeader