FULL PRODUCT VERSION :
java version "1.5.0_01"
A DESCRIPTION OF THE PROBLEM :
As stated in MouseEvent.isPopupTrigger:
Note: Popup menus are triggered differently on different systems. Therefore, isPopupTrigger should be checked in both mousePressed and mouseReleased for proper cross-platform functionality.
BasicTableUI however does not check for isPopupTrigger() is either. On systems where BUTTON2 is not the popup trigger this causes selection to be modified before showing the popup. For instance on Mac systems where Ctrl+BUTTON1 is used for the popup trigger.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run test case provided in Mac L&F. This will not happen in other L&F, but is a Swing issue! This issue is even noted in the MouseEvent.isPopupTrigger as mentioned above.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Selection is not lost/changed when a popup is triggered.
ACTUAL -
Selection changes before the popup is shown due to the mouse event handler in BasicTableUI not checking for isPopupTrigger.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.awt.*;
import java.awt.event.*;
import java.lang.reflect.*;
import javax.swing.*;
public class TableTests {
private JFrame _frame = new JFrame();
private JTable _table;
private JPopupMenu _popup;
public TableTests() {
_table = new JTable(new String[][] { { "Row 0" }, { "Row 1" }, { "Row 2" }, { "Row 3" }, { "Row 4" }, { "Row 5" } }, new String[] { "Column 1" } );
_table.getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
_popup = new JPopupMenu();
_popup.add(new JMenuItem("Popup Menu Item"));
_table.addMouseListener(new PopupHandler());
_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
_frame.getContentPane().add(_table);
_frame.pack();
_frame.setVisible(true);
}
/**
* Simple popup handler used for test3813244.
**/
protected class PopupHandler extends MouseAdapter {
public void mousePressed(MouseEvent ev) {
maybeShowPopup(ev);
}
public void mouseReleased(MouseEvent ev) {
maybeShowPopup(ev);
}
protected void maybeShowPopup(MouseEvent ev) {
if (ev.isPopupTrigger()) {
_popup.show(ev.getComponent(), ev.getX(), ev.getY());
}
}
}
public static void main(String args[]) {
new TableTests();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Difficult as with the new Handler class a lot of state is kept causing subclasses to instead copy and paste the code rather than subclass. The method shouldIgnore() needs to be modified, but is used by a multitude of functions in the Handler class which in turn may access more private fields.
Patch to fix this bug follows:
RCS file: /cvs/repository/java/jdk1_4/src/share/classes/javax/swing/plaf/basic/BasicTableUI.java,v
retrieving revision 1.1.1.5
diff -c -r1.1.1.5 BasicTableUI.java
*** BasicTableUI.java 2004/09/08 22:44:29 1.1.1.5
--- BasicTableUI.java 2005/02/22 20:02:11
***************
*** 876,882 ****
}
private boolean shouldIgnore(MouseEvent e) {
! return e.isConsumed() || (!(SwingUtilities.isLeftMouseButton(e) &&
table.isEnabled()));
}
--- 876,882 ----
}
private boolean shouldIgnore(MouseEvent e) {
! return e.isConsumed() || e.isPopupTrigger() || (!(SwingUtilities.isLeftMouseButton(e) &&
table.isEnabled()));
}
###@###.### 2005-2-22 20:28:42 GMT