JDK-4849062 : JTable and JList have incompatible definitions of cellFocus for renderers.
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.4.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_xp
  • CPU: x86
  • Submitted: 2003-04-16
  • Updated: 2003-08-13
  • Resolved: 2003-08-13
Related Reports
Duplicate :  
Relates :  
Description

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) 
======================================================================

Comments
EVALUATION I believe this has all been resolved as part of 4303294. ###@###.### 2003-08-12 This is the same issue as 4759422 which was fixed as part of 4303294. Closing as a duplicate of 4303294. ###@###.### 2003-08-13
12-08-2003