diff options
author | Mark Wielaard <mark@klomp.org> | 2006-08-04 00:43:42 +0000 |
---|---|---|
committer | Mark Wielaard <mark@klomp.org> | 2006-08-04 00:43:42 +0000 |
commit | bf5fe481a4bae7980207f227d7c2580b33e58c73 (patch) | |
tree | 54b38d2d44f9f76532771aa1361a6c280b852328 /javax | |
parent | aa87fee1640b73144eda36f89367b30715749945 (diff) | |
download | classpath-bf5fe481a4bae7980207f227d7c2580b33e58c73.tar.gz |
2006-08-03 Roman Kennke <kennke@aicas.com>
PR 27606
* javax/swing/plaf/basic/BasicListUI.java
(paintCell): Pass row index to cell renderer.
* javax/swing/plaf/basic/MetalFileChooserUI.java
(DirectoryComboBoxRenderer.indentIcon): New field.
(DirectoryComboBoxRenderer.DirectoryComboBoxRenderer):
Initialize indentIcon.
(DirectoryComboBoxRenderer.getListCellRendererComponent):
Fall back to super and removed standard functionality.
Handle indentation.
(IndentIcon): New class. Wraps and indents another icon.
2006-08-03 Roman Kennke <kennke@aicas.com>
PR 27605
* javax/swing/JComboBox.java
(setSelectedItem): Fire ActionEvent here.
* javax/swing/plaf/basic/BasicDirectoryModel.java
(directories): Changed to type Vector.
(files): New field.
(loadThread): New field.
(DirectoryLoadThread): New inner class. This loads the contents
of directories asynchronously.
(getDirectories): Return cached Vector.
(getFiles): Return cached Vector.
(getSize): Return plain size of contents Vector.
(propertyChange): Reread directory also for DIRECTORY_CHANGED,
FILE_FILTER_CHANGED, FILE_HIDING_CHANGED and FILE_VIEW_CHANGED.
(sort): Don't store sorted list in contents. This must be done
asynchronously from the EventThread.
(validateFileCache): Rewritten for asynchronous reading
of directory contents.
* javax/swing/plaf/basic/BasicFileChooserUI.java
(installListeners): Install model as PropertyChangeListener.
(uninstallListeners): Uninstall model as PropertyChangeListener.
(createPropertyChangeListener): Return null just like the
RI.
2006-08-03 Roman Kennke <kennke@aicas.com>
PR 27604
* javax/swing/plaf/basic/BasicChooserUI.java
(BasicFileView.getName): Fetch the real name from the
file chooser's FileSystemView.
* javax/swing/plaf/metal/MetalChooserUI.java
(DirectoryComboBoxRenderer.getListCellRendererComponent):
Set the text fetched from the JFileChooser.getName().
* javax/swing/FileSystemView.java
(createFileObject): When file is a filesystem root,
create a filesystem root object first.
(getSystemDisplayName): Return the filename. Added specnote
about ShellFolder class that is mentioned in the spec.
* javax/swing/UnixFileSystemView.java
(getSystemDisplayName): Implemented to return the real name
of a file, special handling files like '.' or '..'.
Diffstat (limited to 'javax')
-rw-r--r-- | javax/swing/JComboBox.java | 1 | ||||
-rw-r--r-- | javax/swing/filechooser/FileSystemView.java | 21 | ||||
-rw-r--r-- | javax/swing/filechooser/UnixFileSystemView.java | 27 | ||||
-rw-r--r-- | javax/swing/plaf/basic/BasicDirectoryModel.java | 357 | ||||
-rw-r--r-- | javax/swing/plaf/basic/BasicFileChooserUI.java | 29 | ||||
-rw-r--r-- | javax/swing/plaf/basic/BasicListUI.java | 2 | ||||
-rw-r--r-- | javax/swing/plaf/metal/MetalFileChooserUI.java | 99 |
7 files changed, 449 insertions, 87 deletions
diff --git a/javax/swing/JComboBox.java b/javax/swing/JComboBox.java index ca68d8b33..fa6941cf9 100644 --- a/javax/swing/JComboBox.java +++ b/javax/swing/JComboBox.java @@ -471,6 +471,7 @@ public class JComboBox extends JComponent implements ItemSelectable, public void setSelectedItem(Object item) { dataModel.setSelectedItem(item); + fireActionEvent(); } /** diff --git a/javax/swing/filechooser/FileSystemView.java b/javax/swing/filechooser/FileSystemView.java index f51b745c8..84b80dd40 100644 --- a/javax/swing/filechooser/FileSystemView.java +++ b/javax/swing/filechooser/FileSystemView.java @@ -76,7 +76,10 @@ public abstract class FileSystemView */ public File createFileObject(String path) { - return new File(path); + File f = new File(path); + if (isFileSystemRoot(f)) + f = this.createFileSystemRoot(f); + return f; } /** @@ -223,16 +226,24 @@ public abstract class FileSystemView /** * Returns the name of a file as it would be displayed by the underlying - * system. This implementation returns <code>null</code>, subclasses must - * override. + * system. * * @param f the file. * - * @return <code>null</code>. + * @return the name of a file as it would be displayed by the underlying + * system + * + * @specnote The specification suggests that the information here is + * fetched from a ShellFolder class. This seems to be a non public + * private file handling class. We simply return File.getName() + * here and leave special handling to subclasses. */ public String getSystemDisplayName(File f) { - return null; + String name = null; + if (f != null) + name = f.getName(); + return name; } /** diff --git a/javax/swing/filechooser/UnixFileSystemView.java b/javax/swing/filechooser/UnixFileSystemView.java index 96dfd2e1b..f8d71e1df 100644 --- a/javax/swing/filechooser/UnixFileSystemView.java +++ b/javax/swing/filechooser/UnixFileSystemView.java @@ -106,17 +106,34 @@ class UnixFileSystemView extends FileSystemView /** * Returns the name of a file as it would be displayed by the underlying - * system. This method is NOT YET IMPLEMENTED. + * system. * * @param f the file. * - * @return <code>null</code>. + * @return the name of a file as it would be displayed by the underlying + * system */ public String getSystemDisplayName(File f) - throws NotImplementedException { - // FIXME: Implement; - return null; + String name = null; + if (f != null) + { + if (isRoot(f)) + name = f.getAbsolutePath(); + else + { + try + { + String path = f.getCanonicalPath(); + name = path.substring(path.lastIndexOf(File.separator) + 1); + } + catch (IOException e) + { + name = f.getName(); + } + } + } + return name; } /** diff --git a/javax/swing/plaf/basic/BasicDirectoryModel.java b/javax/swing/plaf/basic/BasicDirectoryModel.java index 058f5586e..de82bd47b 100644 --- a/javax/swing/plaf/basic/BasicDirectoryModel.java +++ b/javax/swing/plaf/basic/BasicDirectoryModel.java @@ -40,12 +40,16 @@ package javax.swing.plaf.basic; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; +import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; import java.util.Vector; import javax.swing.AbstractListModel; import javax.swing.JFileChooser; +import javax.swing.SwingUtilities; import javax.swing.event.ListDataEvent; import javax.swing.filechooser.FileSystemView; @@ -63,8 +67,15 @@ public class BasicDirectoryModel extends AbstractListModel /** The list of files itself */ private Vector contents; - /** The number of directories in the list */ - private int directories; + /** + * The directories in the list. + */ + private Vector directories; + + /** + * The files in the list. + */ + private Vector files; /** The listing mode of the associated JFileChooser, either FILES_ONLY, DIRECTORIES_ONLY or FILES_AND_DIRECTORIES */ @@ -73,6 +84,251 @@ public class BasicDirectoryModel extends AbstractListModel /** The JFileCooser associated with this model */ private JFileChooser filechooser; + /** + * The thread that loads the file view. + */ + private DirectoryLoadThread loadThread; + + /** + * This thread is responsible for loading file lists from the + * current directory and updating the model. + */ + private class DirectoryLoadThread extends Thread + { + + /** + * Updates the Swing list model. + */ + private class UpdateSwingRequest + implements Runnable + { + + private List added; + private int addIndex; + private List removed; + private int removeIndex; + private boolean cancel; + + UpdateSwingRequest(List add, int ai, List rem, int ri) + { + added = add; + addIndex = ai; + removed = rem; + removeIndex = ri; + cancel = false; + } + + public void run() + { + if (! cancel) + { + int numRemoved = removed == null ? 0 : removed.size(); + int numAdded = added == null ? 0 : added.size(); + synchronized (contents) + { + if (numRemoved > 0) + contents.removeAll(removed); + if (numAdded > 0) + contents.addAll(added); + + files = null; + directories = null; + } + if (numRemoved > 0 && numAdded == 0) + fireIntervalRemoved(BasicDirectoryModel.this, removeIndex, + removeIndex + numRemoved - 1); + else if (numRemoved == 0 && numAdded > 0) + fireIntervalAdded(BasicDirectoryModel.this, addIndex, + addIndex + numAdded - 1); + else + fireContentsChanged(); + } + } + + void cancel() + { + cancel = true; + } + } + + /** + * The directory beeing loaded. + */ + File directory; + + /** + * Stores all UpdateSwingRequests that are sent to the event queue. + */ + private UpdateSwingRequest pending; + + /** + * Creates a new DirectoryLoadThread that loads the specified + * directory. + * + * @param dir the directory to load + */ + DirectoryLoadThread(File dir) + { + super("Basic L&F directory loader"); + directory = dir; + } + + public void run() + { + FileSystemView fsv = filechooser.getFileSystemView(); + File[] files = fsv.getFiles(directory, + filechooser.isFileHidingEnabled()); + + // Occasional check if we have been interrupted. + if (isInterrupted()) + return; + + // Check list for accepted files. + Vector accepted = new Vector(); + for (int i = 0; i < files.length; i++) + { + if (filechooser.accept(files[i])) + accepted.add(files[i]); + } + + // Occasional check if we have been interrupted. + if (isInterrupted()) + return; + + // Sort list. + sort(accepted); + + // Now split up directories from files so that we get the directories + // listed before the files. + Vector newFiles = new Vector(); + Vector newDirectories = new Vector(); + for (Iterator i = accepted.iterator(); i.hasNext();) + { + File f = (File) i.next(); + boolean traversable = filechooser.isTraversable(f); + if (traversable) + newDirectories.add(f); + else if (! traversable && filechooser.isFileSelectionEnabled()) + newFiles.add(f); + + // Occasional check if we have been interrupted. + if (isInterrupted()) + return; + + } + + // Build up new file cache. Try to update only the changed elements. + // This will be important for actions like adding new files or + // directories inside a large file list. + Vector newCache = new Vector(newDirectories); + newCache.addAll(newFiles); + + int newSize = newCache.size(); + int oldSize = contents.size(); + if (newSize < oldSize) + { + // Check for removed interval. + int start = -1; + int end = -1; + boolean found = false; + for (int i = 0; i < newSize && !found; i++) + { + if (! newCache.get(i).equals(contents.get(i))) + { + start = i; + end = i + oldSize - newSize; + found = true; + } + } + if (start >= 0 && end > start + && contents.subList(end, oldSize) + .equals(newCache.subList(start, newSize))) + { + // Occasional check if we have been interrupted. + if (isInterrupted()) + return; + + Vector removed = new Vector(contents.subList(start, end)); + UpdateSwingRequest r = new UpdateSwingRequest(null, 0, + removed, start); + invokeLater(r); + newCache = null; + } + } + else if (newSize > oldSize) + { + // Check for inserted interval. + int start = oldSize; + int end = newSize; + boolean found = false; + for (int i = 0; i < oldSize && ! found; i++) + { + if (! newCache.get(i).equals(contents.get(i))) + { + start = i; + boolean foundEnd = false; + for (int j = i; j < newSize && ! foundEnd; j++) + { + if (newCache.get(j).equals(contents.get(i))) + { + end = j; + foundEnd = true; + } + } + end = i + oldSize - newSize; + } + } + if (start >= 0 && end > start + && newCache.subList(end, newSize) + .equals(contents.subList(start, oldSize))) + { + // Occasional check if we have been interrupted. + if (isInterrupted()) + return; + + List added = newCache.subList(start, end); + UpdateSwingRequest r = new UpdateSwingRequest(added, start, + null, 0); + invokeLater(r); + newCache = null; + } + } + + // Handle complete list changes (newCache != null). + if (newCache != null && ! contents.equals(newCache)) + { + // Occasional check if we have been interrupted. + if (isInterrupted()) + return; + UpdateSwingRequest r = new UpdateSwingRequest(newCache, 0, + contents, 0); + invokeLater(r); + } + } + + /** + * Wraps SwingUtilities.invokeLater() and stores the request in + * a Vector so that we can still cancel it later. + * + * @param update the request to invoke + */ + private void invokeLater(UpdateSwingRequest update) + { + pending = update; + SwingUtilities.invokeLater(update); + } + + /** + * Cancels all pending update requests that might be in the AWT + * event queue. + */ + void cancelPending() + { + if (pending != null) + pending.cancel(); + } + } + /** A Comparator class/object for sorting the file list. */ private Comparator comparator = new Comparator() { @@ -127,10 +383,19 @@ public class BasicDirectoryModel extends AbstractListModel */ public Vector<File> getDirectories() { - Vector tmp = new Vector(); - for (int i = 0; i < directories; i++) - tmp.add(contents.get(i)); - return tmp; + // Synchronize this with the UpdateSwingRequest for the case when + // contents is modified. + synchronized (contents) + { + Vector dirs = directories; + if (dirs == null) + { + // Initializes this in getFiles(). + getFiles(); + dirs = directories; + } + return dirs; + } } /** @@ -153,12 +418,28 @@ public class BasicDirectoryModel extends AbstractListModel * * @return a Vector */ - public Vector<File> getFiles() + public Vector<File> getFiles() { - Vector tmp = new Vector(); - for (int i = directories; i < getSize(); i++) - tmp.add(contents.get(i)); - return tmp; + synchronized (contents) + { + Vector f = files; + if (f == null) + { + f = new Vector(); + Vector d = new Vector(); // Directories; + for (Iterator i = contents.iterator(); i.hasNext();) + { + File file = (File) i.next(); + if (filechooser.isTraversable(file)) + d.add(file); + else + f.add(file); + } + files = f; + directories = d; + } + return f; + } } /** @@ -171,8 +452,6 @@ public class BasicDirectoryModel extends AbstractListModel */ public int getSize() { - if (listingMode == JFileChooser.DIRECTORIES_ONLY) - return directories; return contents.size(); } @@ -252,9 +531,14 @@ public class BasicDirectoryModel extends AbstractListModel */ public void propertyChange(PropertyChangeEvent e) { - if (e.getPropertyName().equals(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY)) + String property = e.getPropertyName(); + if (property.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY) + || property.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY) + || property.equals(JFileChooser.FILE_HIDING_CHANGED_PROPERTY) + || property.equals(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY) + || property.equals(JFileChooser.FILE_VIEW_CHANGED_PROPERTY) + ) { - listingMode = filechooser.getFileSelectionMode(); validateFileCache(); } } @@ -281,12 +565,6 @@ public class BasicDirectoryModel extends AbstractListModel protected void sort(Vector<? extends File> v) { Collections.sort(v, comparator); - Enumeration e = Collections.enumeration(v); - Vector tmp = new Vector(); - for (; e.hasMoreElements();) - tmp.add(e.nextElement()); - - contents = tmp; } /** @@ -294,35 +572,18 @@ public class BasicDirectoryModel extends AbstractListModel */ public void validateFileCache() { - // FIXME: Get the files and sort them in a seperate thread and deliver - // them a few at a time to be filtered, so that the file selector is - // responsive even with long file lists. - contents.clear(); - directories = 0; - FileSystemView fsv = filechooser.getFileSystemView(); - File[] list = fsv.getFiles(filechooser.getCurrentDirectory(), - filechooser.isFileHidingEnabled()); - - if (list == null) - return; - - for (int i = 0; i < list.length; i++) + File dir = filechooser.getCurrentDirectory(); + if (dir != null) { - if (list[i] == null) - continue; - boolean isDir = filechooser.isTraversable(list[i]); - - if( listingMode != JFileChooser.DIRECTORIES_ONLY || isDir ) - if (filechooser.accept(list[i])) - { - contents.add(list[i]); - if (isDir) - directories++; - } + // Cancel all pending requests. + if (loadThread != null) + { + loadThread.interrupt(); + loadThread.cancelPending(); + } + loadThread = new DirectoryLoadThread(dir); + loadThread.start(); } - sort(contents); - filechooser.revalidate(); - filechooser.repaint(); } } diff --git a/javax/swing/plaf/basic/BasicFileChooserUI.java b/javax/swing/plaf/basic/BasicFileChooserUI.java index f5b667299..e641a1c10 100644 --- a/javax/swing/plaf/basic/BasicFileChooserUI.java +++ b/javax/swing/plaf/basic/BasicFileChooserUI.java @@ -268,7 +268,14 @@ public class BasicFileChooserUI extends FileChooserUI */ public String getName(File f) { - return f.getName(); + String name = null; + if (f != null) + { + JFileChooser c = getFileChooser(); + FileSystemView v = c.getFileSystemView(); + name = v.getSystemDisplayName(f); + } + return name; } /** @@ -890,7 +897,9 @@ public class BasicFileChooserUI extends FileChooserUI protected void installListeners(JFileChooser fc) { propertyChangeListener = createPropertyChangeListener(filechooser); - filechooser.addPropertyChangeListener(propertyChangeListener); + if (propertyChangeListener != null) + filechooser.addPropertyChangeListener(propertyChangeListener); + fc.addPropertyChangeListener(getModel()); } /** @@ -900,8 +909,12 @@ public class BasicFileChooserUI extends FileChooserUI */ protected void uninstallListeners(JFileChooser fc) { - filechooser.removePropertyChangeListener(propertyChangeListener); - propertyChangeListener = null; + if (propertyChangeListener != null) + { + filechooser.removePropertyChangeListener(propertyChangeListener); + propertyChangeListener = null; + } + fc.removePropertyChangeListener(getModel()); } /** @@ -1062,12 +1075,8 @@ public class BasicFileChooserUI extends FileChooserUI */ public PropertyChangeListener createPropertyChangeListener(JFileChooser fc) { - return new PropertyChangeListener() - { - public void propertyChange(PropertyChangeEvent e) - { - } - }; + // The RI returns null here, so do we. + return null; } /** diff --git a/javax/swing/plaf/basic/BasicListUI.java b/javax/swing/plaf/basic/BasicListUI.java index 378792d74..e8f398fea 100644 --- a/javax/swing/plaf/basic/BasicListUI.java +++ b/javax/swing/plaf/basic/BasicListUI.java @@ -1210,7 +1210,7 @@ public class BasicListUI extends ListUI boolean hasFocus = (list.getLeadSelectionIndex() == row) && BasicListUI.this.list.hasFocus(); Component comp = rend.getListCellRendererComponent(list, data.getElementAt(row), - 0, isSel, hasFocus); + row, isSel, hasFocus); rendererPane.paintComponent(g, comp, list, bounds); } diff --git a/javax/swing/plaf/metal/MetalFileChooserUI.java b/javax/swing/plaf/metal/MetalFileChooserUI.java index fc8024d7b..824f1d802 100644 --- a/javax/swing/plaf/metal/MetalFileChooserUI.java +++ b/javax/swing/plaf/metal/MetalFileChooserUI.java @@ -42,6 +42,7 @@ import java.awt.BorderLayout; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; +import java.awt.Graphics; import java.awt.GridLayout; import java.awt.Insets; import java.awt.LayoutManager; @@ -568,10 +569,17 @@ public class MetalFileChooserUI extends DefaultListCellRenderer { /** + * This is the icon that is displayed in the combobox. This wraps + * the standard icon and adds indendation. + */ + private IndentIcon indentIcon; + + /** * Creates a new renderer. */ public DirectoryComboBoxRenderer(JFileChooser fc) - { + { + indentIcon = new IndentIcon(); } /** @@ -587,31 +595,86 @@ public class MetalFileChooserUI * @return The list cell renderer. */ public Component getListCellRendererComponent(JList list, Object value, - int index, boolean isSelected, boolean cellHasFocus) + int index, + boolean isSelected, + boolean cellHasFocus) { - FileView fileView = getFileView(getFileChooser()); + super.getListCellRendererComponent(list, value, index, isSelected, + cellHasFocus); File file = (File) value; - setIcon(fileView.getIcon(file)); - setText(fileView.getName(file)); - - if (isSelected) - { - setBackground(list.getSelectionBackground()); - setForeground(list.getSelectionForeground()); - } - else - { - setBackground(list.getBackground()); - setForeground(list.getForeground()); - } + setText(getFileChooser().getName(file)); + + // Install indented icon. + Icon icon = getFileChooser().getIcon(file); + indentIcon.setIcon(icon); + int depth = directoryModel.getDepth(index); + indentIcon.setDepth(depth); + setIcon(indentIcon); - setEnabled(list.isEnabled()); - setFont(list.getFont()); return this; } } /** + * An icon that wraps another icon and adds indentation. + */ + class IndentIcon + implements Icon + { + + /** + * The indentation level. + */ + private static final int INDENT = 10; + + /** + * The wrapped icon. + */ + private Icon icon; + + /** + * The current depth. + */ + private int depth; + + /** + * Sets the icon to be wrapped. + * + * @param i the icon + */ + void setIcon(Icon i) + { + icon = i; + } + + /** + * Sets the indentation depth. + * + * @param d the depth to set + */ + void setDepth(int d) + { + depth = d; + } + + public int getIconHeight() + { + return icon.getIconHeight(); + } + + public int getIconWidth() + { + return icon.getIconWidth() + depth * INDENT; + } + + public void paintIcon(Component c, Graphics g, int x, int y) + { + icon.paintIcon(c, g, x + depth * INDENT, y); + } + + } + + /** * A renderer for the files and directories in the file chooser. */ protected class FileRenderer |