Name: jk109818 Date: 04/15/2003
FULL PRODUCT VERSION :
java version "1.4.1_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-b01)
Java HotSpot(TM) Client VM (build 1.4.1_01-b01, mixed mode)
FULL OS VERSION :
All (code in JTable and JList).
A DESCRIPTION OF THE PROBLEM :
When preparing the renderer, JTable uses the list selection anchor to determine cellfocus, viz JTable.prepareRenderer
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Object value = getValueAt(row, column);
boolean isSelected = isCellSelected(row, column);
boolean rowIsAnchor = (selectionModel.getAnchorSelectionIndex() == row);
boolean colIsAnchor =
(columnModel.getSelectionModel().getAnchorSelectionIndex() == column);
boolean hasFocus = (rowIsAnchor && colIsAnchor) && isFocusOwner();
return renderer.getTableCellRendererComponent(this, value,
isSelected, hasFocus,
row, column);
}
JList uses list selection lead - ala BasicListUI.paintCell
protected void paintCell(
Graphics g,
int row,
Rectangle rowBounds,
ListCellRenderer cellRenderer,
ListModel dataModel,
ListSelectionModel selModel,
int leadIndex)
{
Object value = dataModel.getElementAt(row);
boolean cellHasFocus = list.hasFocus() && (row == leadIndex);
boolean isSelected = selModel.isSelectedIndex(row);
Component rendererComponent =
cellRenderer.getListCellRendererComponent(list, value, row, isSelected, cellHasFocus);
int cx = rowBounds.x;
int cy = rowBounds.y;
int cw = rowBounds.width;
int ch = rowBounds.height;
rendererPane.paintComponent(g, rendererComponent, list, cx, cy, cw, ch, true);
}
This is causing some problems when we switch from a list to a table sharing the same selection model. FWIW - the list highlights focus more intuitively.
--- SOURCE CODE BEGIN ---
import java.awt.*;
import java.lang.reflect.*;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;
import junit.framework.*;
/**
* Test to show that JList and JTable have different definitions of the focus cell.
* JList uses the leadSelectionIndex, JTable the anchorSelectionIndex.
*
* Given that the lead is the place that the user just clicked - this should have
* focus.
*/
public class SwingRenderersBugTest extends TestCase {
SortedSet listCellTexts = new TreeSet();
SortedSet tableCellTexts = new TreeSet();
public void test() throws InterruptedException, InvocationTargetException {
ListSelectionModel selectionModel = new DefaultListSelectionModel();
JList list = new JList(new Object[5]);
list.setCellRenderer(new CellRenderer());
list.setSelectionModel(selectionModel);
JTable table = new JTable(5, 1);
table.getColumnModel().getColumn(0).setCellRenderer(new CellRenderer());
table.setSelectionModel(selectionModel);
selectionModel.setAnchorSelectionIndex(1);
selectionModel.setLeadSelectionIndex(3);
selectionModel.setSelectionInterval(1, 3);
JFrame frame1 = mountComponent(list);
listCellTexts.clear();
frame1.show();
emptyEventQueue();
assertEquals(Arrays.asList(new String[] {
"row = 0 selected = false focus = false",
"row = 1 selected = true focus = false",
"row = 2 selected = true focus = false",
"row = 3 selected = true focus = true", // 3 is lead selection hence focus
"row = 4 selected = false focus = false",
}), new ArrayList(listCellTexts));
JFrame frame2 = mountComponent(table);
tableCellTexts.clear();
frame2.show();
emptyEventQueue();
assertEquals(Arrays.asList(new String[] {
"row = 0 selected = false focus = false",
"row = 1 selected = true focus = true", // 1 is anchor selection - this has focus
"row = 2 selected = true focus = false",
"row = 3 selected = true focus = false", // but it should be 3 to match the list
"row = 4 selected = false focus = false",
}), new ArrayList(tableCellTexts));
assertEquals(new ArrayList(listCellTexts), new ArrayList(tableCellTexts));
// this fails as they are different
}
private class CellRenderer extends DefaultListCellRenderer
implements TableCellRenderer {
public Component getListCellRendererComponent(
JList list,
Object value,
int index,
boolean isSelected,
boolean cellHasFocus) {
listCellTexts.add(
"row = " + index +
" selected = " + isSelected +
" focus = " + cellHasFocus);
return this;
}
public Component getTableCellRendererComponent(
JTable table,
Object value,
boolean isSelected,
boolean hasFocus,
int row,
int column) {
tableCellTexts.add(
"row = " + row +
" selected = " + isSelected +
" focus = " + hasFocus);
return this;
}
} // CellRenderer
private JFrame mountComponent(Component list) {
JFrame frame = new JFrame();
frame.getContentPane().add(list, BorderLayout.NORTH);
frame.pack();
return frame;
}
private void emptyEventQueue()
throws InterruptedException, InvocationTargetException {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
}
});
}
}
--- SOURCE CODE END ---
REPRODUCIBILITY :
This bug can be reproduced always.
(Review ID: 182023)
======================================================================