I have an application that takes multiple files and applies some operation that depends on their order (e.g. merge them one after another).
The user can select files in any order by Ctrl+click, or by Shift+click.
The list files returned by the chooser does not have the same order as the user clicked them. I'd like them to be returned in the same order the user clicked them.
Disclaimer: I'm "the user"
I'm using the JFileChooser
class with Java look and feel on Windows 7 64bits, with JDK 7.
Here's a minimal example
package choosertest;
import java.io.File;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
public class ChooserTest extends JFrame {
JFileChooser chooser;
public ChooserTest() {
chooser = new JFileChooser();
chooser.setMultiSelectionEnabled(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
testOpen();
}
public static void main(String[] args) {
new ChooserTest();
}
private void testOpen() {
int choice = chooser.showOpenDialog(this);
if (choice == JFileChooser.APPROVE_OPTION) {
File[] inputFiles = chooser.getSelectedFiles();
for (File f: inputFiles) {
System.out.println(f.getName());
}
}
}
}
Rather than ordering the files based upon selection order in a JFileChooser, you might consider re-ordering the files after selection using something like a JTable/JList. Be that as it may, you might be able to plug into the listener system of a JFileChooser to get the selection order by adding a PropertyChangeListener to the JFileChooser. Whenever a File is selected, the 'SelectedFilesChangedProperty' is fired, and PropertyChangeEvent.getNewValue() should return the selected files
final JFileChooser chooser = new JFileChooser();
chooser.setMultiSelectionEnabled(true);
chooser.addPropertyChangeListener(new PropertyChangeListener(){
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ( evt.getPropertyName().equals("SelectedFilesChangedProperty") ){
System.out.println(Arrays.toString((File[])evt.getNewValue()));
}
}
});
You would need to check the array of Files returned by getNewValue() to see which new file was selected (or deselected) to maintain order.
I got to the point that it Ctrl+click works and Shift+click selecting files "downwards" works.
However, using Shift+click to select files "upwards" still adds files in the wrong order, which can be confusing.
Moreover, this solution does not update the "File name" text field to reflect the actual order of the selection. It may be possible to "fix" this using reflection, though.
If you need a quick solution to select files in the correct order by Ctrl-clicking them, this works just fine (both select and deselect).
package choosertest;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
public class ChooserTest extends JFrame {
File[] selected;
JFileChooser chooser;
public ChooserTest() {
chooser = new JFileChooser();
chooser.setMultiSelectionEnabled(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
testOpen();
}
public static void main(String[] args) {
new ChooserTest();
}
private void testOpen() {
chooser.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("SelectedFilesChangedProperty")) {
if (selected == null) {
selected = (File[]) evt.getNewValue();
} else {
File[] newSelection = (File[]) evt.getNewValue();
if (newSelection == null) {
selected = null;
}
// check back and forth to preserve the order of files
// as the user added them
else {
List<File> orderedSel = new LinkedList<>();
// add files that are still selected
for (File f : selected) {
for (File f2 : newSelection) {
if (f.equals(f2)) {
orderedSel.add(f);
break;
}
}
}
Arrays.sort(selected);
// add newly selected files
for (File f : newSelection) {
if (Arrays.binarySearch(selected, f) < 0) {
orderedSel.add(f);
}
}
selected = orderedSel.toArray(
new File[orderedSel.size()]);
}
}
System.out.println(Arrays.toString(selected)); //debug
}
}
});
// copy previous array of selected files
File[] prevSelected = null;
if (selected != null) {
prevSelected = new File[selected.length];
System.arraycopy( selected, 0, prevSelected, 0, selected.length );
}
int choice = chooser.showOpenDialog(this);
// if the user did not cancel the selection
if (choice == JFileChooser.APPROVE_OPTION) {
System.out.println("FINAL selection: " + Arrays.toString(selected)); //debug
} else {
// restore the previous selection
selected = prevSelected;
System.out.println("PREVIOUS selection: " + Arrays.toString(selected)); //debug
}
}
}