United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-4679673 JFileChooser.setSelectedFiles() is very slow for multiple select
JDK-4679673 : JFileChooser.setSelectedFiles() is very slow for multiple select

Details
Type:
Bug
Submit Date:
2002-05-03
Status:
Resolved
Updated Date:
2003-10-08
Project Name:
JDK
Resolved Date:
2003-02-25
Component:
client-libs
OS:
windows_2000
Sub-Component:
javax.swing
CPU:
x86
Priority:
P3
Resolution:
Fixed
Affected Versions:
1.4.1
Fixed Versions:
1.4.2 (b17)

Related Reports
Backport:
Relates:
Relates:

Sub Tasks

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
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
                                     
2002-05-24
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
                                     
2003-02-13
CONVERTED DATA

BugTraq+ Release Management Values

COMMIT TO FIX:
mantis-beta
tiger

FIXED IN:
mantis-beta
tiger

INTEGRATED IN:
mantis-b17
mantis-beta
tiger


                                     
2004-06-14



Hardware and Software, Engineered to Work Together