summaryrefslogtreecommitdiff
path: root/javax
diff options
context:
space:
mode:
authorMark Wielaard <mark@klomp.org>2006-08-04 00:43:42 +0000
committerMark Wielaard <mark@klomp.org>2006-08-04 00:43:42 +0000
commitbf5fe481a4bae7980207f227d7c2580b33e58c73 (patch)
tree54b38d2d44f9f76532771aa1361a6c280b852328 /javax
parentaa87fee1640b73144eda36f89367b30715749945 (diff)
downloadclasspath-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.java1
-rw-r--r--javax/swing/filechooser/FileSystemView.java21
-rw-r--r--javax/swing/filechooser/UnixFileSystemView.java27
-rw-r--r--javax/swing/plaf/basic/BasicDirectoryModel.java357
-rw-r--r--javax/swing/plaf/basic/BasicFileChooserUI.java29
-rw-r--r--javax/swing/plaf/basic/BasicListUI.java2
-rw-r--r--javax/swing/plaf/metal/MetalFileChooserUI.java99
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