JDK-6195469 : REGRESSION: Multiple interval selection is lost in JTable if mouse is dragged
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 5.0,5.0u2,5.0u3
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • OS: linux,windows_2000,windows_xp
  • CPU: x86
  • Submitted: 2004-11-15
  • Updated: 2017-05-16
  • Resolved: 2005-08-31
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other JDK 6
5.0u6Fixed 6 b50Fixed
Related Reports
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Duplicate :  
Description
FULL PRODUCT VERSION :
java version "1.5.0-rc"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-rc-b63)
Java HotSpot(TM) Client VM (build 1.5.0-rc-b63, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows 2000 [Version 5.00.2195]

EXTRA RELEVANT SYSTEM CONFIGURATION :
Not any

A DESCRIPTION OF THE PROBLEM :
In JTable, when multiple interval selection mode is used users can select multiple rows. However, if a user drags the mouse over a row, then the previous selections are lost.

I verified that this does not happen with the following Java version

java version "1.4.2_03"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_03-b02)
Java HotSpot(TM) Client VM (build 1.4.2_03-b02, mixed mode)


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create a JTable with MULTIPLE_INTERVAL_SELECTION mode and
populate it with some date.

2. Select first two rows with CTRL key pressed.

3. Move mouse to an unselected row to select that row

4. Click on the that unselected row to make is selected.

5. Without releasing the CTRL key, drag the mouse  a little without going out of the row boundaries over that last row.


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
All the previous selections and the last selected row should both stay selected.
ACTUAL -
The previous selection is lost and only the last row becomes selected.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
No error messages.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
/*
 * SimpleTableDemo.java is a 1.4 application that requires no other files.
 */

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public class SimpleTableDemo extends JPanel {
    private boolean DEBUG = false;

    public SimpleTableDemo() {
        super(new GridLayout(1,0));

        String[] columnNames = {"First Name",
                                "Last Name",
                                "Sport",
                                "# of Years",
                                "Vegetarian"};

        Object[][] data = {
            {"Mary", "Campione",
             "Snowboarding", new Integer(5), new Boolean(false)},
            {"Alison", "Huml",
             "Rowing", new Integer(3), new Boolean(true)},
            {"Kathy", "Walrath",
             "Knitting", new Integer(2), new Boolean(false)},
            {"Sharon", "Zakhour",
             "Speed reading", new Integer(20), new Boolean(true)},
            {"Philip", "Milne",
             "Pool", new Integer(10), new Boolean(false)}
        };

        final JTable table = new JTable(data, columnNames);
        table.setPreferredScrollableViewportSize(new Dimension(500, 70));

        if (DEBUG) {
            table.addMouseListener(new MouseAdapter() {
                public void mouseClicked(MouseEvent e) {
                    printDebugData(table);
                }
            });
        }

        //Create the scroll pane and add the table to it.
        JScrollPane scrollPane = new JScrollPane(table);

        //Add the scroll pane to this panel.
        add(scrollPane);
    }

    private void printDebugData(JTable table) {
        int numRows = table.getRowCount();
        int numCols = table.getColumnCount();
        javax.swing.table.TableModel model = table.getModel();

        System.out.println("Value of data: ");
        for (int i=0; i < numRows; i++) {
            System.out.print("    row " + i + ":");
            for (int j=0; j < numCols; j++) {
                System.out.print("  " + model.getValueAt(i, j));
            }
            System.out.println();
        }
        System.out.println("--------------------------");
    }

    /**
     * Create the GUI and show it.  For thread safety,
     * this method should be invoked from the
     * event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Make sure we have nice window decorations.
        JFrame.setDefaultLookAndFeelDecorated(true);

        //Create and set up the window.
        JFrame frame = new JFrame("SimpleTableDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        SimpleTableDemo newContentPane = new SimpleTableDemo();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}

---------- END SOURCE ----------

Release Regression From : 1.4.2
The above release value was the last known release where this 
bug was known to work. Since then there has been a regression.
###@###.### 2004-11-15 20:17:45 GMT

Comments
WORK AROUND A temporary work-around is available. It should be removed once this bug is fixed as it's suitability has NOT been tested against fixed releases. Use this subclass of JTable. Note: This is for the MetalLookAndFeel. If using other look and feels, the inner FixedTableUI subclass will have to extend the TableUI subclass for that look and feel. import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.table.*; import javax.swing.event.*; import javax.swing.plaf.basic.*; public class FixedTable extends JTable { private boolean isControlDownInDrag; public FixedTable(TableModel model) { super(model); setUI(new FixedTableUI()); } private class FixedTableUI extends BasicTableUI { private MouseInputHandler handler = new MouseInputHandler() { public void mouseDragged(MouseEvent e) { if (e.isControlDown()) { isControlDownInDrag = true; } super.mouseDragged(e); } public void mousePressed(MouseEvent e) { isControlDownInDrag = false; super.mousePressed(e); } public void mouseReleased(MouseEvent e) { isControlDownInDrag = false; super.mouseReleased(e); } }; protected MouseInputListener createMouseInputListener() { return handler; } } public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) { if (isControlDownInDrag) { ListSelectionModel rsm = getSelectionModel(); ListSelectionModel csm = getColumnModel().getSelectionModel(); int anchorRow = rsm.getAnchorSelectionIndex(); int anchorCol = csm.getAnchorSelectionIndex(); boolean anchorSelected = isCellSelected(anchorRow, anchorCol); if (anchorSelected) { rsm.addSelectionInterval(anchorRow, rowIndex); csm.addSelectionInterval(anchorCol, columnIndex); } else { rsm.removeSelectionInterval(anchorRow, rowIndex); csm.removeSelectionInterval(anchorCol, columnIndex); } if (getAutoscrolls()) { Rectangle cellRect = getCellRect(rowIndex, columnIndex, false); if (cellRect != null) { scrollRectToVisible(cellRect); } } } else { super.changeSelection(rowIndex, columnIndex, toggle, extend); } } }
12-08-2005

EVALUATION BasicTableUI's mouseDragged handler always passes "false" as the toggle parameter when it calls changeSelection on the JTable. As such, JTable always clears the previous selections. By passing the value of isControlDown() instead, changeSelection can do the right thing for control. However, an extra change is needed in changeSelection(). Currently for the true/true case (which mouseDragged with control calls), there is logic that ALWAYS selects the cell being dragged over. This ruins the ctrl-drag-unselect case. Since this logic was specifically meant for Windows JFileChooser, it will be special-cased for JFileChooser.
09-08-2005

EVALUATION Confirmed - this is a bug. ###@###.### 2005-07-20 17:45:08 GMT
20-07-2005