Imported GNU Classpath 0.90
[official-gcc.git] / libjava / classpath / javax / swing / JTable.java
blobfbf74934a0a2c6b4ae498810684b597a29073735
1 /* JTable.java --
2 Copyright (C) 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing;
41 import java.awt.Color;
42 import java.awt.Component;
43 import java.awt.Cursor;
44 import java.awt.Dimension;
45 import java.awt.Font;
46 import java.awt.FontMetrics;
47 import java.awt.Point;
48 import java.awt.Rectangle;
49 import java.awt.event.FocusListener;
50 import java.beans.PropertyChangeEvent;
51 import java.beans.PropertyChangeListener;
52 import java.text.DateFormat;
53 import java.text.NumberFormat;
54 import java.util.Date;
55 import java.util.EventObject;
56 import java.util.Hashtable;
57 import java.util.Locale;
58 import java.util.Vector;
60 import javax.accessibility.Accessible;
61 import javax.accessibility.AccessibleComponent;
62 import javax.accessibility.AccessibleContext;
63 import javax.accessibility.AccessibleExtendedTable;
64 import javax.accessibility.AccessibleRole;
65 import javax.accessibility.AccessibleSelection;
66 import javax.accessibility.AccessibleStateSet;
67 import javax.accessibility.AccessibleTable;
68 import javax.accessibility.AccessibleTableModelChange;
69 import javax.swing.event.CellEditorListener;
70 import javax.swing.event.ChangeEvent;
71 import javax.swing.event.ListSelectionEvent;
72 import javax.swing.event.ListSelectionListener;
73 import javax.swing.event.TableColumnModelEvent;
74 import javax.swing.event.TableColumnModelListener;
75 import javax.swing.event.TableModelEvent;
76 import javax.swing.event.TableModelListener;
77 import javax.swing.plaf.TableUI;
78 import javax.swing.table.DefaultTableCellRenderer;
79 import javax.swing.table.DefaultTableColumnModel;
80 import javax.swing.table.DefaultTableModel;
81 import javax.swing.table.JTableHeader;
82 import javax.swing.table.TableCellEditor;
83 import javax.swing.table.TableCellRenderer;
84 import javax.swing.table.TableColumn;
85 import javax.swing.table.TableColumnModel;
86 import javax.swing.table.TableModel;
88 /**
89 * The table component, displaying information, organized in rows and columns.
90 * The table can be placed in the scroll bar and have the optional header
91 * that is always visible. Cell values may be editable after double clicking
92 * on the cell. Cell columns may have various data types, that are
93 * displayed and edited by the different renderers and editors. It is possible
94 * to set different column width. The columns are also resizeable by
95 * dragging the column boundary in the header.
97 public class JTable
98 extends JComponent
99 implements TableModelListener, Scrollable, TableColumnModelListener,
100 ListSelectionListener, CellEditorListener, Accessible
103 * Provides accessibility support for <code>JTable</code>.
105 * @author Roman Kennke (kennke@aicas.com)
107 protected class AccessibleJTable
108 extends AccessibleJComponent
109 implements AccessibleSelection, ListSelectionListener, TableModelListener,
110 TableColumnModelListener, CellEditorListener, PropertyChangeListener,
111 AccessibleExtendedTable
115 * Provides accessibility support for table cells.
117 * @author Roman Kennke (kennke@aicas.com)
119 protected class AccessibleJTableCell
120 extends AccessibleContext
121 implements Accessible, AccessibleComponent
125 * The table of this cell.
127 private JTable table;
130 * The row index of this cell.
132 private int row;
135 * The column index of this cell.
137 private int column;
140 * The index of this cell inside the AccessibleJTable parent.
142 private int index;
145 * Creates a new <code>AccessibleJTableCell</code>.
147 * @param t the table
148 * @param r the row
149 * @param c the column
150 * @param i the index of this cell inside the accessible table parent
152 public AccessibleJTableCell(JTable t, int r, int c, int i)
154 table = t;
155 row = r;
156 column = c;
157 index = i;
161 * Returns the accessible row for the table cell.
163 * @return the accessible row for the table cell
165 public AccessibleRole getAccessibleRole()
167 // TODO: What is the role of the table cell?
168 return AccessibleRole.UNKNOWN;
172 * Returns the accessible state set of this accessible table cell.
174 * @return the accessible state set of this accessible table cell
176 public AccessibleStateSet getAccessibleStateSet()
178 // TODO: What state shoiuld be returned here?
179 return new AccessibleStateSet();
183 * Returns the index of this cell in the parent object.
185 * @return the index of this cell in the parent object
187 public int getAccessibleIndexInParent()
189 return index;
193 * Returns the number of children of this object. Table cells cannot have
194 * children, so we return <code>0</code> here.
196 * @return <code>0</code>
198 public int getAccessibleChildrenCount()
200 return 0;
204 * Returns the accessible child at index <code>i</code>. Table cells
205 * don't have children, so we return <code>null</code> here.
207 * @return <code>null</code>
209 public Accessible getAccessibleChild(int i)
211 return null;
215 * Returns the locale setting for this accessible table cell.
217 * @return the locale setting for this accessible table cell
219 public Locale getLocale()
221 // TODO: For now, we return english here. This must be fixed as soon
222 // as we have a localized Swing.
223 return Locale.ENGLISH;
227 * Returns the accessible context of this table cell. Since accessible
228 * table cells are their own accessible context, we return
229 * <code>this</code>.
231 * @return the accessible context of this table cell
233 public AccessibleContext getAccessibleContext()
235 return this;
239 * Returns the background color of this cell.
241 * @return the background color of this cell
243 public Color getBackground()
245 return table.getBackground();
249 * Sets the background of the cell. Since table cells cannot have
250 * individual background colors, this method does nothing. Set the
251 * background directly on the table instead.
253 * @param color not used
255 public void setBackground(Color color)
257 // This method does nothing. See API comments.
261 * Returns the foreground color of the table cell.
263 * @return the foreground color of the table cell
265 public Color getForeground()
267 return table.getForeground();
271 * Sets the foreground of the cell. Since table cells cannot have
272 * individual foreground colors, this method does nothing. Set the
273 * foreground directly on the table instead.
275 * @param color not used
277 public void setForeground(Color color)
279 // This method does nothing. See API comments.
283 * Returns the cursor for this table cell.
285 * @return the cursor for this table cell
287 public Cursor getCursor()
289 return table.getCursor();
293 * Sets the cursor of the cell. Since table cells cannot have
294 * individual cursors, this method does nothing. Set the
295 * cursor directly on the table instead.
297 * @param cursor not used
299 public void setCursor(Cursor cursor)
301 // This method does nothing. See API comments.
305 * Returns the font of the table cell.
307 * @return the font of the table cell
309 public Font getFont()
311 return table.getFont();
315 * Sets the font of the cell. Since table cells cannot have
316 * individual fonts, this method does nothing. Set the
317 * font directly on the table instead.
319 * @param font not used
321 public void setFont(Font font)
323 // This method does nothing. See API comments.
327 * Returns the font metrics for a specified font.
329 * @param font the font for which we return the metrics
331 * @return the font metrics for a specified font
333 public FontMetrics getFontMetrics(Font font)
335 return table.getFontMetrics(font);
339 * Returns <code>true</code> if this table cell is enabled,
340 * <code>false</code> otherwise.
342 * @return <code>true</code> if this table cell is enabled,
343 * <code>false</code> otherwise
345 public boolean isEnabled()
347 return table.isEnabled();
351 * Table cells cannot be disabled or enabled individually, so this method
352 * does nothing. Set the enabled flag on the table itself.
354 * @param b not used here
356 public void setEnabled(boolean b)
358 // This method does nothing. See API comments.
362 * Returns <code>true</code> if this cell is visible, <code>false</code>
363 * otherwise.
365 * @return <code>true</code> if this cell is visible, <code>false</code>
366 * otherwise
368 public boolean isVisible()
370 return table.isVisible();
374 * The visibility cannot be set on individual table cells, so this method
375 * does nothing. Set the visibility on the table itself.
377 * @param b not used
379 public void setVisible(boolean b)
381 // This method does nothing. See API comments.
385 * Returns <code>true</code> if this table cell is currently showing on
386 * screen.
388 * @return <code>true</code> if this table cell is currently showing on
389 * screen
391 public boolean isShowing()
393 return table.isShowing();
397 * Returns <code>true</code> if this table cell contains the location
398 * at <code>point</code>, <code>false</code> otherwise.
399 * <code>point</code> is interpreted as relative to the coordinate system
400 * of the table cell.
402 * @return <code>true</code> if this table cell contains the location
403 * at <code>point</code>, <code>false</code> otherwise
405 public boolean contains(Point point)
407 Rectangle cellRect = table.getCellRect(row, column, true);
408 cellRect.x = 0;
409 cellRect.y = 0;
410 return cellRect.contains(point);
414 * Returns the screen location of the table cell.
416 * @return the screen location of the table cell
418 public Point getLocationOnScreen()
420 Point tableLoc = table.getLocationOnScreen();
421 Rectangle cellRect = table.getCellRect(row, column, true);
422 tableLoc.x += cellRect.x;
423 tableLoc.y += cellRect.y;
424 return tableLoc;
428 * Returns the location of this cell relative to the table's bounds.
430 * @return the location of this cell relative to the table's bounds
432 public Point getLocation()
434 Rectangle cellRect = table.getCellRect(row, column, true);
435 return new Point(cellRect.x, cellRect.y);
439 * The location of the table cells cannot be manipulated directly, so
440 * this method does nothing.
442 * @param point not used
444 public void setLocation(Point point)
446 // This method does nothing. See API comments.
450 * Returns the bounds of the cell relative to its table.
452 * @return the bounds of the cell relative to its table
454 public Rectangle getBounds()
456 return table.getCellRect(row, column, true);
460 * The bounds of the table cells cannot be manipulated directly, so
461 * this method does nothing.
463 * @param rectangle not used
465 public void setBounds(Rectangle rectangle)
467 // This method does nothing. See API comments.
471 * Returns the size of the table cell.
473 * @return the size of the table cell
475 public Dimension getSize()
477 Rectangle cellRect = table.getCellRect(row, column, true);
478 return new Dimension(cellRect.width, cellRect.height);
482 * The size cannot be set on table cells directly, so this method does
483 * nothing.
485 * @param dimension not used
487 public void setSize(Dimension dimension)
489 // This method does nothing. See API comments.
493 * Table cells have no children, so we return <code>null</code> here.
495 * @return <code>null</code>
497 public Accessible getAccessibleAt(Point point)
499 return null;
503 * Returns <code>true</code> if this table cell is focus traversable,
504 * <code>false</code> otherwise.
506 * @return <code>true</code> if this table cell is focus traversable,
507 * <code>false</code> otherwise
509 public boolean isFocusTraversable()
511 return table.isFocusable();
515 * Requests that this table cell gets the keyboard focus.
517 public void requestFocus()
519 // We first set the selection models' lead selection to this cell.
520 table.getColumnModel().getSelectionModel()
521 .setLeadSelectionIndex(column);
522 table.getSelectionModel().setLeadSelectionIndex(row);
523 // Now we request that the table receives focus.
524 table.requestFocus();
528 * Adds a focus listener to this cell. The focus listener is really
529 * added to the table, so there is no way to find out when an individual
530 * cell changes the focus.
532 * @param listener the focus listener to add
534 public void addFocusListener(FocusListener listener)
536 table.addFocusListener(listener);
540 * Removes a focus listener from the cell. The focus listener is really
541 * removed from the table.
543 * @param listener the listener to remove
545 public void removeFocusListener(FocusListener listener)
547 table.removeFocusListener(listener);
552 protected class AccessibleJTableModelChange
553 implements AccessibleTableModelChange
555 protected int type;
556 protected int firstRow;
557 protected int lastRow;
558 protected int firstColumn;
559 protected int lastColumn;
561 protected AccessibleJTableModelChange(int type, int firstRow,
562 int lastRow, int firstColumn,
563 int lastColumn)
565 this.type = type;
566 this.firstRow = firstRow;
567 this.lastRow = lastRow;
568 this.firstColumn = firstColumn;
569 this.lastColumn = lastColumn;
572 public int getType()
574 return type;
577 public int getFirstRow()
579 return firstRow;
582 public int getLastRow()
584 return lastRow;
587 public int getFirstColumn()
589 return firstColumn;
592 public int getLastColumn()
594 return lastColumn;
599 * Creates a new <code>AccessibleJTable</code>.
601 * @since JDK1.5
603 protected AccessibleJTable()
605 getModel().addTableModelListener(this);
606 getSelectionModel().addListSelectionListener(this);
607 getColumnModel().addColumnModelListener(this);
608 getCellEditor().addCellEditorListener(this);
612 * Returns the number of selected items in this table.
614 public int getAccessibleSelectionCount()
616 return getSelectedColumnCount();
619 public Accessible getAccessibleSelection(int i)
621 // TODO Auto-generated method stub
622 return null;
625 public boolean isAccessibleChildSelected(int i)
627 // TODO Auto-generated method stub
628 return false;
631 public void addAccessibleSelection(int i)
633 // TODO Auto-generated method stub
637 public void removeAccessibleSelection(int i)
639 // TODO Auto-generated method stub
643 public void clearAccessibleSelection()
645 // TODO Auto-generated method stub
649 public void selectAllAccessibleSelection()
651 // TODO Auto-generated method stub
655 public void valueChanged(ListSelectionEvent event)
657 // TODO Auto-generated method stub
662 * Receives notification when the table model changes. Depending on the
663 * type of change, this method calls {@link #tableRowsInserted} or
664 * {@link #tableRowsDeleted}.
666 * @param event the table model event
668 public void tableChanged(TableModelEvent event)
670 switch (event.getType())
672 case TableModelEvent.INSERT:
673 tableRowsInserted(event);
674 break;
675 case TableModelEvent.DELETE:
676 tableRowsDeleted(event);
677 break;
682 * Receives notification when one or more rows have been inserted into the
683 * table.
685 * @param event the table model event
687 public void tableRowsInserted(TableModelEvent event)
689 // TODO: What to do here, if anything? This might be a hook method for
690 // subclasses...
694 * Receives notification when one or more rows have been deleted from the
695 * table.
697 * @param event the table model event
699 public void tableRowsDeleted(TableModelEvent event)
701 // TODO: What to do here, if anything? This might be a hook method for
702 // subclasses...
705 public void columnAdded(TableColumnModelEvent event)
707 // TODO Auto-generated method stub
711 public void columnMarginChanged(ChangeEvent event)
713 // TODO Auto-generated method stub
717 public void columnMoved(TableColumnModelEvent event)
719 // TODO Auto-generated method stub
723 public void columnRemoved(TableColumnModelEvent event)
725 // TODO Auto-generated method stub
729 public void columnSelectionChanged(ListSelectionEvent event)
731 // TODO Auto-generated method stub
735 public void editingCanceled(ChangeEvent event)
737 // TODO Auto-generated method stub
741 public void editingStopped(ChangeEvent event)
743 // TODO Auto-generated method stub
748 * Receives notification when any of the JTable's properties changes. This
749 * is used to replace the listeners on the table's model, selection model,
750 * column model and cell editor.
752 * @param e the property change event
754 public void propertyChange(PropertyChangeEvent e)
756 String propName = e.getPropertyName();
757 if (propName.equals("tableModel"))
759 TableModel oldModel = (TableModel) e.getOldValue();
760 oldModel.removeTableModelListener(this);
761 TableModel newModel = (TableModel) e.getNewValue();
762 newModel.addTableModelListener(this);
764 else if (propName.equals("columnModel"))
766 TableColumnModel oldModel = (TableColumnModel) e.getOldValue();
767 oldModel.removeColumnModelListener(this);
768 TableColumnModel newModel = (TableColumnModel) e.getNewValue();
769 newModel.addColumnModelListener(this);
771 else if (propName.equals("selectionModel"))
773 ListSelectionModel oldModel = (ListSelectionModel) e.getOldValue();
774 oldModel.removeListSelectionListener(this);
775 ListSelectionModel newModel = (ListSelectionModel) e.getNewValue();
776 newModel.addListSelectionListener(this);
778 else if (propName.equals("cellEditor"))
780 CellEditor oldEd = (CellEditor) e.getOldValue();
781 oldEd.removeCellEditorListener(this);
782 CellEditor newEd = (CellEditor) e.getNewValue();
783 newEd.addCellEditorListener(this);
787 public int getAccessibleRow(int index)
789 // TODO Auto-generated method stub
790 return 0;
793 public int getAccessibleColumn(int index)
795 // TODO Auto-generated method stub
796 return 0;
799 public int getAccessibleIndex(int r, int c)
801 // TODO Auto-generated method stub
802 return 0;
805 public Accessible getAccessibleCaption()
807 // TODO Auto-generated method stub
808 return null;
811 public void setAccessibleCaption(Accessible caption)
813 // TODO Auto-generated method stub
817 public Accessible getAccessibleSummary()
819 // TODO Auto-generated method stub
820 return null;
823 public void setAccessibleSummary(Accessible summary)
825 // TODO Auto-generated method stub
829 public int getAccessibleRowCount()
831 // TODO Auto-generated method stub
832 return 0;
835 public int getAccessibleColumnCount()
837 // TODO Auto-generated method stub
838 return 0;
841 public Accessible getAccessibleAt(int r, int c)
843 // TODO Auto-generated method stub
844 return null;
847 public int getAccessibleRowExtentAt(int r, int c)
849 // TODO Auto-generated method stub
850 return 0;
853 public int getAccessibleColumnExtentAt(int r, int c)
855 // TODO Auto-generated method stub
856 return 0;
859 public AccessibleTable getAccessibleRowHeader()
861 // TODO Auto-generated method stub
862 return null;
865 public void setAccessibleRowHeader(AccessibleTable header)
867 // TODO Auto-generated method stub
871 public AccessibleTable getAccessibleColumnHeader()
873 // TODO Auto-generated method stub
874 return null;
877 public void setAccessibleColumnHeader(AccessibleTable header)
879 // TODO Auto-generated method stub
883 public Accessible getAccessibleRowDescription(int r)
885 // TODO Auto-generated method stub
886 return null;
889 public void setAccessibleRowDescription(int r, Accessible description)
891 // TODO Auto-generated method stub
895 public Accessible getAccessibleColumnDescription(int c)
897 // TODO Auto-generated method stub
898 return null;
901 public void setAccessibleColumnDescription(int c, Accessible description)
903 // TODO Auto-generated method stub
907 public boolean isAccessibleSelected(int r, int c)
909 // TODO Auto-generated method stub
910 return false;
913 public boolean isAccessibleRowSelected(int r)
915 // TODO Auto-generated method stub
916 return false;
919 public boolean isAccessibleColumnSelected(int c)
921 // TODO Auto-generated method stub
922 return false;
925 public int[] getSelectedAccessibleRows()
927 // TODO Auto-generated method stub
928 return null;
931 public int[] getSelectedAccessibleColumns()
933 // TODO Auto-generated method stub
934 return null;
938 * Returns the accessible row at the specified index.
940 * @param index the index for which to query the row
942 * @return the row number at the specified table index
944 public int getAccessibleRowAtIndex(int index)
946 // TODO: Back this up by a Mauve test and update API docs accordingly.
947 return index / getColumnCount();
951 * Returns the accessible column at the specified index.
953 * @param index the index for which to query the column
955 * @return the column number at the specified table index
957 public int getAccessibleColumnAtIndex(int index)
959 // TODO: Back this up by a Mauve test and update API docs accordingly.
960 return index % getColumnCount();
964 * Returns the accessible child index at the specified column and row.
966 * @param row the row
967 * @param column the column
969 * @return the index of the accessible child at the specified row and
970 * column
972 public int getAccessibleIndexAt(int row, int column)
974 // TODO: Back this up by a Mauve test and update API docs accordingly.
975 return row * getColumnCount() + column;
979 * Handles property changes from the <code>TableColumn</code>s of this
980 * <code>JTable</code>.
982 * More specifically, this triggers a {@link #revalidate()} call if the
983 * preferredWidth of one of the observed columns changes.
985 class TableColumnPropertyChangeHandler implements PropertyChangeListener
988 * Receives notification that a property of the observed TableColumns has
989 * changed.
991 * @param ev the property change event
993 public void propertyChange(PropertyChangeEvent ev)
995 if (ev.getPropertyName().equals("preferredWidth"))
997 JTableHeader header = getTableHeader();
998 if (header != null)
999 // Do nothing if the table is in the resizing mode.
1000 if (header.getResizingColumn() == null)
1002 TableColumn col = (TableColumn) ev.getSource();
1003 header.setResizingColumn(col);
1004 doLayout();
1005 header.setResizingColumn(null);
1012 * A cell renderer for boolean values.
1014 private class BooleanCellRenderer
1015 extends DefaultTableCellRenderer
1018 * The CheckBox that is used for rendering.
1020 private final JCheckBox checkBox = new JCheckBox();
1023 * The check box must have the text field background and be centered.
1025 private BooleanCellRenderer()
1027 // Render the checkbox identically as the text field.
1028 JTextField f = new JTextField();
1029 checkBox.setForeground(f.getForeground());
1030 checkBox.setBackground(f.getBackground());
1031 checkBox.setHorizontalAlignment(SwingConstants.CENTER);
1035 * Get the check box.
1037 JCheckBox getCheckBox()
1039 return checkBox;
1043 * Returns the component that is used for rendering the value.
1045 * @param table the JTable
1046 * @param value the value of the object
1047 * @param isSelected is the cell selected?
1048 * @param hasFocus has the cell the focus?
1049 * @param row the row to render
1050 * @param column the cell to render
1052 * @return this component (the default table cell renderer)
1054 public Component getTableCellRendererComponent(JTable table, Object value,
1055 boolean isSelected,
1056 boolean hasFocus, int row,
1057 int column)
1059 // Null is rendered as false.
1060 if (value == null)
1061 checkBox.setSelected(false);
1062 else
1064 Boolean boolValue = (Boolean) value;
1065 checkBox.setSelected(boolValue.booleanValue());
1067 return checkBox;
1072 * A cell renderer for Date values.
1074 private class DateCellRenderer
1075 extends DefaultTableCellRenderer
1078 * Returns the component that is used for rendering the value.
1080 * @param table the JTable
1081 * @param value the value of the object
1082 * @param isSelected is the cell selected?
1083 * @param hasFocus has the cell the focus?
1084 * @param row the row to render
1085 * @param column the cell to render
1087 * @return this component (the default table cell renderer)
1089 public Component getTableCellRendererComponent(JTable table, Object value,
1090 boolean isSelected,
1091 boolean hasFocus, int row,
1092 int column)
1094 super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
1095 row, column);
1096 if (value instanceof Date)
1098 Date dateValue = (Date) value;
1099 DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
1100 setText(df.format(dateValue));
1102 return this;
1107 * A cell renderer for Double values.
1109 private class DoubleCellRenderer
1110 extends DefaultTableCellRenderer
1113 * Creates a new instance of NumberCellRenderer.
1115 public DoubleCellRenderer()
1117 setHorizontalAlignment(JLabel.RIGHT);
1121 * Returns the component that is used for rendering the value.
1123 * @param table the JTable
1124 * @param value the value of the object
1125 * @param isSelected is the cell selected?
1126 * @param hasFocus has the cell the focus?
1127 * @param row the row to render
1128 * @param column the cell to render
1130 * @return this component (the default table cell renderer)
1132 public Component getTableCellRendererComponent(JTable table, Object value,
1133 boolean isSelected,
1134 boolean hasFocus, int row,
1135 int column)
1137 super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
1138 row, column);
1139 if (value instanceof Double)
1141 Double doubleValue = (Double) value;
1142 NumberFormat nf = NumberFormat.getInstance();
1143 setText(nf.format(doubleValue.doubleValue()));
1145 return this;
1150 * A cell renderer for Float values.
1152 private class FloatCellRenderer
1153 extends DefaultTableCellRenderer
1156 * Creates a new instance of NumberCellRenderer.
1158 public FloatCellRenderer()
1160 setHorizontalAlignment(JLabel.RIGHT);
1164 * Returns the component that is used for rendering the value.
1166 * @param table the JTable
1167 * @param value the value of the object
1168 * @param isSelected is the cell selected?
1169 * @param hasFocus has the cell the focus?
1170 * @param row the row to render
1171 * @param column the cell to render
1173 * @return this component (the default table cell renderer)
1175 public Component getTableCellRendererComponent(JTable table, Object value,
1176 boolean isSelected,
1177 boolean hasFocus, int row,
1178 int column)
1180 super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
1181 row, column);
1182 if (value instanceof Float)
1184 Float floatValue = (Float) value;
1185 NumberFormat nf = NumberFormat.getInstance();
1186 setText(nf.format(floatValue.floatValue()));
1188 return this;
1193 * A cell renderer for Number values.
1195 private class NumberCellRenderer
1196 extends DefaultTableCellRenderer
1199 * Creates a new instance of NumberCellRenderer.
1201 public NumberCellRenderer()
1203 setHorizontalAlignment(JLabel.RIGHT);
1208 * A cell renderer for Icon values.
1210 private class IconCellRenderer
1211 extends DefaultTableCellRenderer
1214 * Returns the component that is used for rendering the value.
1216 * @param table the JTable
1217 * @param value the value of the object
1218 * @param isSelected is the cell selected?
1219 * @param hasFocus has the cell the focus?
1220 * @param row the row to render
1221 * @param column the cell to render
1223 * @return this component (the default table cell renderer)
1225 public Component getTableCellRendererComponent(JTable table, Object value,
1226 boolean isSelected,
1227 boolean hasFocus, int row,
1228 int column)
1230 super.getTableCellRendererComponent(table, value, isSelected, hasFocus,
1231 row, column);
1232 if (value instanceof Icon)
1234 Icon iconValue = (Icon) value;
1235 setIcon(iconValue);
1236 setText("");
1238 return this;
1243 * The JTable text component (used in editing) always has the table
1244 * as its parent. The scrollRectToVisible must be adjusted taking the
1245 * relative component position.
1247 * @author Audrius Meskauskas (AudriusA@Bioinformatics.org)
1249 private class TableTextField extends JTextField
1252 * Create the text field without the border.
1254 TableTextField()
1256 setBorder(null);
1260 * Scroll the table, making the given rectangle of this component
1261 * visible. Mind the component position with relate to the table.
1262 * With not this method overridden, the scroll pane scrolls to the
1263 * top left cornec (untranslated position of the caret) after the first
1264 * keystroke.
1266 public void scrollRectToVisible(Rectangle r)
1268 // In private class we known that the rectangle data will not be
1269 // reused and we need not to clone it.
1270 r.translate(getX(), getY());
1271 super.scrollRectToVisible(r);
1276 private static final long serialVersionUID = 3876025080382781659L;
1279 * This table, for referring identically name methods from inner classes.
1281 final JTable this_table = this;
1285 * When resizing columns, do not automatically change any columns. In this
1286 * case the table should be enclosed in a {@link JScrollPane} in order to
1287 * accomodate cases in which the table size exceeds its visible area.
1289 public static final int AUTO_RESIZE_OFF = 0;
1292 * When resizing column <code>i</code>, automatically change only the
1293 * single column <code>i+1</code> to provide or absorb excess space
1294 * requirements.
1296 public static final int AUTO_RESIZE_NEXT_COLUMN = 1;
1299 * When resizing column <code>i</code> in a table of <code>n</code>
1300 * columns, automatically change all columns in the range <code>[i+1,
1301 * n)</code>, uniformly, to provide or absorb excess space requirements.
1303 public static final int AUTO_RESIZE_SUBSEQUENT_COLUMNS = 2;
1306 * When resizing column <code>i</code> in a table of <code>n</code>
1307 * columns, automatically change all columns in the range <code>[0,
1308 * n)</code> (with the exception of column i) uniformly, to provide or
1309 * absorb excess space requirements.
1311 public static final int AUTO_RESIZE_ALL_COLUMNS = 4;
1314 * When resizing column <code>i</code> in a table of <code>n</code>
1315 * columns, automatically change column <code>n-1</code> (the last column
1316 * in the table) to provide or absorb excess space requirements.
1318 public static final int AUTO_RESIZE_LAST_COLUMN = 3;
1322 * A table mapping {@link java.lang.Class} objects to
1323 * {@link TableCellEditor} objects. This table is consulted by the
1324 * FIXME
1326 protected Hashtable defaultEditorsByColumnClass;
1329 * A table mapping {@link java.lang.Class} objects to
1330 * {@link TableCellEditor} objects. This table is consulted by the
1331 * FIXME
1333 protected Hashtable defaultRenderersByColumnClass;
1336 * The column that is edited, -1 if the table is not edited currently.
1338 protected int editingColumn;
1341 * The row that is edited, -1 if the table is not edited currently.
1343 protected int editingRow;
1346 * The component that is used for editing.
1347 * <code>null</code> if the table is not editing currently.
1350 protected transient Component editorComp;
1354 * Whether or not the table should automatically compute a matching
1355 * {@link TableColumnModel} and assign it to the {@link #columnModel}
1356 * property when the {@link #dataModel} property is changed.
1358 * @see #setModel(TableModel)
1359 * @see #createDefaultColumnsFromModel()
1360 * @see #setColumnModel(TableColumnModel)
1361 * @see #setAutoCreateColumnsFromModel(boolean)
1362 * @see #getAutoCreateColumnsFromModel()
1364 protected boolean autoCreateColumnsFromModel;
1367 * A numeric code specifying the resizing behavior of the table. Must be
1368 * one of {@link #AUTO_RESIZE_ALL_COLUMNS} (the default), {@link
1369 * #AUTO_RESIZE_LAST_COLUMN}, {@link #AUTO_RESIZE_NEXT_COLUMN}, {@link
1370 * #AUTO_RESIZE_SUBSEQUENT_COLUMNS}, or {@link #AUTO_RESIZE_OFF}.
1372 * @see #doLayout()
1373 * @see #setAutoResizeMode(int)
1374 * @see #getAutoResizeMode()
1376 protected int autoResizeMode;
1379 * The height in pixels of any row of the table. All rows in a table are
1380 * of uniform height. This differs from column width, which varies on a
1381 * per-column basis, and is stored in the individual columns of the
1382 * {@link #columnModel}.
1384 * @see #getRowHeight()
1385 * @see #setRowHeight(int)
1386 * @see TableColumn#getWidth()
1387 * @see TableColumn#setWidth(int)
1389 protected int rowHeight;
1392 * The height in pixels of the gap left between any two rows of the table.
1394 * @see #setRowMargin(int)
1395 * @see #getRowHeight()
1396 * @see #getIntercellSpacing()
1397 * @see #setIntercellSpacing(Dimension)
1398 * @see TableColumnModel#getColumnMargin()
1399 * @see TableColumnModel#setColumnMargin(int)
1401 protected int rowMargin;
1404 * Whether or not the table should allow row selection. If the table
1405 * allows both row <em>and</em> column selection, it is said to allow
1406 * "cell selection". Previous versions of the JDK supported cell
1407 * selection as an independent concept, but it is now represented solely
1408 * in terms of simultaneous row and column selection.
1410 * @see TableColumnModel#getColumnSelectionAllowed()
1411 * @see #setRowSelectionAllowed(boolean)
1412 * @see #getRowSelectionAllowed()
1413 * @see #getCellSelectionEnabled()
1414 * @see #setCellSelectionEnabled(boolean)
1416 protected boolean rowSelectionAllowed;
1419 * Obsolete. Use {@link #rowSelectionAllowed}, {@link
1420 * #getColumnSelectionAllowed}, or the combined methods {@link
1421 * #getCellSelectionEnabled} and {@link #setCellSelectionEnabled(boolean)}.
1423 protected boolean cellSelectionEnabled;
1426 * The model for data stored in the table. Confusingly, the published API
1427 * requires that this field be called <code>dataModel</code>, despite its
1428 * property name. The table listens to its model as a {@link
1429 * TableModelListener}.
1431 * @see #tableChanged(TableModelEvent)
1432 * @see TableModel#addTableModelListener(TableModelListener)
1434 protected TableModel dataModel;
1437 * <p>A model of various aspects of the columns of the table, <em>not
1438 * including</em> the data stored in them. The {@link TableColumnModel}
1439 * is principally concerned with holding a set of {@link TableColumn}
1440 * objects, each of which describes the display parameters of a column
1441 * and the numeric index of the column from the data model which the
1442 * column is presenting.</p>
1444 * <p>The TableColumnModel also contains a {@link ListSelectionModel} which
1445 * indicates which columns are currently selected. This selection model
1446 * works in combination with the {@link #selectionModel} of the table
1447 * itself to specify a <em>table selection</em>: a combination of row and
1448 * column selections.</p>
1450 * <p>Most application programmers do not need to work with this property
1451 * at all: setting {@link #autoCreateColumnsFromModel} will construct the
1452 * columnModel automatically, and the table acts as a facade for most of
1453 * the interesting properties of the columnModel anyways.</p>
1455 * @see #setColumnModel(TableColumnModel)
1456 * @see #getColumnModel()
1458 protected TableColumnModel columnModel;
1461 * A model of the rows of this table which are currently selected. This
1462 * model is used in combination with the column selection model held as a
1463 * member of the {@link #columnModel} property, to represent the rows and
1464 * columns (or both: cells) of the table which are currently selected.
1466 * @see #rowSelectionAllowed
1467 * @see #setSelectionModel(ListSelectionModel)
1468 * @see #getSelectionModel()
1469 * @see TableColumnModel#getSelectionModel()
1470 * @see ListSelectionModel#addListSelectionListener(ListSelectionListener)
1472 protected ListSelectionModel selectionModel;
1475 * The current cell editor.
1477 protected TableCellEditor cellEditor;
1480 * Whether or not drag-and-drop is enabled on this table.
1482 * @see #setDragEnabled(boolean)
1483 * @see #getDragEnabled()
1485 private boolean dragEnabled;
1488 * The color to paint the grid lines of the table, when either {@link
1489 * #showHorizontalLines} or {@link #showVerticalLines} is set.
1491 * @see #setGridColor(Color)
1492 * @see #getGridColor()
1494 protected Color gridColor;
1497 * The size this table would prefer its viewport assume, if it is
1498 * contained in a {@link JScrollPane}.
1500 * @see #setPreferredScrollableViewportSize(Dimension)
1501 * @see #getPreferredScrollableViewportSize()
1503 protected Dimension preferredViewportSize;
1506 * The color to paint the background of selected cells. Fires a property
1507 * change event with name {@link #SELECTION_BACKGROUND_CHANGED_PROPERTY}
1508 * when its value changes.
1510 * @see #setSelectionBackground(Color)
1511 * @see #getSelectionBackground()
1513 protected Color selectionBackground;
1516 * The name carried in property change events when the {@link
1517 * #selectionBackground} property changes.
1519 private static final String SELECTION_BACKGROUND_CHANGED_PROPERTY = "selectionBackground";
1522 * The color to paint the foreground of selected cells. Fires a property
1523 * change event with name {@link #SELECTION_FOREGROUND_CHANGED_PROPERTY}
1524 * when its value changes.
1526 * @see #setSelectionForeground(Color)
1527 * @see #getSelectionForeground()
1529 protected Color selectionForeground;
1532 * The name carried in property change events when the
1533 * {@link #selectionForeground} property changes.
1535 private static final String SELECTION_FOREGROUND_CHANGED_PROPERTY = "selectionForeground";
1538 * The showHorizontalLines property.
1540 protected boolean showHorizontalLines;
1543 * The showVerticalLines property.
1545 protected boolean showVerticalLines;
1548 * The tableHeader property.
1550 protected JTableHeader tableHeader;
1553 * The property handler for this table's columns.
1555 TableColumnPropertyChangeHandler tableColumnPropertyChangeHandler =
1556 new TableColumnPropertyChangeHandler();
1559 * Whether cell editors should receive keyboard focus when the table is
1560 * activated.
1562 private boolean surrendersFocusOnKeystroke = false;
1565 * A Rectangle object to be reused in {@link #getCellRect}.
1567 private Rectangle rectCache = new Rectangle();
1570 * Creates a new <code>JTable</code> instance.
1572 public JTable ()
1574 this(null, null, null);
1578 * Creates a new <code>JTable</code> instance with the given number
1579 * of rows and columns.
1581 * @param numRows an <code>int</code> value
1582 * @param numColumns an <code>int</code> value
1584 public JTable (int numRows, int numColumns)
1586 this(new DefaultTableModel(numRows, numColumns));
1590 * Creates a new <code>JTable</code> instance, storing the given data
1591 * array and heaving the given column names. To see the column names,
1592 * you must place the JTable into the {@link JScrollPane}.
1594 * @param data an <code>Object[][]</code> the table data
1595 * @param columnNames an <code>Object[]</code> the column headers
1597 public JTable(Object[][] data, Object[] columnNames)
1599 this(new DefaultTableModel(data, columnNames));
1603 * Creates a new <code>JTable</code> instance, using the given data model
1604 * object that provides information about the table content. The table model
1605 * object is asked for the table size, other features and also receives
1606 * notifications in the case when the table has been edited by the user.
1608 * @param model
1609 * the table model.
1611 public JTable (TableModel model)
1613 this(model, null, null);
1617 * Creates a new <code>JTable</code> instance, using the given model object
1618 * that provides information about the table content. The table data model
1619 * object is asked for the table size, other features and also receives
1620 * notifications in the case when the table has been edited by the user. The
1621 * table column model provides more detailed control on the table column
1622 * related features.
1624 * @param dm
1625 * the table data mode
1626 * @param cm
1627 * the table column model
1629 public JTable (TableModel dm, TableColumnModel cm)
1631 this(dm, cm, null);
1635 * Creates a new <code>JTable</code> instance, providing data model,
1636 * column model and list selection model. The list selection model
1637 * manages the selections.
1639 * @param dm data model (manages table data)
1640 * @param cm column model (manages table columns)
1641 * @param sm list selection model (manages table selections)
1643 public JTable (TableModel dm, TableColumnModel cm, ListSelectionModel sm)
1645 boolean autoCreate = false;
1646 if (cm != null)
1647 setColumnModel(cm);
1648 else
1650 setColumnModel(createDefaultColumnModel());
1651 autoCreate = true;
1653 setSelectionModel(sm == null ? createDefaultSelectionModel() : sm);
1654 setModel(dm == null ? createDefaultDataModel() : dm);
1655 setAutoCreateColumnsFromModel(autoCreate);
1656 initializeLocalVars();
1657 // The following four lines properly set the lead selection indices.
1658 // After this, the UI will handle the lead selection indices.
1659 // FIXME: this should probably not be necessary, if the UI is installed
1660 // before the TableModel is set then the UI will handle things on its
1661 // own, but certain variables need to be set before the UI can be installed
1662 // so we must get the correct order for all the method calls in this
1663 // constructor.
1664 selectionModel.setAnchorSelectionIndex(0);
1665 selectionModel.setLeadSelectionIndex(0);
1666 columnModel.getSelectionModel().setAnchorSelectionIndex(0);
1667 columnModel.getSelectionModel().setLeadSelectionIndex(0);
1668 updateUI();
1672 * Creates a new <code>JTable</code> instance that uses data and column
1673 * names, stored in {@link Vector}s.
1675 * @param data the table data
1676 * @param columnNames the table column names.
1678 public JTable(Vector data, Vector columnNames)
1680 this(new DefaultTableModel(data, columnNames));
1684 * Initialize local variables to default values.
1686 protected void initializeLocalVars()
1688 setTableHeader(createDefaultTableHeader());
1689 if (autoCreateColumnsFromModel)
1690 createDefaultColumnsFromModel();
1691 this.columnModel.addColumnModelListener(this);
1693 this.defaultRenderersByColumnClass = new Hashtable();
1694 createDefaultRenderers();
1696 this.defaultEditorsByColumnClass = new Hashtable();
1697 createDefaultEditors();
1699 this.autoResizeMode = AUTO_RESIZE_SUBSEQUENT_COLUMNS;
1700 this.rowHeight = 16;
1701 this.rowMargin = 1;
1702 this.rowSelectionAllowed = true;
1703 // this.accessibleContext = new AccessibleJTable();
1704 this.cellEditor = null;
1705 // COMPAT: Both Sun and IBM have drag enabled
1706 this.dragEnabled = true;
1707 this.preferredViewportSize = new Dimension(450,400);
1708 this.showHorizontalLines = true;
1709 this.showVerticalLines = true;
1710 this.editingColumn = -1;
1711 this.editingRow = -1;
1712 setIntercellSpacing(new Dimension(1,1));
1716 * Add the new table column. The table column class allows to specify column
1717 * features more precisely, setting the preferred width, column data type
1718 * (column class) and table headers.
1720 * There is no need the add columns to the table if the default column
1721 * handling is sufficient.
1723 * @param column
1724 * the new column to add.
1726 public void addColumn(TableColumn column)
1728 if (column.getHeaderValue() == null)
1730 String name = dataModel.getColumnName(column.getModelIndex());
1731 column.setHeaderValue(name);
1734 columnModel.addColumn(column);
1735 column.addPropertyChangeListener(tableColumnPropertyChangeHandler);
1739 * Create the default editors for this table. The default method creates
1740 * the editor for Booleans.
1742 * Other fields are edited as strings at the moment.
1744 protected void createDefaultEditors()
1746 JCheckBox box = new BooleanCellRenderer().getCheckBox();
1747 setDefaultEditor(Boolean.class, new DefaultCellEditor(box));
1751 * Create the default renderers for this table. The default method creates
1752 * renderers for Boolean, Number, Double, Date, Icon and ImageIcon.
1755 protected void createDefaultRenderers()
1757 setDefaultRenderer(Boolean.class, new BooleanCellRenderer());
1758 setDefaultRenderer(Number.class, new NumberCellRenderer());
1759 setDefaultRenderer(Double.class, new DoubleCellRenderer());
1760 setDefaultRenderer(Double.class, new FloatCellRenderer());
1761 setDefaultRenderer(Date.class, new DateCellRenderer());
1762 setDefaultRenderer(Icon.class, new IconCellRenderer());
1763 setDefaultRenderer(ImageIcon.class, new IconCellRenderer());
1767 * @deprecated 1.0.2, replaced by <code>new JScrollPane(JTable)</code>
1769 public static JScrollPane createScrollPaneForTable(JTable table)
1771 return new JScrollPane(table);
1775 * Create the default table column model that is used if the user-defined
1776 * column model is not provided. The default method creates
1777 * {@link DefaultTableColumnModel}.
1779 * @return the created table column model.
1781 protected TableColumnModel createDefaultColumnModel()
1783 return new DefaultTableColumnModel();
1787 * Create the default table data model that is used if the user-defined
1788 * data model is not provided. The default method creates
1789 * {@link DefaultTableModel}.
1791 * @return the created table data model.
1793 protected TableModel createDefaultDataModel()
1795 return new DefaultTableModel();
1799 * Create the default table selection model that is used if the user-defined
1800 * selection model is not provided. The default method creates
1801 * {@link DefaultListSelectionModel}.
1803 * @return the created table data model.
1805 protected ListSelectionModel createDefaultSelectionModel()
1807 return new DefaultListSelectionModel();
1811 * Create the default table header, if the user - defined table header is not
1812 * provided.
1814 * @return the default table header.
1816 protected JTableHeader createDefaultTableHeader()
1818 return new JTableHeader(columnModel);
1822 * Invoked when the column is added. Revalidates and repains the table.
1824 public void columnAdded (TableColumnModelEvent event)
1826 revalidate();
1827 repaint();
1831 * Invoked when the column margin is changed.
1832 * Revalidates and repains the table.
1834 public void columnMarginChanged (ChangeEvent event)
1836 revalidate();
1837 repaint();
1841 * Invoked when the column is moved. Revalidates and repains the table.
1843 public void columnMoved (TableColumnModelEvent event)
1845 revalidate();
1846 repaint();
1850 * Invoked when the column is removed. Revalidates and repains the table.
1852 public void columnRemoved (TableColumnModelEvent event)
1854 revalidate();
1855 repaint();
1859 * Invoked when the the column selection changes.
1861 public void columnSelectionChanged (ListSelectionEvent event)
1863 repaint();
1867 * Invoked when the editing is cancelled.
1869 public void editingCanceled (ChangeEvent event)
1871 if (editorComp!=null)
1873 remove(editorComp);
1874 repaint(editorComp.getBounds());
1875 editorComp = null;
1880 * Finish the current editing session and update the table with the
1881 * new value by calling {@link #setValueAt}.
1883 * @param event the change event
1885 public void editingStopped (ChangeEvent event)
1887 if (editorComp!=null)
1889 remove(editorComp);
1890 setValueAt(cellEditor.getCellEditorValue(), editingRow, editingColumn);
1891 repaint(editorComp.getBounds());
1892 editorComp = null;
1894 requestFocusInWindow();
1898 * Invoked when the table changes.
1899 * <code>null</code> means everything changed.
1901 public void tableChanged (TableModelEvent event)
1903 // update the column model from the table model if the structure has
1904 // changed and the flag autoCreateColumnsFromModel is set
1905 if ((event == null || (event.getFirstRow() == TableModelEvent.HEADER_ROW))
1906 && autoCreateColumnsFromModel)
1907 createDefaultColumnsFromModel();
1909 // If the structure changes, we need to revalidate, since that might
1910 // affect the size parameters of the JTable. Otherwise we only need
1911 // to perform a repaint to update the view.
1912 if (event == null || event.getType() == TableModelEvent.INSERT)
1913 revalidate();
1914 if (event == null || event.getType() == TableModelEvent.DELETE)
1916 if (dataModel.getRowCount() == 0)
1917 clearSelection();
1918 revalidate();
1920 repaint();
1924 * Invoked when another table row is selected.
1926 public void valueChanged (ListSelectionEvent event)
1928 repaint();
1932 * Returns index of the column that contains specified point
1933 * or -1 if this table doesn't contain this point.
1935 * @param point point to identify the column
1936 * @return index of the column that contains specified point or
1937 * -1 if this table doesn't contain this point.
1939 public int columnAtPoint(Point point)
1941 if (point != null)
1943 int ncols = getColumnCount();
1944 Dimension gap = getIntercellSpacing();
1945 TableColumnModel cols = getColumnModel();
1946 int x = point.x;
1948 for (int i = 0; i < ncols; ++i)
1950 int width = cols.getColumn(i).getWidth()
1951 + (gap == null ? 0 : gap.width);
1952 if (0 <= x && x < width)
1953 return i;
1954 x -= width;
1957 return -1;
1961 * Returns index of the row that contains specified point or -1 if this table
1962 * doesn't contain this point.
1964 * @param point
1965 * point to identify the row
1966 * @return index of the row that contains specified point or -1 if this table
1967 * doesn't contain this point.
1969 public int rowAtPoint(Point point)
1971 if (point != null)
1973 int nrows = getRowCount();
1974 int height = getRowHeight() + getRowMargin();
1975 int y = point.y;
1977 int r = y / height;
1978 if (r < 0 || r >= nrows)
1979 return -1;
1980 else
1981 return r;
1983 else
1984 return -1;
1987 /**
1988 * Calculate the visible rectangle for a particular row and column. The
1989 * row and column are specified in visual terms; the column may not match
1990 * the {@link #dataModel} column.
1992 * @param row the visible row to get the cell rectangle of
1994 * @param column the visible column to get the cell rectangle of, which may
1995 * differ from the {@link #dataModel} column
1997 * @param includeSpacing whether or not to include the cell margins in the
1998 * resulting cell. If <code>false</code>, the result will only contain the
1999 * inner area of the target cell, not including its margins.
2001 * @return a rectangle enclosing the specified cell
2003 public Rectangle getCellRect(int row,
2004 int column,
2005 boolean includeSpacing)
2007 // moveToCellBeingEdited expects the cached value and clones it.
2008 // If the caching would be removed later, uplate moveToCellBeingEdited
2009 // as well.
2010 int height = getRowHeight(row);
2011 int width = columnModel.getColumn(column).getWidth();
2012 int x_gap = columnModel.getColumnMargin();
2013 int y_gap = rowMargin;
2015 column = Math.max(0, Math.min(column, getColumnCount() - 1));
2016 row = Math.max(0, Math.min(row, getRowCount() - 1));
2018 int x = 0;
2019 int y = (height + y_gap) * row;
2021 for (int i = 0; i < column; ++i)
2022 x += columnModel.getColumn(i).getWidth();
2024 if (includeSpacing)
2025 rectCache.setBounds(x, y, width, height +y_gap);
2026 else
2027 rectCache.setBounds(x, y, width - x_gap, height);
2028 return rectCache;
2031 public void clearSelection()
2033 selectionModel.clearSelection();
2034 getColumnModel().getSelectionModel().clearSelection();
2038 * Get the value of the selectedRow property by delegation to
2039 * the {@link ListSelectionModel#getMinSelectionIndex} method of the
2040 * {@link #selectionModel} field.
2042 * @return The current value of the selectedRow property
2044 public int getSelectedRow ()
2046 return selectionModel.getMinSelectionIndex();
2050 * Get the value of the {@link #selectionModel} property.
2052 * @return The current value of the property
2054 public ListSelectionModel getSelectionModel()
2056 //Neither Sun nor IBM returns null if rowSelection not allowed
2057 return selectionModel;
2060 public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction)
2062 if (orientation == SwingConstants.VERTICAL)
2063 return visibleRect.height * direction;
2064 else
2065 return visibleRect.width * direction;
2069 * Get the value of the <code>scrollableTracksViewportHeight</code> property.
2071 * @return The constant value <code>false</code>
2073 public boolean getScrollableTracksViewportHeight()
2075 return false;
2079 * Get the value of the <code>scrollableTracksViewportWidth</code> property.
2081 * @return <code>true</code> unless the {@link #autoResizeMode} property is
2082 * <code>AUTO_RESIZE_OFF</code>
2084 public boolean getScrollableTracksViewportWidth()
2086 if (autoResizeMode == AUTO_RESIZE_OFF)
2087 return false;
2088 else
2089 return true;
2092 public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction)
2094 // FIXME: I don't exactly know what sun does here. in both cases they
2095 // pick values which do *not* simply expose the next cell in a given
2096 // scroll direction.
2098 if (orientation == SwingConstants.VERTICAL)
2099 return direction * rowHeight;
2100 else
2102 int sum = 0;
2103 for (int i = 0; i < getColumnCount(); ++i)
2104 sum += columnModel.getColumn(0).getWidth();
2105 int inc = getColumnCount() == 0 ? 10 : sum / getColumnCount();
2106 return direction * inc;
2112 * Get the cell editor, suitable for editing the given cell. The default
2113 * method requests the editor from the column model. If the column model does
2114 * not provide the editor, the call is forwarded to the
2115 * {@link #getDefaultEditor(Class)} with the parameter, obtained from
2116 * {@link TableModel#getColumnClass(int)}.
2118 * @param row the cell row
2119 * @param column the cell column
2120 * @return the editor to edit that cell
2122 public TableCellEditor getCellEditor(int row, int column)
2124 TableCellEditor editor = columnModel.getColumn(column).getCellEditor();
2126 if (editor == null)
2128 int mcolumn = convertColumnIndexToModel(column);
2129 editor = getDefaultEditor(dataModel.getColumnClass(mcolumn));
2132 return editor;
2136 * Get the default editor for editing values of the given type
2137 * (String, Boolean and so on).
2139 * @param columnClass the class of the value that will be edited.
2141 * @return the editor, suitable for editing this data type
2143 public TableCellEditor getDefaultEditor(Class columnClass)
2145 if (defaultEditorsByColumnClass.containsKey(columnClass))
2146 return (TableCellEditor) defaultEditorsByColumnClass.get(columnClass);
2147 else
2149 JTextField t = new TableTextField();
2150 TableCellEditor r = new DefaultCellEditor(t);
2151 defaultEditorsByColumnClass.put(columnClass, r);
2152 return r;
2157 * Get the cell renderer for rendering the given cell.
2159 * @param row the cell row
2160 * @param column the cell column
2161 * @return the cell renderer to render that cell.
2163 public TableCellRenderer getCellRenderer(int row, int column)
2165 TableCellRenderer renderer = columnModel.getColumn(column).getCellRenderer();
2166 if (renderer == null)
2168 int mcolumn = convertColumnIndexToModel(column);
2169 renderer = getDefaultRenderer(dataModel.getColumnClass(mcolumn));
2171 return renderer;
2175 * Set default renderer for rendering the given data type.
2177 * @param columnClass the data type (String, Boolean and so on) that must be
2178 * rendered.
2179 * @param rend the renderer that will rend this data type
2181 public void setDefaultRenderer(Class columnClass, TableCellRenderer rend)
2183 defaultRenderersByColumnClass.put(columnClass, rend);
2187 * Get the default renderer for rendering the given data type.
2189 * @param columnClass the data that must be rendered
2191 * @return the appropriate defauld renderer for rendering that data type.
2193 public TableCellRenderer getDefaultRenderer(Class columnClass)
2195 if (defaultRenderersByColumnClass.containsKey(columnClass))
2196 return (TableCellRenderer) defaultRenderersByColumnClass.get(columnClass);
2197 else
2199 TableCellRenderer r = new DefaultTableCellRenderer();
2200 defaultRenderersByColumnClass.put(columnClass, r);
2201 return r;
2206 * Convert the table model index into the table column number.
2207 * The model number need not match the real column position. The columns
2208 * may be rearranged by the user with mouse at any time by dragging the
2209 * column headers.
2211 * @param vc the column number (0=first).
2213 * @return the table column model index of this column.
2215 * @see TableColumn#getModelIndex()
2217 public int convertColumnIndexToModel(int vc)
2219 if (vc < 0)
2220 return vc;
2221 else
2222 return columnModel.getColumn(vc).getModelIndex();
2226 * Convert the table column number to the table column model index.
2227 * The model number need not match the real column position. The columns
2228 * may be rearranged by the user with mouse at any time by dragging the
2229 * column headers.
2231 * @param mc the table column index (0=first).
2233 * @return the table column number in the model
2235 * @see TableColumn#getModelIndex()
2237 public int convertColumnIndexToView(int mc)
2239 if (mc < 0)
2240 return mc;
2241 int ncols = getColumnCount();
2242 for (int vc = 0; vc < ncols; ++vc)
2244 if (columnModel.getColumn(vc).getModelIndex() == mc)
2245 return vc;
2247 return -1;
2251 * Prepare the renderer for rendering the given cell.
2253 * @param renderer the renderer being prepared
2254 * @param row the row of the cell being rendered
2255 * @param column the column of the cell being rendered
2257 * @return the component which .paint() method will paint the cell.
2259 public Component prepareRenderer(TableCellRenderer renderer,
2260 int row,
2261 int column)
2264 boolean rowSelAllowed = getRowSelectionAllowed();
2265 boolean colSelAllowed = getColumnSelectionAllowed();
2266 boolean isSel = false;
2267 if (rowSelAllowed && colSelAllowed || !rowSelAllowed && !colSelAllowed)
2268 isSel = isCellSelected(row, column);
2269 else
2270 isSel = isRowSelected(row) && getRowSelectionAllowed()
2271 || isColumnSelected(column) && getColumnSelectionAllowed();
2273 // Determine the focused cell. The focused cell is the cell at the
2274 // leadSelectionIndices of the row and column selection model.
2275 ListSelectionModel rowSel = getSelectionModel();
2276 ListSelectionModel colSel = getColumnModel().getSelectionModel();
2277 boolean hasFocus = hasFocus() && isEnabled()
2278 && rowSel.getLeadSelectionIndex() == row
2279 && colSel.getLeadSelectionIndex() == column;
2281 return renderer.getTableCellRendererComponent(this,
2282 dataModel.getValueAt(row,
2283 convertColumnIndexToModel(column)),
2284 isSel,
2285 hasFocus,
2286 row, column);
2291 * Get the value of the {@link #autoCreateColumnsFromModel} property.
2293 * @return The current value of the property
2295 public boolean getAutoCreateColumnsFromModel()
2297 return autoCreateColumnsFromModel;
2301 * Get the value of the {@link #autoResizeMode} property.
2303 * @return The current value of the property
2305 public int getAutoResizeMode()
2307 return autoResizeMode;
2311 * Get the value of the {@link #rowHeight} property.
2313 * @return The current value of the property
2315 public int getRowHeight()
2317 return rowHeight;
2321 * Get the height of the specified row.
2323 * @param row the row whose height to return
2325 public int getRowHeight(int row)
2327 // FIXME: return the height of the specified row
2328 // which may be different from the general rowHeight
2329 return rowHeight;
2334 * Get the value of the {@link #rowMargin} property.
2336 * @return The current value of the property
2338 public int getRowMargin()
2340 return rowMargin;
2344 * Get the value of the {@link #rowSelectionAllowed} property.
2346 * @return The current value of the property
2348 public boolean getRowSelectionAllowed()
2350 return rowSelectionAllowed;
2354 * Get the value of the {@link #cellSelectionEnabled} property.
2356 * @return The current value of the property
2358 public boolean getCellSelectionEnabled()
2360 return getColumnSelectionAllowed() && getRowSelectionAllowed();
2364 * Get the value of the {@link #dataModel} property.
2366 * @return The current value of the property
2368 public TableModel getModel()
2370 return dataModel;
2374 * Get the value of the <code>columnCount</code> property by
2375 * delegation to the @{link #columnModel} field.
2377 * @return The current value of the columnCount property
2379 public int getColumnCount()
2381 return columnModel.getColumnCount();
2385 * Get the value of the <code>rowCount</code> property by
2386 * delegation to the @{link #dataModel} field.
2388 * @return The current value of the rowCount property
2390 public int getRowCount()
2392 return dataModel.getRowCount();
2396 * Get the value of the {@link #columnModel} property.
2398 * @return The current value of the property
2400 public TableColumnModel getColumnModel()
2402 return columnModel;
2406 * Get the value of the <code>selectedColumn</code> property by
2407 * delegation to the @{link #columnModel} field.
2409 * @return The current value of the selectedColumn property
2411 public int getSelectedColumn()
2413 return columnModel.getSelectionModel().getMinSelectionIndex();
2416 private static int countSelections(ListSelectionModel lsm)
2418 int lo = lsm.getMinSelectionIndex();
2419 int hi = lsm.getMaxSelectionIndex();
2420 int sum = 0;
2421 if (lo != -1 && hi != -1)
2423 switch (lsm.getSelectionMode())
2425 case ListSelectionModel.SINGLE_SELECTION:
2426 sum = 1;
2427 break;
2429 case ListSelectionModel.SINGLE_INTERVAL_SELECTION:
2430 sum = hi - lo + 1;
2431 break;
2433 case ListSelectionModel.MULTIPLE_INTERVAL_SELECTION:
2434 for (int i = lo; i <= hi; ++i)
2435 if (lsm.isSelectedIndex(i))
2436 ++sum;
2437 break;
2440 return sum;
2443 private static int[] getSelections(ListSelectionModel lsm)
2445 int sz = countSelections(lsm);
2446 int [] ret = new int[sz];
2448 int lo = lsm.getMinSelectionIndex();
2449 int hi = lsm.getMaxSelectionIndex();
2450 int j = 0;
2451 if (lo != -1 && hi != -1)
2453 switch (lsm.getSelectionMode())
2455 case ListSelectionModel.SINGLE_SELECTION:
2456 ret[0] = lo;
2457 break;
2459 case ListSelectionModel.SINGLE_INTERVAL_SELECTION:
2460 for (int i = lo; i <= hi; ++i)
2461 ret[j++] = i;
2462 break;
2464 case ListSelectionModel.MULTIPLE_INTERVAL_SELECTION:
2465 for (int i = lo; i <= hi; ++i)
2466 if (lsm.isSelectedIndex(i))
2467 ret[j++] = i;
2468 break;
2471 return ret;
2475 * Get the value of the <code>selectedColumnCount</code> property by
2476 * delegation to the @{link #columnModel} field.
2478 * @return The current value of the selectedColumnCount property
2480 public int getSelectedColumnCount()
2482 return countSelections(columnModel.getSelectionModel());
2486 * Get the value of the <code>selectedColumns</code> property by
2487 * delegation to the @{link #columnModel} field.
2489 * @return The current value of the selectedColumns property
2491 public int[] getSelectedColumns()
2493 return getSelections(columnModel.getSelectionModel());
2497 * Get the value of the <code>columnSelectionAllowed</code> property.
2499 * @return The current value of the columnSelectionAllowed property
2501 public boolean getColumnSelectionAllowed()
2503 return getColumnModel().getColumnSelectionAllowed();
2507 * Get the value of the <code>selectedRowCount</code> property by
2508 * delegation to the @{link #selectionModel} field.
2510 * @return The current value of the selectedRowCount property
2512 public int getSelectedRowCount()
2514 return countSelections(selectionModel);
2518 * Get the value of the <code>selectedRows</code> property by
2519 * delegation to the @{link #selectionModel} field.
2521 * @return The current value of the selectedRows property
2523 public int[] getSelectedRows()
2525 return getSelections(selectionModel);
2529 * Get the value of the {@link #accessibleContext} property.
2531 * @return The current value of the property
2533 public AccessibleContext getAccessibleContext()
2535 return accessibleContext;
2539 * Get the value of the {@link #cellEditor} property.
2541 * @return The current value of the property
2543 public TableCellEditor getCellEditor()
2545 return cellEditor;
2549 * Get the value of the {@link #dragEnabled} property.
2551 * @return The current value of the property
2553 public boolean getDragEnabled()
2555 return dragEnabled;
2559 * Get the value of the {@link #gridColor} property.
2561 * @return The current value of the property
2563 public Color getGridColor()
2565 return gridColor;
2569 * Get the value of the <code>intercellSpacing</code> property.
2571 * @return The current value of the property
2573 public Dimension getIntercellSpacing()
2575 return new Dimension(columnModel.getColumnMargin(), rowMargin);
2579 * Get the value of the {@link #preferredViewportSize} property.
2581 * @return The current value of the property
2583 public Dimension getPreferredScrollableViewportSize()
2585 return preferredViewportSize;
2589 * Get the value of the {@link #selectionBackground} property.
2591 * @return The current value of the property
2593 public Color getSelectionBackground()
2595 return selectionBackground;
2599 * Get the value of the {@link #selectionForeground} property.
2601 * @return The current value of the property
2603 public Color getSelectionForeground()
2605 return selectionForeground;
2609 * Get the value of the {@link #showHorizontalLines} property.
2611 * @return The current value of the property
2613 public boolean getShowHorizontalLines()
2615 return showHorizontalLines;
2619 * Get the value of the {@link #showVerticalLines} property.
2621 * @return The current value of the property
2623 public boolean getShowVerticalLines()
2625 return showVerticalLines;
2629 * Get the value of the {@link #tableHeader} property.
2631 * @return The current value of the property
2633 public JTableHeader getTableHeader()
2635 return tableHeader;
2639 * Removes specified column from displayable columns of this table.
2641 * @param column column to removed
2643 public void removeColumn(TableColumn column)
2645 columnModel.removeColumn(column);
2649 * Moves column at the specified index to new given location.
2651 * @param column index of the column to move
2652 * @param targetColumn index specifying new location of the column
2654 public void moveColumn(int column,int targetColumn)
2656 columnModel.moveColumn(column, targetColumn);
2660 * Set the value of the {@link #autoCreateColumnsFromModel} flag. If the
2661 * flag changes from <code>false</code> to <code>true</code>, the
2662 * {@link #createDefaultColumnsFromModel()} method is called.
2664 * @param autoCreate the new value of the flag.
2666 public void setAutoCreateColumnsFromModel(boolean autoCreate)
2668 if (autoCreateColumnsFromModel != autoCreate)
2670 autoCreateColumnsFromModel = autoCreate;
2671 if (autoCreate)
2672 createDefaultColumnsFromModel();
2677 * Set the value of the {@link #autoResizeMode} property.
2679 * @param a The new value of the autoResizeMode property
2681 public void setAutoResizeMode(int a)
2683 autoResizeMode = a;
2684 revalidate();
2685 repaint();
2689 * Set the value of the {@link #rowHeight} property.
2691 * @param r The new value of the rowHeight property
2693 public void setRowHeight(int r)
2695 if (r < 1)
2696 throw new IllegalArgumentException();
2698 rowHeight = r;
2699 revalidate();
2700 repaint();
2704 * Sets the value of the rowHeight property for the specified
2705 * row.
2707 * @param rh is the new rowHeight
2708 * @param row is the row to change the rowHeight of
2710 public void setRowHeight(int row, int rh)
2712 setRowHeight(rh);
2713 // FIXME: not implemented
2717 * Set the value of the {@link #rowMargin} property.
2719 * @param r The new value of the rowMargin property
2721 public void setRowMargin(int r)
2723 rowMargin = r;
2724 revalidate();
2725 repaint();
2729 * Set the value of the {@link #rowSelectionAllowed} property.
2731 * @param r The new value of the rowSelectionAllowed property
2733 public void setRowSelectionAllowed(boolean r)
2735 rowSelectionAllowed = r;
2736 repaint();
2740 * Set the value of the {@link #cellSelectionEnabled} property.
2742 * @param c The new value of the cellSelectionEnabled property
2744 public void setCellSelectionEnabled(boolean c)
2746 setColumnSelectionAllowed(c);
2747 setRowSelectionAllowed(c);
2748 // for backward-compatibility sake:
2749 cellSelectionEnabled = true;
2753 * <p>Set the value of the {@link #dataModel} property.</p>
2755 * <p>Unregister <code>this</code> as a {@link TableModelListener} from
2756 * previous {@link #dataModel} and register it with new parameter
2757 * <code>m</code>.</p>
2759 * @param m The new value of the model property
2761 public void setModel(TableModel m)
2763 // Throw exception is m is null.
2764 if (m == null)
2765 throw new IllegalArgumentException();
2767 // Don't do anything if setting the current model again.
2768 if (dataModel == m)
2769 return;
2771 TableModel oldModel = dataModel;
2773 // Remove table as TableModelListener from old model.
2774 if (dataModel != null)
2775 dataModel.removeTableModelListener(this);
2777 if (m != null)
2779 // Set property.
2780 dataModel = m;
2782 // Add table as TableModelListener to new model.
2783 dataModel.addTableModelListener(this);
2785 // Automatically create columns.
2786 if (autoCreateColumnsFromModel)
2787 createDefaultColumnsFromModel();
2790 // This property is bound, so we fire a property change event.
2791 firePropertyChange("model", oldModel, dataModel);
2793 // Repaint table.
2794 revalidate();
2795 repaint();
2799 * <p>Set the value of the {@link #columnModel} property.</p>
2801 * <p>Unregister <code>this</code> as a {@link TableColumnModelListener}
2802 * from previous {@link #columnModel} and register it with new parameter
2803 * <code>c</code>.</p>
2805 * @param c The new value of the columnModel property
2807 public void setColumnModel(TableColumnModel c)
2809 if (c == null)
2810 throw new IllegalArgumentException();
2811 TableColumnModel tmp = columnModel;
2812 if (tmp != null)
2813 tmp.removeColumnModelListener(this);
2814 if (c != null)
2815 c.addColumnModelListener(this);
2816 columnModel = c;
2817 if (dataModel != null && columnModel != null)
2819 int ncols = getColumnCount();
2820 TableColumn column;
2821 for (int i = 0; i < ncols; ++i)
2823 column = columnModel.getColumn(i);
2824 if (column.getHeaderValue()==null)
2825 column.setHeaderValue(dataModel.getColumnName(i));
2829 // according to Sun's spec we also have to set the tableHeader's
2830 // column model here
2831 if (tableHeader != null)
2832 tableHeader.setColumnModel(c);
2834 revalidate();
2835 repaint();
2839 * Set the value of the <code>columnSelectionAllowed</code> property.
2841 * @param c The new value of the property
2843 public void setColumnSelectionAllowed(boolean c)
2845 getColumnModel().setColumnSelectionAllowed(c);
2846 repaint();
2850 * <p>Set the value of the {@link #selectionModel} property.</p>
2852 * <p>Unregister <code>this</code> as a {@link ListSelectionListener}
2853 * from previous {@link #selectionModel} and register it with new
2854 * parameter <code>s</code>.</p>
2856 * @param s The new value of the selectionModel property
2858 public void setSelectionModel(ListSelectionModel s)
2860 if (s == null)
2861 throw new IllegalArgumentException();
2862 ListSelectionModel tmp = selectionModel;
2863 if (tmp != null)
2864 tmp.removeListSelectionListener(this);
2865 if (s != null)
2866 s.addListSelectionListener(this);
2867 selectionModel = s;
2871 * Set the value of the <code>selectionMode</code> property by
2872 * delegation to the {@link #selectionModel} field. The same selection
2873 * mode is set for row and column selection models.
2875 * @param s The new value of the property
2877 public void setSelectionMode(int s)
2879 selectionModel.setSelectionMode(s);
2880 columnModel.getSelectionModel().setSelectionMode(s);
2882 repaint();
2886 * <p>Set the value of the {@link #cellEditor} property.</p>
2888 * <p>Unregister <code>this</code> as a {@link CellEditorListener} from
2889 * previous {@link #cellEditor} and register it with new parameter
2890 * <code>c</code>.</p>
2892 * @param c The new value of the cellEditor property
2894 public void setCellEditor(TableCellEditor c)
2896 TableCellEditor tmp = cellEditor;
2897 if (tmp != null)
2898 tmp.removeCellEditorListener(this);
2899 if (c != null)
2900 c.addCellEditorListener(this);
2901 cellEditor = c;
2905 * Set the value of the {@link #dragEnabled} property.
2907 * @param d The new value of the dragEnabled property
2909 public void setDragEnabled(boolean d)
2911 dragEnabled = d;
2915 * Set the value of the {@link #gridColor} property.
2917 * @param g The new value of the gridColor property
2919 public void setGridColor(Color g)
2921 gridColor = g;
2922 repaint();
2926 * Set the value of the <code>intercellSpacing</code> property.
2928 * @param i The new value of the intercellSpacing property
2930 public void setIntercellSpacing(Dimension i)
2932 rowMargin = i.height;
2933 columnModel.setColumnMargin(i.width);
2934 repaint();
2938 * Set the value of the {@link #preferredViewportSize} property.
2940 * @param p The new value of the preferredViewportSize property
2942 public void setPreferredScrollableViewportSize(Dimension p)
2944 preferredViewportSize = p;
2945 revalidate();
2946 repaint();
2950 * <p>Set the value of the {@link #selectionBackground} property.</p>
2952 * <p>Fire a PropertyChangeEvent with name {@link
2953 * #SELECTION_BACKGROUND_CHANGED_PROPERTY} to registered listeners, if
2954 * selectionBackground changed.</p>
2956 * @param s The new value of the selectionBackground property
2958 public void setSelectionBackground(Color s)
2960 Color tmp = selectionBackground;
2961 selectionBackground = s;
2962 if (((tmp == null && s != null)
2963 || (s == null && tmp != null)
2964 || (tmp != null && s != null && !tmp.equals(s))))
2965 firePropertyChange(SELECTION_BACKGROUND_CHANGED_PROPERTY, tmp, s);
2966 repaint();
2970 * <p>Set the value of the {@link #selectionForeground} property.</p>
2972 * <p>Fire a PropertyChangeEvent with name {@link
2973 * #SELECTION_FOREGROUND_CHANGED_PROPERTY} to registered listeners, if
2974 * selectionForeground changed.</p>
2976 * @param s The new value of the selectionForeground property
2978 public void setSelectionForeground(Color s)
2980 Color tmp = selectionForeground;
2981 selectionForeground = s;
2982 if (((tmp == null && s != null)
2983 || (s == null && tmp != null)
2984 || (tmp != null && s != null && !tmp.equals(s))))
2985 firePropertyChange(SELECTION_FOREGROUND_CHANGED_PROPERTY, tmp, s);
2986 repaint();
2990 * Set the value of the <code>showGrid</code> property.
2992 * @param s The new value of the showGrid property
2994 public void setShowGrid(boolean s)
2996 setShowVerticalLines(s);
2997 setShowHorizontalLines(s);
3001 * Set the value of the {@link #showHorizontalLines} property.
3003 * @param s The new value of the showHorizontalLines property
3005 public void setShowHorizontalLines(boolean s)
3007 showHorizontalLines = s;
3008 repaint();
3012 * Set the value of the {@link #showVerticalLines} property.
3014 * @param s The new value of the showVerticalLines property
3016 public void setShowVerticalLines(boolean s)
3018 showVerticalLines = s;
3019 repaint();
3023 * Set the value of the {@link #tableHeader} property.
3025 * @param t The new value of the tableHeader property
3027 public void setTableHeader(JTableHeader t)
3029 if (tableHeader != null)
3030 tableHeader.setTable(null);
3031 tableHeader = t;
3032 if (tableHeader != null)
3033 tableHeader.setTable(this);
3034 revalidate();
3035 repaint();
3038 protected void configureEnclosingScrollPane()
3040 JScrollPane jsp = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, this);
3041 if (jsp != null && tableHeader != null)
3043 jsp.setColumnHeaderView(tableHeader);
3047 protected void unconfigureEnclosingScrollPane()
3049 JScrollPane jsp = (JScrollPane) SwingUtilities.getAncestorOfClass(JScrollPane.class, this);
3050 if (jsp != null)
3052 jsp.setColumnHeaderView(null);
3057 public void addNotify()
3059 super.addNotify();
3060 configureEnclosingScrollPane();
3063 public void removeNotify()
3065 super.addNotify();
3066 unconfigureEnclosingScrollPane();
3071 * This distributes the superfluous width in a table evenly on its columns.
3073 * The implementation used here is different to that one described in
3074 * the JavaDocs. It is much simpler, and seems to work very well.
3076 * TODO: correctly implement the algorithm described in the JavaDoc
3078 private void distributeSpill(TableColumn[] cols, int spill)
3080 int average = spill / cols.length;
3081 for (int i = 0; i < cols.length; i++)
3083 if (cols[i] != null)
3084 cols[i].setWidth(cols[i].getPreferredWidth() + average);
3089 * This distributes the superfluous width in a table, setting the width of the
3090 * column being resized strictly to its preferred width.
3092 private void distributeSpillResizing(TableColumn[] cols, int spill,
3093 TableColumn resizeIt)
3095 int average = 0;
3096 if (cols.length != 1)
3097 average = spill / (cols.length-1);
3098 for (int i = 0; i < cols.length; i++)
3100 if (cols[i] != null && !cols[i].equals(resizeIt))
3101 cols[i].setWidth(cols[i].getPreferredWidth() + average);
3103 resizeIt.setWidth(resizeIt.getPreferredWidth());
3107 * Set the widths of all columns, taking they preferred widths into
3108 * consideration. The excess space, if any, will be distrubuted between
3109 * all columns. This method also handles special cases when one of the
3110 * collumns is currently being resized.
3112 * @see TableColumn#setPreferredWidth(int)
3114 public void doLayout()
3116 TableColumn resizingColumn = null;
3118 int ncols = getColumnCount();
3119 if (ncols < 1)
3120 return;
3122 int prefSum = 0;
3123 int rCol = -1;
3125 if (tableHeader != null)
3126 resizingColumn = tableHeader.getResizingColumn();
3128 for (int i = 0; i < ncols; ++i)
3130 TableColumn col = columnModel.getColumn(i);
3131 int p = col.getPreferredWidth();
3132 prefSum += p;
3133 if (resizingColumn == col)
3134 rCol = i;
3137 int spill = getWidth() - prefSum;
3139 if (resizingColumn != null)
3141 TableColumn col;
3142 TableColumn [] cols;
3144 switch (getAutoResizeMode())
3146 case AUTO_RESIZE_LAST_COLUMN:
3147 col = columnModel.getColumn(ncols-1);
3148 col.setWidth(col.getPreferredWidth() + spill);
3149 break;
3151 case AUTO_RESIZE_NEXT_COLUMN:
3152 col = columnModel.getColumn(ncols-1);
3153 col.setWidth(col.getPreferredWidth() + spill);
3154 break;
3156 case AUTO_RESIZE_ALL_COLUMNS:
3157 cols = new TableColumn[ncols];
3158 for (int i = 0; i < ncols; ++i)
3159 cols[i] = columnModel.getColumn(i);
3160 distributeSpillResizing(cols, spill, resizingColumn);
3161 break;
3163 case AUTO_RESIZE_SUBSEQUENT_COLUMNS:
3165 // Subtract the width of the non-resized columns from the spill.
3166 int w = 0;
3167 int wp = 0;
3168 TableColumn column;
3169 for (int i = 0; i < rCol; i++)
3171 column = columnModel.getColumn(i);
3172 w += column.getWidth();
3173 wp+= column.getPreferredWidth();
3176 // The number of columns right from the column being resized.
3177 int n = ncols-rCol-1;
3178 if (n>0)
3180 // If there are any columns on the right sied to resize.
3181 spill = (getWidth()-w) - (prefSum-wp);
3182 int average = spill / n;
3184 // For all columns right from the column being resized:
3185 for (int i = rCol+1; i < ncols; i++)
3187 column = columnModel.getColumn(i);
3188 column.setWidth(column.getPreferredWidth() + average);
3191 resizingColumn.setWidth(resizingColumn.getPreferredWidth());
3192 break;
3194 case AUTO_RESIZE_OFF:
3195 default:
3196 int prefWidth = resizingColumn.getPreferredWidth();
3197 resizingColumn.setWidth(prefWidth);
3200 else
3202 TableColumn [] cols = new TableColumn[ncols];
3203 for (int i = 0; i < ncols; ++i)
3204 cols[i] = columnModel.getColumn(i);
3205 distributeSpill(cols, spill);
3208 if (editorComp!=null)
3209 moveToCellBeingEdited(editorComp);
3211 // Repaint fixes the invalid view after the first keystroke if the cell
3212 // editing is started immediately after the program start or cell
3213 // resizing.
3214 repaint();
3215 if (tableHeader!=null)
3216 tableHeader.repaint();
3220 * @deprecated Replaced by <code>doLayout()</code>
3222 public void sizeColumnsToFit(boolean lastColumnOnly)
3224 doLayout();
3228 * Obsolete since JDK 1.4. Please use <code>doLayout()</code>.
3230 public void sizeColumnsToFit(int resizingColumn)
3232 doLayout();
3235 public String getUIClassID()
3237 return "TableUI";
3241 * This method returns the table's UI delegate.
3243 * @return The table's UI delegate.
3245 public TableUI getUI()
3247 return (TableUI) ui;
3251 * This method sets the table's UI delegate.
3253 * @param ui The table's UI delegate.
3255 public void setUI(TableUI ui)
3257 super.setUI(ui);
3260 public void updateUI()
3262 setUI((TableUI) UIManager.getUI(this));
3263 revalidate();
3264 repaint();
3268 * Get the class (datatype) of the column. The cells are rendered and edited
3269 * differently, depending from they data type.
3271 * @param column the column (not the model index).
3273 * @return the class, defining data type of that column (String.class for
3274 * String, Boolean.class for boolean and so on).
3276 public Class getColumnClass(int column)
3278 return getModel().getColumnClass(convertColumnIndexToModel(column));
3282 * Get the name of the column. If the column has the column identifier set,
3283 * the return value is the result of the .toString() method call on that
3284 * identifier. If the identifier is not explicitly set, the returned value
3285 * is calculated by
3286 * {@link javax.swing.table.AbstractTableModel#getColumnName(int)}.
3288 * @param column the column
3290 * @return the name of that column.
3292 public String getColumnName(int column)
3294 int modelColumn = columnModel.getColumn(column).getModelIndex();
3295 return dataModel.getColumnName(modelColumn);
3299 * Get the column, currently being edited
3301 * @return the column, currently being edited.
3303 public int getEditingColumn()
3305 return editingColumn;
3309 * Set the column, currently being edited
3311 * @param column the column, currently being edited.
3313 public void setEditingColumn(int column)
3315 editingColumn = column;
3319 * Get the row currently being edited.
3321 * @return the row, currently being edited.
3323 public int getEditingRow()
3325 return editingRow;
3329 * Set the row currently being edited.
3331 * @param row the row, that will be edited
3333 public void setEditingRow(int row)
3335 editingRow = row;
3339 * Get the editor component that is currently editing one of the cells
3341 * @return the editor component or null, if none of the cells is being
3342 * edited.
3344 public Component getEditorComponent()
3346 return editorComp;
3350 * Check if one of the table cells is currently being edited.
3352 * @return true if there is a cell being edited.
3354 public boolean isEditing()
3356 return editorComp != null;
3360 * Set the default editor for the given column class (column data type).
3361 * By default, String is handled by text field and Boolean is handled by
3362 * the check box.
3364 * @param columnClass the column data type
3365 * @param editor the editor that will edit this data type
3367 * @see TableModel#getColumnClass(int)
3369 public void setDefaultEditor(Class columnClass, TableCellEditor editor)
3371 if (editor != null)
3372 defaultEditorsByColumnClass.put(columnClass, editor);
3373 else
3374 defaultEditorsByColumnClass.remove(columnClass);
3377 public void addColumnSelectionInterval(int index0, int index1)
3379 if ((index0 < 0 || index0 > (getColumnCount()-1)
3380 || index1 < 0 || index1 > (getColumnCount()-1)))
3381 throw new IllegalArgumentException("Column index out of range.");
3383 getColumnModel().getSelectionModel().addSelectionInterval(index0, index1);
3386 public void addRowSelectionInterval(int index0, int index1)
3388 if ((index0 < 0 || index0 > (getRowCount()-1)
3389 || index1 < 0 || index1 > (getRowCount()-1)))
3390 throw new IllegalArgumentException("Row index out of range.");
3392 getSelectionModel().addSelectionInterval(index0, index1);
3395 public void setColumnSelectionInterval(int index0, int index1)
3397 if ((index0 < 0 || index0 > (getColumnCount()-1)
3398 || index1 < 0 || index1 > (getColumnCount()-1)))
3399 throw new IllegalArgumentException("Column index out of range.");
3401 getColumnModel().getSelectionModel().setSelectionInterval(index0, index1);
3404 public void setRowSelectionInterval(int index0, int index1)
3406 if ((index0 < 0 || index0 > (getRowCount()-1)
3407 || index1 < 0 || index1 > (getRowCount()-1)))
3408 throw new IllegalArgumentException("Row index out of range.");
3410 getSelectionModel().setSelectionInterval(index0, index1);
3413 public void removeColumnSelectionInterval(int index0, int index1)
3415 if ((index0 < 0 || index0 > (getColumnCount()-1)
3416 || index1 < 0 || index1 > (getColumnCount()-1)))
3417 throw new IllegalArgumentException("Column index out of range.");
3419 getColumnModel().getSelectionModel().removeSelectionInterval(index0, index1);
3422 public void removeRowSelectionInterval(int index0, int index1)
3424 if ((index0 < 0 || index0 > (getRowCount()-1)
3425 || index1 < 0 || index1 > (getRowCount()-1)))
3426 throw new IllegalArgumentException("Row index out of range.");
3428 getSelectionModel().removeSelectionInterval(index0, index1);
3432 * Checks if the given column is selected.
3434 * @param column the column
3436 * @return true if the column is selected (as reported by the selection
3437 * model, associated with the column model), false otherwise.
3439 public boolean isColumnSelected(int column)
3441 return getColumnModel().getSelectionModel().isSelectedIndex(column);
3445 * Checks if the given row is selected.
3447 * @param row the row
3449 * @return true if the row is selected (as reported by the selection model),
3450 * false otherwise.
3452 public boolean isRowSelected(int row)
3454 return getSelectionModel().isSelectedIndex(row);
3458 * Checks if the given cell is selected. The cell is selected if both
3459 * the cell row and the cell column are selected.
3461 * @param row the cell row
3462 * @param column the cell column
3464 * @return true if the cell is selected, false otherwise
3466 public boolean isCellSelected(int row, int column)
3468 return isRowSelected(row) && isColumnSelected(column);
3472 * Select all table.
3474 public void selectAll()
3476 // rowLead and colLead store the current lead selection indices
3477 int rowLead = selectionModel.getLeadSelectionIndex();
3478 int colLead = getColumnModel().getSelectionModel().getLeadSelectionIndex();
3479 // the following calls to setSelectionInterval change the lead selection
3480 // indices
3481 setColumnSelectionInterval(0, getColumnCount() - 1);
3482 setRowSelectionInterval(0, getRowCount() - 1);
3483 // the following addSelectionInterval calls restore the lead selection
3484 // indices to their previous values
3485 addColumnSelectionInterval(colLead,colLead);
3486 addRowSelectionInterval(rowLead, rowLead);
3490 * Get the cell value at the given position.
3492 * @param row the row to get the value
3493 * @param column the actual column number (not the model index)
3494 * to get the value.
3496 * @return the cell value, as returned by model.
3498 public Object getValueAt(int row, int column)
3500 return dataModel.getValueAt(row, convertColumnIndexToModel(column));
3504 * Set value for the cell at the given position. If the cell is not
3505 * editable, this method returns without action. The modified cell is
3506 * repainted.
3508 * @param value the value to set
3509 * @param row the row of the cell being modified
3510 * @param column the column of the cell being modified
3512 public void setValueAt(Object value, int row, int column)
3514 if (!isCellEditable(row, column))
3515 return;
3516 dataModel.setValueAt(value, row, convertColumnIndexToModel(column));
3518 repaint(getCellRect(row, column, true));
3522 * Get table column with the given identified.
3524 * @param identifier the column identifier
3526 * @return the table column with this identifier
3528 * @throws IllegalArgumentException if <code>identifier</code> is
3529 * <code>null</code> or there is no column with that identifier.
3531 * @see TableColumn#setIdentifier(Object)
3533 public TableColumn getColumn(Object identifier)
3535 return columnModel.getColumn(columnModel.getColumnIndex(identifier));
3539 * Returns <code>true</code> if the specified cell is editable, and
3540 * <code>false</code> otherwise.
3542 * @param row the row index.
3543 * @param column the column index.
3545 * @return true if the cell is editable, false otherwise.
3547 public boolean isCellEditable(int row, int column)
3549 return dataModel.isCellEditable(row, convertColumnIndexToModel(column));
3553 * Clears any existing columns from the <code>JTable</code>'s
3554 * {@link TableColumnModel} and creates new columns to match the values in
3555 * the data ({@link TableModel}) used by the table.
3557 * @see #setAutoCreateColumnsFromModel(boolean)
3559 public void createDefaultColumnsFromModel()
3561 assert columnModel != null : "The columnModel must not be null.";
3563 // remove existing columns
3564 int columnIndex = columnModel.getColumnCount() - 1;
3565 while (columnIndex >= 0)
3567 columnModel.removeColumn(columnModel.getColumn(columnIndex));
3568 columnIndex--;
3571 // add new columns to match the TableModel
3572 int columnCount = dataModel.getColumnCount();
3573 for (int c = 0; c < columnCount; c++)
3575 TableColumn column = new TableColumn(c);
3576 column.setIdentifier(dataModel.getColumnName(c));
3577 column.setHeaderValue(dataModel.getColumnName(c));
3578 columnModel.addColumn(column);
3579 column.addPropertyChangeListener(tableColumnPropertyChangeHandler);
3583 public void changeSelection (int rowIndex, int columnIndex, boolean toggle, boolean extend)
3585 if (toggle && extend)
3587 // Leave the selection state as is, but move the anchor
3588 // index to the specified location
3589 selectionModel.setAnchorSelectionIndex(rowIndex);
3590 getColumnModel().getSelectionModel().setAnchorSelectionIndex(columnIndex);
3592 else if (toggle)
3594 // Toggle the state of the specified cell
3595 if (isCellSelected(rowIndex,columnIndex))
3597 selectionModel.removeSelectionInterval(rowIndex,rowIndex);
3598 getColumnModel().getSelectionModel().removeSelectionInterval(columnIndex,columnIndex);
3600 else
3602 selectionModel.addSelectionInterval(rowIndex,rowIndex);
3603 getColumnModel().getSelectionModel().addSelectionInterval(columnIndex,columnIndex);
3606 else if (extend)
3608 // Extend the previous selection from the anchor to the
3609 // specified cell, clearing all other selections
3610 selectionModel.setLeadSelectionIndex(rowIndex);
3611 getColumnModel().getSelectionModel().setLeadSelectionIndex(columnIndex);
3613 else
3615 // Clear the previous selection and ensure the new cell
3616 // is selected
3617 selectionModel.clearSelection();
3618 selectionModel.setSelectionInterval(rowIndex,rowIndex);
3619 getColumnModel().getSelectionModel().clearSelection();
3620 getColumnModel().getSelectionModel().setSelectionInterval(columnIndex, columnIndex);
3627 * Programmatically starts editing the specified cell.
3629 * @param row the row of the cell to edit.
3630 * @param column the column of the cell to edit.
3632 public boolean editCellAt (int row, int column)
3634 // Complete the previous editing session, if still active.
3635 if (isEditing())
3636 editingStopped(new ChangeEvent("editingStopped"));
3638 editingRow = row;
3639 editingColumn = column;
3641 setCellEditor(getCellEditor(row, column));
3642 editorComp = prepareEditor(cellEditor, row, column);
3644 // Remove the previous editor components, if present. Only one
3645 // editor component at time is allowed in the table.
3646 removeAll();
3647 add(editorComp);
3648 moveToCellBeingEdited(editorComp);
3649 scrollRectToVisible(editorComp.getBounds());
3650 editorComp.requestFocusInWindow();
3651 return true;
3655 * Move the given component under the cell being edited.
3656 * The table must be in the editing mode.
3658 * @param component the component to move.
3660 private void moveToCellBeingEdited(Component component)
3662 Rectangle r = getCellRect(editingRow, editingColumn, true);
3663 // Place the text field so that it would not touch the table
3664 // border.
3666 // TODO Figure out while 5 and which constant should here be.
3667 int xOffset = 5;
3668 r.x+=xOffset;
3669 r.y++;
3670 r.width -=xOffset;
3671 r.height --;
3673 // Clone rectangle as getCellRect returns the cached value.
3674 component.setBounds(new Rectangle(r));
3678 * Programmatically starts editing the specified cell.
3680 * @param row the row of the cell to edit.
3681 * @param column the column of the cell to edit.
3683 public boolean editCellAt (int row, int column, EventObject e)
3685 return editCellAt(row, column);
3689 * Discards the editor object.
3691 public void removeEditor()
3693 editingStopped(new ChangeEvent(this));
3697 * Prepares the editor by querying for the value and selection state of the
3698 * cell at (row, column).
3700 * @param editor the TableCellEditor to set up
3701 * @param row the row of the cell to edit
3702 * @param column the column of the cell to edit
3703 * @return the Component being edited
3705 public Component prepareEditor (TableCellEditor editor, int row, int column)
3707 return editor.getTableCellEditorComponent
3708 (this, getValueAt(row, column), isCellSelected(row, column), row, column);
3712 * This revalidates the <code>JTable</code> and queues a repaint.
3714 protected void resizeAndRepaint()
3716 revalidate();
3717 repaint();
3721 * Sets whether cell editors of this table should receive keyboard focus
3722 * when the editor is activated by a keystroke. The default setting is
3723 * <code>false</code> which means that the table should keep the keyboard
3724 * focus until the cell is selected by a mouse click.
3726 * @param value the value to set
3728 * @since 1.4
3730 public void setSurrendersFocusOnKeystroke(boolean value)
3732 // TODO: Implement functionality of this property (in UI impl).
3733 surrendersFocusOnKeystroke = value;
3737 * Returns whether cell editors of this table should receive keyboard focus
3738 * when the editor is activated by a keystroke. The default setting is
3739 * <code>false</code> which means that the table should keep the keyboard
3740 * focus until the cell is selected by a mouse click.
3742 * @return whether cell editors of this table should receive keyboard focus
3743 * when the editor is activated by a keystroke
3745 * @since 1.4
3747 public boolean getSurrendersFocusOnKeystroke()
3749 // TODO: Implement functionality of this property (in UI impl).
3750 return surrendersFocusOnKeystroke;