-
Bug
-
Resolution: Cannot Reproduce
-
P4
-
8u60
-
x86
-
os_x
FULL PRODUCT VERSION :
Java SE 1.8.0.60-b27
ADDITIONAL OS VERSION INFORMATION :
OS X El Capitan (version 10.11)
A DESCRIPTION OF THE PROBLEM :
The provided sample app is a small working example of how creating a JDialog or message box from within the importData() override of the TransferHandler.java class will result in a JDialog that does not accept mouse clicks (to click the OK button).
This issue has very practical implications in that one often wants to do some error handling of drag/drop operations, but in this case one isn't able to drive the JDialog via mouse.
Using a keyboard to tab to the OK button and then using the Space key to action the button work fine without issue, and that's the only way that I'm able to get past the dialog.
Note that this seems to only affect the newest OS X El Caption (10.11) release. The same application works perfectly fine on Windows and on the older OS X Yosemite.
From additional tests, anything contained within the JDialog (such as text boxes, etc) will also not accept mouse clicks but works fine via keyboard clicks. It seems as if the drag/drop action is blocking mouse events from the JDialog, but adding a MouseListener to the JDialog and clicking the dialog will hit the MouseClicked/Released methods(), even though nothing really happs after that click...
PS - The sample code is basically the Oracle DropDemo app from https://docs.oracle.com/javase/tutorial/uiswing/examples/zipfiles/dnd-ChooseDropActionDemoProject.zip. The only difference is the added line of code at line 68 of src\dnd\ListTransferHandler.java that reads:
JOptionPane.showMessageDialog(null, "CAN YOU CLICK ME AWAT?", "Try to click me away...", JOptionPane.INFORMATION_MESSAGE);
ADDITIONAL REGRESSION INFORMATION:
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1) Launch the attached app (java -cp dnd-DropDemoProject/dist/DropDemo.jar dnd.DropDemo
2) Drag drop "List Item 0" under "List Item 2"
3) Try to click the OK button on the message box that appears. It will work on all OS (I tried Windows and older Mac OS) but will fail on OS X El Capitan (v 10.11)
4) Use the Tab key and then the Space bar key to click the OK button on the message to close it.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The message box (and JDialog in general) should be responsive to the mouse clicks on the OK button.
ACTUAL -
The message box/JDialog is not responsive to the mouse click.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
/*
* Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle or the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package dnd;
/*
* DropDemo.java requires the following file:
* ListTransferHandler.java
*/
import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
public class DropDemo extends JPanel implements ActionListener {
private JComboBox dropCombo;
private JList list;
public DropDemo() {
super(new GridLayout(2,1));
add(createArea());
add(createList());
}
private JPanel createList() {
DefaultListModel listModel = new DefaultListModel();
for (int i = 0; i < 10; i++) {
listModel.addElement("List Item " + i);
}
list = new JList(listModel);
list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
JScrollPane scrollPane = new JScrollPane(list);
scrollPane.setPreferredSize(new Dimension(400,100));
list.setDragEnabled(true);
list.setTransferHandler(new ListTransferHandler());
dropCombo = new JComboBox(new String[] {"USE_SELECTION", "ON", "INSERT", "ON_OR_INSERT"});
dropCombo.addActionListener(this);
JPanel dropPanel = new JPanel();
dropPanel.add(new JLabel("List Drop Mode:"));
dropPanel.add(dropCombo);
JPanel panel = new JPanel(new BorderLayout());
panel.add(scrollPane, BorderLayout.CENTER);
panel.add(dropPanel, BorderLayout.SOUTH);
panel.setBorder(BorderFactory.createTitledBorder("List"));
return panel;
}
private JPanel createArea() {
String text = "Drag from or drop into this area.\nThe default action is MOVE;\nhold the Control key to COPY.";
JTextArea area = new JTextArea();
area.setText(text);
area.setDragEnabled(true);
JScrollPane scrollPane = new JScrollPane(area);
scrollPane.setPreferredSize(new Dimension(400,100));
JPanel panel = new JPanel(new BorderLayout());
panel.add(scrollPane, BorderLayout.CENTER);
panel.setBorder(BorderFactory.createTitledBorder("Text Area"));
return panel;
}
public void actionPerformed(ActionEvent ae) {
Object val = dropCombo.getSelectedItem();
if (val == "USE_SELECTION") {
list.setDropMode(DropMode.USE_SELECTION);
} else if (val == "ON") {
list.setDropMode(DropMode.ON);
} else if (val == "INSERT") {
list.setDropMode(DropMode.INSERT);
} else if (val == "ON_OR_INSERT") {
list.setDropMode(DropMode.ON_OR_INSERT);
}
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("DropDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
JComponent newContentPane = new DropDemo();
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() {
//Turn off metal's use of bold fonts
UIManager.put("swing.boldMetal", Boolean.FALSE);
createAndShowGUI();
}
});
}
}
/*
* Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle or the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
class ListTransferHandler extends TransferHandler {
private int[] indices = null;
private int addIndex = -1; //Location where items were added
private int addCount = 0; //Number of items added.
public boolean canImport(TransferHandler.TransferSupport info) {
// Check for String flavor
if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
return false;
}
return true;
}
protected Transferable createTransferable(JComponent c) {
return new StringSelection(exportString(c));
}
public int getSourceActions(JComponent c) {
return TransferHandler.COPY_OR_MOVE;
}
public boolean importData(TransferHandler.TransferSupport info) {
if (!info.isDrop()) {
return false;
}
//This dialog is responsive to mouse clicks everywhere except in MAC OS X El Capitan
JOptionPane.showMessageDialog(null, "CAN YOU CLICK ME AWAT?", "Try to click me away...", JOptionPane.INFORMATION_MESSAGE);
JList list = (JList)info.getComponent();
DefaultListModel listModel = (DefaultListModel)list.getModel();
JList.DropLocation dl = (JList.DropLocation)info.getDropLocation();
int index = dl.getIndex();
boolean insert = dl.isInsert();
// Get the string that is being dropped.
Transferable t = info.getTransferable();
String data;
try {
data = (String)t.getTransferData(DataFlavor.stringFlavor);
}
catch (Exception e) { return false; }
// Perform the actual import.
if (insert) {
listModel.add(index, data);
} else {
listModel.set(index, data);
}
return true;
}
protected void exportDone(JComponent c, Transferable data, int action) {
cleanup(c, action == TransferHandler.MOVE);
}
//Bundle up the selected items in the list
//as a single string, for export.
protected String exportString(JComponent c) {
JList list = (JList)c;
indices = list.getSelectedIndices();
Object[] values = list.getSelectedValues();
StringBuffer buff = new StringBuffer();
for (int i = 0; i < values.length; i++) {
Object val = values[i];
buff.append(val == null ? "" : val.toString());
if (i != values.length - 1) {
buff.append("\n");
}
}
return buff.toString();
}
//Take the incoming string and wherever there is a
//newline, break it into a separate item in the list.
protected void importString(JComponent c, String str) {
JList target = (JList)c;
DefaultListModel listModel = (DefaultListModel)target.getModel();
int index = target.getSelectedIndex();
//Prevent the user from dropping data back on itself.
//For example, if the user is moving items #4,#5,#6 and #7 and
//attempts to insert the items after item #5, this would
//be problematic when removing the original items.
//So this is not allowed.
if (indices != null && index >= indices[0] - 1 &&
index <= indices[indices.length - 1]) {
indices = null;
return;
}
int max = listModel.getSize();
if (index < 0) {
index = max;
} else {
index++;
if (index > max) {
index = max;
}
}
addIndex = index;
String[] values = str.split("\n");
addCount = values.length;
for (int i = 0; i < values.length; i++) {
listModel.add(index++, values[i]);
}
}
//If the remove argument is true, the drop has been
//successful and it's time to remove the selected items
//from the list. If the remove argument is false, it
//was a Copy operation and the original list is left
//intact.
protected void cleanup(JComponent c, boolean remove) {
if (remove && indices != null) {
JList source = (JList)c;
DefaultListModel model = (DefaultListModel)source.getModel();
//If we are moving items around in the same list, we
//need to adjust the indices accordingly, since those
//after the insertion point have moved.
if (addCount > 0) {
for (int i = 0; i < indices.length; i++) {
if (indices[i] > addIndex) {
indices[i] += addCount;
}
}
}
for (int i = indices.length - 1; i >= 0; i--) {
model.remove(indices[i]);
}
}
indices = null;
addCount = 0;
addIndex = -1;
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Use the keyboard. Not pretty and our clients wouldn't really be happy. It's also not a viable workaroud if you don't know to use the keyboard, you will get stuck on the modal JDialog indefinitely.
Java SE 1.8.0.60-b27
ADDITIONAL OS VERSION INFORMATION :
OS X El Capitan (version 10.11)
A DESCRIPTION OF THE PROBLEM :
The provided sample app is a small working example of how creating a JDialog or message box from within the importData() override of the TransferHandler.java class will result in a JDialog that does not accept mouse clicks (to click the OK button).
This issue has very practical implications in that one often wants to do some error handling of drag/drop operations, but in this case one isn't able to drive the JDialog via mouse.
Using a keyboard to tab to the OK button and then using the Space key to action the button work fine without issue, and that's the only way that I'm able to get past the dialog.
Note that this seems to only affect the newest OS X El Caption (10.11) release. The same application works perfectly fine on Windows and on the older OS X Yosemite.
From additional tests, anything contained within the JDialog (such as text boxes, etc) will also not accept mouse clicks but works fine via keyboard clicks. It seems as if the drag/drop action is blocking mouse events from the JDialog, but adding a MouseListener to the JDialog and clicking the dialog will hit the MouseClicked/Released methods(), even though nothing really happs after that click...
PS - The sample code is basically the Oracle DropDemo app from https://docs.oracle.com/javase/tutorial/uiswing/examples/zipfiles/dnd-ChooseDropActionDemoProject.zip. The only difference is the added line of code at line 68 of src\dnd\ListTransferHandler.java that reads:
JOptionPane.showMessageDialog(null, "CAN YOU CLICK ME AWAT?", "Try to click me away...", JOptionPane.INFORMATION_MESSAGE);
ADDITIONAL REGRESSION INFORMATION:
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1) Launch the attached app (java -cp dnd-DropDemoProject/dist/DropDemo.jar dnd.DropDemo
2) Drag drop "List Item 0" under "List Item 2"
3) Try to click the OK button on the message box that appears. It will work on all OS (I tried Windows and older Mac OS) but will fail on OS X El Capitan (v 10.11)
4) Use the Tab key and then the Space bar key to click the OK button on the message to close it.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The message box (and JDialog in general) should be responsive to the mouse clicks on the OK button.
ACTUAL -
The message box/JDialog is not responsive to the mouse click.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
/*
* Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle or the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package dnd;
/*
* DropDemo.java requires the following file:
* ListTransferHandler.java
*/
import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
public class DropDemo extends JPanel implements ActionListener {
private JComboBox dropCombo;
private JList list;
public DropDemo() {
super(new GridLayout(2,1));
add(createArea());
add(createList());
}
private JPanel createList() {
DefaultListModel listModel = new DefaultListModel();
for (int i = 0; i < 10; i++) {
listModel.addElement("List Item " + i);
}
list = new JList(listModel);
list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
JScrollPane scrollPane = new JScrollPane(list);
scrollPane.setPreferredSize(new Dimension(400,100));
list.setDragEnabled(true);
list.setTransferHandler(new ListTransferHandler());
dropCombo = new JComboBox(new String[] {"USE_SELECTION", "ON", "INSERT", "ON_OR_INSERT"});
dropCombo.addActionListener(this);
JPanel dropPanel = new JPanel();
dropPanel.add(new JLabel("List Drop Mode:"));
dropPanel.add(dropCombo);
JPanel panel = new JPanel(new BorderLayout());
panel.add(scrollPane, BorderLayout.CENTER);
panel.add(dropPanel, BorderLayout.SOUTH);
panel.setBorder(BorderFactory.createTitledBorder("List"));
return panel;
}
private JPanel createArea() {
String text = "Drag from or drop into this area.\nThe default action is MOVE;\nhold the Control key to COPY.";
JTextArea area = new JTextArea();
area.setText(text);
area.setDragEnabled(true);
JScrollPane scrollPane = new JScrollPane(area);
scrollPane.setPreferredSize(new Dimension(400,100));
JPanel panel = new JPanel(new BorderLayout());
panel.add(scrollPane, BorderLayout.CENTER);
panel.setBorder(BorderFactory.createTitledBorder("Text Area"));
return panel;
}
public void actionPerformed(ActionEvent ae) {
Object val = dropCombo.getSelectedItem();
if (val == "USE_SELECTION") {
list.setDropMode(DropMode.USE_SELECTION);
} else if (val == "ON") {
list.setDropMode(DropMode.ON);
} else if (val == "INSERT") {
list.setDropMode(DropMode.INSERT);
} else if (val == "ON_OR_INSERT") {
list.setDropMode(DropMode.ON_OR_INSERT);
}
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("DropDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
JComponent newContentPane = new DropDemo();
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() {
//Turn off metal's use of bold fonts
UIManager.put("swing.boldMetal", Boolean.FALSE);
createAndShowGUI();
}
});
}
}
/*
* Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of Oracle or the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
class ListTransferHandler extends TransferHandler {
private int[] indices = null;
private int addIndex = -1; //Location where items were added
private int addCount = 0; //Number of items added.
public boolean canImport(TransferHandler.TransferSupport info) {
// Check for String flavor
if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
return false;
}
return true;
}
protected Transferable createTransferable(JComponent c) {
return new StringSelection(exportString(c));
}
public int getSourceActions(JComponent c) {
return TransferHandler.COPY_OR_MOVE;
}
public boolean importData(TransferHandler.TransferSupport info) {
if (!info.isDrop()) {
return false;
}
//This dialog is responsive to mouse clicks everywhere except in MAC OS X El Capitan
JOptionPane.showMessageDialog(null, "CAN YOU CLICK ME AWAT?", "Try to click me away...", JOptionPane.INFORMATION_MESSAGE);
JList list = (JList)info.getComponent();
DefaultListModel listModel = (DefaultListModel)list.getModel();
JList.DropLocation dl = (JList.DropLocation)info.getDropLocation();
int index = dl.getIndex();
boolean insert = dl.isInsert();
// Get the string that is being dropped.
Transferable t = info.getTransferable();
String data;
try {
data = (String)t.getTransferData(DataFlavor.stringFlavor);
}
catch (Exception e) { return false; }
// Perform the actual import.
if (insert) {
listModel.add(index, data);
} else {
listModel.set(index, data);
}
return true;
}
protected void exportDone(JComponent c, Transferable data, int action) {
cleanup(c, action == TransferHandler.MOVE);
}
//Bundle up the selected items in the list
//as a single string, for export.
protected String exportString(JComponent c) {
JList list = (JList)c;
indices = list.getSelectedIndices();
Object[] values = list.getSelectedValues();
StringBuffer buff = new StringBuffer();
for (int i = 0; i < values.length; i++) {
Object val = values[i];
buff.append(val == null ? "" : val.toString());
if (i != values.length - 1) {
buff.append("\n");
}
}
return buff.toString();
}
//Take the incoming string and wherever there is a
//newline, break it into a separate item in the list.
protected void importString(JComponent c, String str) {
JList target = (JList)c;
DefaultListModel listModel = (DefaultListModel)target.getModel();
int index = target.getSelectedIndex();
//Prevent the user from dropping data back on itself.
//For example, if the user is moving items #4,#5,#6 and #7 and
//attempts to insert the items after item #5, this would
//be problematic when removing the original items.
//So this is not allowed.
if (indices != null && index >= indices[0] - 1 &&
index <= indices[indices.length - 1]) {
indices = null;
return;
}
int max = listModel.getSize();
if (index < 0) {
index = max;
} else {
index++;
if (index > max) {
index = max;
}
}
addIndex = index;
String[] values = str.split("\n");
addCount = values.length;
for (int i = 0; i < values.length; i++) {
listModel.add(index++, values[i]);
}
}
//If the remove argument is true, the drop has been
//successful and it's time to remove the selected items
//from the list. If the remove argument is false, it
//was a Copy operation and the original list is left
//intact.
protected void cleanup(JComponent c, boolean remove) {
if (remove && indices != null) {
JList source = (JList)c;
DefaultListModel model = (DefaultListModel)source.getModel();
//If we are moving items around in the same list, we
//need to adjust the indices accordingly, since those
//after the insertion point have moved.
if (addCount > 0) {
for (int i = 0; i < indices.length; i++) {
if (indices[i] > addIndex) {
indices[i] += addCount;
}
}
}
for (int i = indices.length - 1; i >= 0; i--) {
model.remove(indices[i]);
}
}
indices = null;
addCount = 0;
addIndex = -1;
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Use the keyboard. Not pretty and our clients wouldn't really be happy. It's also not a viable workaroud if you don't know to use the keyboard, you will get stuck on the modal JDialog indefinitely.