Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4357853

DefaultListSelectionModel.removeIndexInterval() is broken.

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P4 P4
    • None
    • 1.3.0
    • client-libs



      Name: sl110371 Date: 07/31/2000


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

      I submitted this against 1.2, but it vanished without trace. It's
      still in 1.3, so I'm submitting it again.

      DefaultListSelectionModel.removeIndexInterval(int, int) does not fire a
      ListSelectionEvent when it removes selected indices. JTable uses a
      DefaultListSelectionModel to model row selection. This means that when a
      selected row is removed from a JTable's TableModel, no ListSelectionEvent is
      generated to notify listeners of the change in selection.

      The following code demonstrates the problem:

      import java.awt.*;
      import java.awt.event.*;
      import javax.swing.*;
      import javax.swing.event.*;
      import javax.swing.table.*;

      public class ListModelTest extends JFrame
      {
         private JButton deleteButton = new JButton("Delete Row");
         private JLabel rowText = new JLabel("none");
         private JLabel columnText = new JLabel("none");

         private void setupSelectionModels(final ListSelectionModel rowModel, final
      ListSelectionModel columnModel)
         {
            // Listen for changes in the row selection and update our interface in
            // response:

            rowModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
            rowModel.addListSelectionListener(new ListSelectionListener() {
               public void valueChanged(ListSelectionEvent e)
               {
                  if (rowModel.isSelectionEmpty())
                  {
                     //
                     // Bug:
                     //
                     // Even though the row selection vanishes after we hit the
                     // delete button, we never arrive here.
                     //

                     rowText.setText("none");
                     deleteButton.setEnabled(false);
                  }
                  else
                  {
                     rowText.setText("" + rowModel.getMinSelectionIndex());
                     deleteButton.setEnabled(true);
                  }
               }
            });

            // Listen for changes in the column selection:

            columnModel.addListSelectionListener(new ListSelectionListener() {
               public void valueChanged(ListSelectionEvent e)
               {
                  if (columnModel.isSelectionEmpty())
                  {
                     //
                     // We never arrive here either (but probably not a bug).
                     //

                     columnText.setText("none");
                  }
                  else
                  {
                     char minColumn = (char) ('A' +
                        columnModel.getMinSelectionIndex());
                     char maxColumn = (char) ('A' +
                        columnModel.getMaxSelectionIndex());
                     String text = "" + minColumn;
                     if (minColumn != maxColumn)
                        text += "..." + maxColumn;
                     columnText.setText(text);
                  }
               }
            });
         }

         /**
          * Setup <i>deleteButton</i> to delete the the minimum selected row
          * of <i>table</i>
          */

         private void setupDeleteButton(JButton deleteButton, final JTable table)
         {
            deleteButton.setEnabled(false);

            deleteButton.addActionListener(new ActionListener() {
               public void actionPerformed(ActionEvent e)
               {
                  int row = table.getSelectionModel().getMinSelectionIndex();
                  if (row == -1)
                  {
                     // We shouldn't ever arrive here because our row selection
                     // listener disables the delete button when there is no
                     // selection.

                     System.out.println("Arrrrgh! No row to delete!");
                  }
                  else
                  {
                     // This is where the trouble starts. Removing the selected row
                     // changes the selection, but it doesn't notify the selection
                     // listeners.

                     ((DefaultTableModel) table.getModel()).removeRow(row);
                  }
               }
            });
         }

         /**
          * Interface.
          */

         public ListModelTest()
         {
            addWindowListener(new WindowAdapter() {
               public void windowClosing(WindowEvent e)
               {
                  System.exit(0);
               }
            });

            JLabel columnLabel = new JLabel("Selected Column: ");
            JLabel rowLabel = new JLabel("Selected Row: ");
            rowLabel.setPreferredSize(columnLabel.getPreferredSize());
            JTable table = new JTable(100, 5);
            table.setCellSelectionEnabled(true);
            JScrollPane tablePane = new JScrollPane(table);

      tablePane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
            setupSelectionModels(table.getSelectionModel(),
      table.getColumnModel().getSelectionModel());
            setupDeleteButton(deleteButton, table);

            // layout:

            Box b1 = Box.createVerticalBox();
            Box b2 = Box.createHorizontalBox();
            Box b3 = Box.createHorizontalBox();
            Box b4 = Box.createHorizontalBox();

            getContentPane().add(tablePane);
            getContentPane().add(b1, BorderLayout.SOUTH);
            b1.add(b2);
            b1.add(b3);
            b1.add(b4);
            b2.add(rowLabel);
            b2.add(Box.createHorizontalStrut(5));
            b2.add(rowText);
            b2.add(Box.createHorizontalGlue());
            b3.add(columnLabel);
            b3.add(Box.createHorizontalStrut(5));
            b3.add(columnText);
            b3.add(Box.createHorizontalGlue());
            b4.add(Box.createHorizontalGlue());
            b4.add(deleteButton);
            setBounds(new Rectangle(20, 20, 300, 200));
         }

         /**
          * Go.
          */

         public static void main(String[] argv)
         {
            new ListModelTest().show();
         }
      }

      The offending code is in DefaultListSelectionModel:

          /**
           * Remove the indices in the interval index0,index1 (inclusive) from
           * the selection model. This is typically called to sync the selection
           * model width a corresponding change in the data model. Note
           * that (as always) index0 need not be <= index1.
           */
         public void removeIndexInterval(int index0, int index1)
         {
            int rmMinIndex = Math.min(index0, index1);
            int rmMaxIndex = Math.max(index0, index1);
            int gapLength = (rmMaxIndex - rmMinIndex) + 1;

            /* Shift the entire bitset to the left to close the index0, index1
             * gap.
             */
            for(int i = rmMinIndex; i <= maxIndex; i++) {
               setState(i, value.get(i + gapLength));
            }

            // Woops... just stomped on part of the selection and didn't
            // notify anyone.
         }

      This _is_ a bug. DefaultListSelectionModel is incomplete in the formal
      sense: It is impossible to track the state of a DefaultListSelectionModel
      by observation.
      (Review ID: 107799)
      ======================================================================

            pmilnesunw Philip Milne (Inactive)
            duke J. Duke
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: