JDK-4679673 : JFileChooser.setSelectedFiles() is very slow for multiple select
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.4.1
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_2000
  • CPU: x86
  • Submitted: 2002-05-03
  • Updated: 2003-10-08
  • Resolved: 2003-02-25
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
1.4.2 b17Fixed
Related Reports
Relates :  
Relates :  
Description

Name: jk109818			Date: 05/03/2002


FULL PRODUCT VERSION :
java version "1.4.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.0-b92)
Java HotSpot(TM) Client VM (build 1.4.0-b92, mixed mode)

FULL OPERATING SYSTEM VERSION :
Microsoft Windows 2000 [Version 5.00.2195]

A DESCRIPTION OF THE PROBLEM :
Calling setSelectedFiles() with a large array of files
(e.g. 475) on a JFileChooser configured with
setMultiSelectionEnabled(true) is extremely slow (i.e. 3.5
minutes). Selecting all files by typing Ctrl-A in the file
list takes a second or two.

The bulk of the time is taken by
MetalFileChooserUI.setFileSelected(). It walks through the
selectedFiles array comparing it to the array of selected
values in the JList, then adjusts the JList selection which
fires a selection property change which starts the whole
process over again. It's very inefficient.

It would also be nice if JFileChooser exposed a selectAll()
method that efficiently selected all files in the list.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Run the attached SelectAllChooser program
2. Navigate to a directory containing a lot of files (you
can see the slowness with only 30 files or so, but the more
files the more obvious)
3. Press the Select All button in the chooser accessory

EXPECTED VERSUS ACTUAL BEHAVIOR :
It takes a very long time to select all the files. The
program prints how long it took to stdout.

This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
public class SelectAllChooser {
	public static void main(String args[]) {
		final JFileChooser fc = new JFileChooser();
		fc.setMultiSelectionEnabled(true);
		JButton btnSelectAll = new JButton("Select All");
		btnSelectAll.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				long lStart = System.currentTimeMillis();
				File[] files = fc.getCurrentDirectory
().listFiles();
				fc.setSelectedFiles(files);
				System.out.println("time " +
(System.currentTimeMillis() - lStart) + "ms");
			}
		});
		fc.setAccessory(btnSelectAll);
		fc.showOpenDialog(null);
		System.exit(0);
	}
}
---------- END SOURCE ----------

CUSTOMER WORKAROUND :
You can type Ctrl-A in the list to select all files, but
users do not know this which is why I am providing a
button. It would be nice if there was some way to have the
button programmatically invoke the "selectAll" Action on
the JList.
(Review ID: 146137) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: mantis-beta tiger FIXED IN: mantis-beta tiger INTEGRATED IN: mantis-b17 mantis-beta tiger
14-06-2004

EVALUATION This has been mostly fixed in 1.4.1, but some more work is still needed. ###@###.### 2002-05-24 When typing ctrl-A, the list selection handler in the file chooser UI goes through all the selected files and determines which ones are valid, e.g. folders can't be selected in FILES_ONLY mode and non- filesystem folders can't be selected in DIRECTORIES_ONLY mode. This algorithm was coded in a very inefficient way, using double loops that fired new selection events causing the whole thing to be called recursively. The fix takes care of by straightening out the logig into one loop and coalescing events. ###@###.### 2003-02-13
13-02-2003

WORK AROUND While the response time is much better in 1.4.1 beta, the following workaround may improve it further by obout 30%. Note that this is a complex workaround that has not been extensively tested and may cause other problems. Use at your own risk. This workaround will probably not yield significant improvements on releases prior to 1.4.1 beta. import java.awt.*; import java.awt.event.*; import java.beans.*; import java.io.*; import javax.swing.*; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.metal.MetalFileChooserUI; public class SelectAllChooser { public static void main(String args[]) { final JFileChooser fc = new JFileChooser(); fc.setMultiSelectionEnabled(true); if (fc.getUI() instanceof MetalFileChooserUI) { UIManager.getDefaults().put("FileChooserUI", "SelectAllChooser$MyMetalFCUI"); fc.updateUI(); }; JButton btnSelectAll = new JButton("Select All"); btnSelectAll.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { long lStart = System.currentTimeMillis(); File[] files = fc.getCurrentDirectory().listFiles(); fc.setSelectedFiles(files); System.out.println(fc.getSelectedFiles().length + "files, time=" + (System.currentTimeMillis() - lStart) + "ms"); } }); fc.setAccessory(btnSelectAll); fc.showOpenDialog(null); System.exit(0); } public static class MyMetalFCUI extends MetalFileChooserUI implements PropertyChangeListener { JList list; PropertyChangeListener superPCL; public static ComponentUI createUI(JComponent c) { return new MyMetalFCUI((JFileChooser)c); } MyMetalFCUI(JFileChooser filechooser) { super(filechooser); list = findJList(filechooser); } public PropertyChangeListener createPropertyChangeListener(JFileChooser fc) { superPCL = super.createPropertyChangeListener(fc); return this; } public void propertyChange(PropertyChangeEvent e) { String s = e.getPropertyName(); if (s.equals(JFileChooser.SELECTED_FILES_CHANGED_PROPERTY) && list.getValueIsAdjusting()) { return; } if (s.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) { list.setValueIsAdjusting(true); } superPCL.propertyChange(e); if (s.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) { list.setValueIsAdjusting(false); } } private JList findJList(Container container) { int n = container.getComponentCount(); for (int i = 0; i < n; i++) { Component comp = container.getComponent(i); if (comp instanceof JList) { return (JList)comp; } else if (comp instanceof Container) { JList list = findJList((Container)comp); if (list != null) { return list; } } } return null; } } } ###@###.### 2002-05-24
24-05-2002