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