classpath-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[cp-patches] RFC: MetalFileChooserUI implementation


From: David Gilbert
Subject: [cp-patches] RFC: MetalFileChooserUI implementation
Date: Fri, 25 Nov 2005 11:39:42 +0000
User-agent: Mozilla Thunderbird 1.0.7 (X11/20051026)

Hi all,

In recent weeks I have done some work on a MetalFileChooserUI implementation, but don't have enough time lately to fix the last few problems. Lillian mentioned that she has just started looking at this also, so I thought I would send in my current patch (which is unfortunately somewhat large) for others to look at and/or work on.

Some notes:

- the patch destroys the current file chooser UI in the BasicLookAndFeel (the one in the reference implementation doesn't function on its own either); - I already committed a FileChooserDemo to the GNU Classpath Swing demo, and this is useful for testing ('open' and 'save' work for me, selecting a directory doesn't, multiple selection doesn't); - a recent regression in the JComboBox implementation makes the directory selection somewhat flakey; - there is a bug in the JList implementation that prevents the correct layout of the files and directories from being used, it was working previously (for now, I've used the standard list layout); - this patch fixes most (but not all) of the Mauve tests that I've written for JFileChooser/BasicFileChooserUI/MetalFileChooserUI.

If there any questions, please ask. Perhaps if the patch works well enough for others, I can just commit it to CVS and then anyone else can jump in to help with fixes.

Here is a ChangeLog entry (with some TODOs marked):

2005-11-25  David Gilbert  <address@hidden>

        * javax/swing/JFileChooser.java
        (selectedFiles): Initialise,
        (JFileChooser(String)): Delegate to another constructor,
        (JFileChooser(String, FileSystemView)): Convert directory to file,
        (setSelectedFile): Check for current selection == null,
        (getSelectedFiles): Updated API docs,
        (setSelectedFiles): Changed order of event generation,
        (changeToParentDirectory): Don't check for null parent (reference
        implementation doesn't),
        (addChoosableFileFilter): Change handling of null filter,
        (removeChoosableFileFilter): Handle case where removed filter is also
        the current selection,
        (setAcceptAllFileFilterUsed): Add or remove accept all filter as
        appropriate,
        (setFileFilter): Add new filter to choosable filters if necessary,
        (accept): Reimplemented,
        * javax/swing/plaf/basic/BasicFileChooserUI.java
        (ApproveSelectionAction.ApproveSelectionAction): Set action name,
        (ApproveSelectionAction.actionPerformed): Call getFileName() rather
        than accessing JTextField directly,
        (CancelSelectionAction.CancelSelectionAction): Set action name,
        (ChangeToParentDirectoryAction.ChangeToParentDirectoryAction): Set
        action name,
        (DoubleClickListener.mouseClicked): Call setFileName rather than
        accessing JTextField directly,
        (GoHomeAction.GoHomeAction): Set action name,
        (NewFolderAction.NewFolderAction): Set action name,
        (SelectionListener.valueChanged): Get list from event,
        (UpdateAction.UpdateAction): Set action name to null,
        (computerIcon): Removed initialization,
        (detailsViewIcon): Likewise,
        (directoryIcon): Likewise,
        (fileIcon): Likewise,
        (floppyDriveIcon): Likewise,
        (hardDriveIcon): Likewise,
        (homeFolderIcon): Likewise,
        (listViewIcon): Likewise,
        (upFolderIcon): Likewise,
        (fileList): Removed,
        (filters): Removed,
        (ICON_SIZE): Removed,
        (parents): Removed,
        (filename): Removed,
        (cancel): Removed,
        (upFolderButton): Removed,
        (newFolderButton): Removed,
        (homeFolderButton): Removed,
        (approveSelectionAction): New field,
        (cancelSelectionAction): New field,
        (goHomeAction): New field,
        (changeToParentDirectoryAction): New field,
        (newFolderAction): New field,
        (updateAction): New field,
        (BasicFileChooserUI): Do nothing here,
        (installUI): Initialise filechooser field,
        (createBoxListener): Removed,
        (createFilterListener): Removed,
        (filterEntries): Removed,
        (installComponents): Do nothing here,
        (uninstallComponents): Do nothing here,
        (installListeners): Removed component specific listeners,
        (installIcons): Use Metal icons,
        (unintallIcons): Clear icons,
        (installStrings): Use fixed strings for text items that aren't defined
        in the UI defaults - should implement localised strings later,
        (uninstallStrings): Clear text items,
        (createPropertyChangeListener): Return blank listener,
        (getFileName): TODO,
        (setFileName): TODO,
        (rescanCurrentDirectory): Remove call on deleted filelist,
        (getApproveButton): Just return field,
        (getFileView): Updated API docs,
        (getDialogTitle): Reimplemented,
        (getApproveButtonText): Reimplemented,
        (getNewFolderAction): Create new instance if required,
        (getGoHomeAction): Likewise,
        (getChangeToParentDirectoryAction): Likewise,
        (getApproveSelectionAction): Likewise,
        (getCancelSelectionAction): Likewise,
        (getUpdateAction): Likewise,
        * javax/swing/plaf/metal/MetalFileChooserUI.java
        (MetalFileChooserPropertyChangeListener): New class,
        (DirectoryComboBoxRenderer): New class,
        (FilterComboBoxModel.selectedIndex): Removed field,
        (FilterComboBoxModel.selected): New field,
        (FilterComboBoxModel.FilterComboBoxModel): Initialise selected field,
        (FilterComboBoxModel.propertyChange): Update filter list,
        (FilterComboBoxModel.setSelectedItem): Reimplemented,
        (FilterComboBoxModel.getSelectedItem): Return selected field,
        (FilterComboBoxRenderer.getListCellRendererComponent): Call super,
        (MetalFileChooserSelectionListener): New class,
        (SingleClickListener): New class TODO,
        (directoryLabel): New field,
        (directoryComboBox): New field,
        (fileLabel): New field,
        (fileTextField): New field,
        (filterLabel): New field,
        (topPanel): New field,
        (controls): New field,
        (bottomPanel): New field,
        (buttonPanel): New field,
        (approveButton): New field,
        (fileList): New field,
        (fileListPanel): New field,
        (filterModel): New field,
        (MetalFileChooserUI): Initialise panels,
        (installUI): TODO,
        (uninstallUI): TODO,
        (installComponents): Implemented,
        (uninstallComponents): Implemented,
        (getButtonPanel): Implemented,
        (getBottomPanel): Implemented,
        (installStrings): Implemented,
        (installListeners): Implemented,
        (uninstallListeners): Implemented,
        (getActionMap): TODO,
        (createActionMap): Implemented,
        (createList): Implemented,
        (createDetailsView): Implemented,
        (createListSelectionListener): Implemented,
        (getPreferredSize): Implemented badly,
        (getMinimumSize): Likewise,
        (getMaximumSize): Implemented,
        (createPropertyChangeListener): Implemented,
        (createDirectoryComboBoxRenderer): Implemented,
        (addControlButtons): Implemented,
        (removeControlButtons): TODO,
        (ensureFileIsVisible): TODO,
        (rescanCurrentDirectory): Implemented,
        (getFileName): Implemented,
        (setFileName): Implemented,
        (setDirectorySelected): TODO,
        (getDirectoryName): TODO,
        (setDirectoryName): TODO,
        (valueChanged): TODO,
        (getApproveButton): Implemented,
        (VerticalMidLayout): New support class,
        (ButtonLayout): New support class,
        * javax/swing/plaf/metal/MetalLookAndFeel.java
        (initClassDefaults): Add 'FileChooserUI' default,
        (initComponentDefaults): Added FileChooser icons.

Regards,

Dave
Index: javax/swing/JFileChooser.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/swing/JFileChooser.java,v
retrieving revision 1.22
diff -u -r1.22 JFileChooser.java
--- javax/swing/JFileChooser.java       1 Nov 2005 18:02:30 -0000       1.22
+++ javax/swing/JFileChooser.java       25 Nov 2005 10:21:07 -0000
@@ -381,7 +381,7 @@
    * An array of selected files.
    * @see #setSelectedFiles(File[]) 
    */
-  private File[] selectedFiles;
+  private File[] selectedFiles = new File[0];
 
   /** 
    * The selected file. 
@@ -407,8 +407,7 @@
    */
   public JFileChooser(String currentDirectoryPath)
   {
-    setup(null);
-    setCurrentDirectory(fsv.createFileObject(currentDirectoryPath));
+    this(currentDirectoryPath, null);
   }
 
   /**
@@ -424,7 +423,10 @@
   public JFileChooser(String currentDirectoryPath, FileSystemView fsv)
   {
     setup(fsv);
-    setCurrentDirectory(fsv.createFileObject(currentDirectoryPath));
+    File dir = null;
+    if (currentDirectoryPath != null)
+      dir = getFileSystemView().createFileObject(currentDirectoryPath);
+    setCurrentDirectory(dir);
   }
 
   /**
@@ -525,7 +527,7 @@
    */
   public void setSelectedFile(File file)
   {
-    if (selectedFile != file)
+    if (selectedFile == null || !selectedFile.equals(file))
       {
        File old = selectedFile;
        selectedFile = file;
@@ -534,10 +536,10 @@
   }
 
   /**
-   * Returns the selected file or files.
+   * Returns the selected file or files in an array.  If no files are selected,
+   * an empty array is returned.
    *
-   * @return An array of the selected files, or <code>null</code> if there are 
-   *         no selected files.
+   * @return An array of the selected files (possibly empty).
    */
   public File[] getSelectedFiles()
   {
@@ -557,6 +559,12 @@
    */
   public void setSelectedFiles(File[] selectedFiles)
   {
+    if (selectedFiles == null)
+      selectedFiles = new File[0];
+    if (selectedFiles.length > 0)
+      setSelectedFile(selectedFiles[0]);
+    else
+      setSelectedFile(null);
     if (this.selectedFiles != selectedFiles)
       {
        File[] old = this.selectedFiles;
@@ -564,8 +572,6 @@
        firePropertyChange(SELECTED_FILES_CHANGED_PROPERTY, old, selectedFiles);
       }
 
-    if (selectedFiles != null)
-      setSelectedFile(selectedFiles[0]);
   }
 
   /**
@@ -607,8 +613,7 @@
    */
   public void changeToParentDirectory()
   {
-    if (fsv.getParentDirectory(currentDir) != null)
-      setCurrentDirectory(fsv.getParentDirectory(currentDir));
+    setCurrentDirectory(fsv.getParentDirectory(currentDir));
   }
 
   /**
@@ -958,14 +963,19 @@
    * address@hidden #CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY}) to all 
registered 
    * listeners.
    *
-   * @param filter  the filter.
+   * @param filter  the filter (<code>null</code> permitted).
    */
   public void addChoosableFileFilter(FileFilter filter)
   {
-    FileFilter[] old = getChoosableFileFilters();
-    choosableFilters.add(filter);
-    FileFilter[] newFilters = getChoosableFileFilters();
-    firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, old, 
newFilters);
+    if (filter != null)
+      {
+        FileFilter[] old = getChoosableFileFilters();
+        choosableFilters.add(filter);
+        FileFilter[] newFilters = getChoosableFileFilters();
+        firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, old, 
+              newFilters);
+      }
+    setFileFilter(filter);
   }
 
   /**
@@ -981,6 +991,8 @@
    */
   public boolean removeChoosableFileFilter(FileFilter f)
   {
+    if (f == currentFilter)
+      setFileFilter(null);
     FileFilter[] old = getChoosableFileFilters();
     if (! choosableFilters.remove(f))
       return false;
@@ -1037,6 +1049,10 @@
     if (isAcceptAll != b)
       {
        isAcceptAll = b;
+        if (b)
+          addChoosableFileFilter(getAcceptAllFileFilter());
+        else 
+          removeChoosableFileFilter(getAcceptAllFileFilter());
        firePropertyChange(ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY,
                           ! isAcceptAll, isAcceptAll);
       }
@@ -1208,15 +1224,17 @@
    * property name address@hidden #FILE_FILTER_CHANGED_PROPERTY}) to all 
registered 
    * listeners.
    *
-   * @param filter  the filter.
+   * @param filter  the filter (<code>null</code> permitted).
    */
   public void setFileFilter(FileFilter filter)
   {
     if (currentFilter != filter)
       {
-       FileFilter old = currentFilter;
-       currentFilter = filter;
-       firePropertyChange(FILE_FILTER_CHANGED_PROPERTY, old, currentFilter);
+        if (filter != null && !choosableFilters.contains(filter))
+          addChoosableFileFilter(filter);
+        FileFilter old = currentFilter;
+        currentFilter = filter;
+        firePropertyChange(FILE_FILTER_CHANGED_PROPERTY, old, currentFilter);
       }
   }
 
@@ -1356,8 +1374,12 @@
   public boolean accept(File f)
   {
     if (f == null)
-      return false;
-    return getFileFilter().accept(f);
+      return true;
+    FileFilter ff = getFileFilter();
+    if (ff != null) 
+      return ff.accept(f);
+    else
+      return true;
   }
 
   /**
Index: javax/swing/plaf/basic/BasicFileChooserUI.java
===================================================================
RCS file: 
/cvsroot/classpath/classpath/javax/swing/plaf/basic/BasicFileChooserUI.java,v
retrieving revision 1.17
diff -u -r1.17 BasicFileChooserUI.java
--- javax/swing/plaf/basic/BasicFileChooserUI.java      15 Nov 2005 20:32:46 
-0000      1.17
+++ javax/swing/plaf/basic/BasicFileChooserUI.java      25 Nov 2005 10:21:09 
-0000
@@ -37,19 +37,10 @@
 
 package javax.swing.plaf.basic;
 
-import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Component;
-import java.awt.Dimension;
-import java.awt.Graphics;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Point;
-import java.awt.Polygon;
 import java.awt.Window;
 import java.awt.event.ActionEvent;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
@@ -62,23 +53,20 @@
 
 import javax.swing.AbstractAction;
 import javax.swing.Action;
-import javax.swing.ButtonGroup;
 import javax.swing.Icon;
 import javax.swing.JButton;
-import javax.swing.JComboBox;
 import javax.swing.JComponent;
 import javax.swing.JDialog;
 import javax.swing.JFileChooser;
 import javax.swing.JLabel;
 import javax.swing.JList;
 import javax.swing.JPanel;
-import javax.swing.JScrollPane;
 import javax.swing.JTextField;
-import javax.swing.JToggleButton;
 import javax.swing.ListCellRenderer;
 import javax.swing.SwingConstants;
 import javax.swing.SwingUtilities;
 import javax.swing.Timer;
+import javax.swing.UIDefaults;
 import javax.swing.UIManager;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
@@ -87,6 +75,7 @@
 import javax.swing.filechooser.FileView;
 import javax.swing.plaf.ComponentUI;
 import javax.swing.plaf.FileChooserUI;
+import javax.swing.plaf.metal.MetalIconFactory;
 
 
 /**
@@ -144,7 +133,7 @@
      */
     protected ApproveSelectionAction()
     {
-      // Nothing to do here.
+      super("approveSelection");
     }
 
     /**
@@ -154,7 +143,7 @@
      */
     public void actionPerformed(ActionEvent e)
     {
-      Object obj = new String(parentPath + entry.getText());
+      Object obj = new String(parentPath + getFileName());
       if (obj != null)
         {
           File f = filechooser.getFileSystemView().createFileObject(
@@ -307,7 +296,7 @@
      */
     protected CancelSelectionAction()
     {
-      // Nothing to do here.
+      super(null);
     }
 
     /**
@@ -335,7 +324,7 @@
      */
     protected ChangeToParentDirectoryAction()
     {
-      // Nothing to do here.
+      super("Go Up");
     }
 
     /**
@@ -424,7 +413,7 @@
             }
           lastSelected = path;
           parentPath = path.substring(0, path.lastIndexOf("/") + 1);
-          entry.setText(path.substring(path.lastIndexOf("/") + 1));
+          setFileName(path.substring(path.lastIndexOf("/") + 1));
           timer.restart();
         }
     }
@@ -453,7 +442,7 @@
      */
     protected GoHomeAction()
     {
-      // Nothing to do here.
+      super("Go Home");
     }
 
     /**
@@ -483,7 +472,7 @@
      */
     protected NewFolderAction()
     {
-      // Nothing to do here.
+      super("New Folder");
     }
 
     /**
@@ -529,7 +518,8 @@
      */
     public void valueChanged(ListSelectionEvent e)
     {
-      Object f = filelist.getSelectedValue();
+      JList list = (JList) e.getSource();
+      Object f = list.getSelectedValue();
       if (f == null)
        return;
       File file = 
filechooser.getFileSystemView().createFileObject(f.toString());
@@ -552,7 +542,7 @@
      */
     protected UpdateAction()
     {
-      // Nothing to do here.
+      super(null);
     }
 
     /**
@@ -576,91 +566,13 @@
   protected String cancelButtonToolTipText;
 
   /** An icon representing a computer. */
-  protected Icon computerIcon = new Icon()
-    {
-      public int getIconHeight()
-      {
-       return ICON_SIZE;
-      }
-
-      public int getIconWidth()
-      {
-       return ICON_SIZE;
-      }
-
-      public void paintIcon(Component c, Graphics g, int x, int y)
-      {
-        // FIXME: is this not implemented, or is the icon intentionally blank?
-      }
-    };
+  protected Icon computerIcon;
 
   /** An icon for the "details view" button. */
-  protected Icon detailsViewIcon = new Icon()
-    {
-      public int getIconHeight()
-      {
-       return ICON_SIZE;
-      }
-
-      public int getIconWidth()
-      {
-       return ICON_SIZE;
-      }
-
-      public void paintIcon(Component c, Graphics g, int x, int y)
-      {
-       Color saved = g.getColor();
-       g.translate(x, y);
-
-       g.setColor(Color.GRAY);
-       g.drawRect(1, 1, 15, 20);
-       g.drawLine(17, 6, 23, 6);
-       g.drawLine(17, 12, 23, 12);
-       g.drawLine(17, 18, 23, 18);
-
-       g.setColor(saved);
-       g.translate(-x, -y);
-      }
-    };
+  protected Icon detailsViewIcon;
 
   /** An icon representing a directory. */
-  protected Icon directoryIcon = new Icon()
-    {
-      public int getIconHeight()
-      {
-       return ICON_SIZE;
-      }
-
-      public int getIconWidth()
-      {
-       return ICON_SIZE;
-      }
-
-      public void paintIcon(Component c, Graphics g, int x, int y)
-      {
-       Color saved = g.getColor();
-       g.translate(x, y);
-
-       Point ap = new Point(3, 7);
-       Point bp = new Point(3, 21);
-       Point cp = new Point(21, 21);
-       Point dp = new Point(21, 12);
-       Point ep = new Point(16, 12);
-       Point fp = new Point(13, 7);
-
-       Polygon dir = new Polygon(new int[] { ap.x, bp.x, cp.x, dp.x, ep.x, 
fp.x },
-                                 new int[] { ap.y, bp.y, cp.y, dp.y, ep.y, 
fp.y },
-                                 6);
-
-       g.setColor(new Color(153, 204, 255));
-       g.fillPolygon(dir);
-       g.setColor(Color.BLACK);
-       g.drawPolygon(dir);
-
-       g.translate(-x, -y);
-       g.setColor(saved);
-      }
-    };
+  protected Icon directoryIcon;
 
   /** The localised Mnemonic for the open button. */
   protected int directoryOpenButtonMnemonic;
@@ -672,82 +584,13 @@
   protected String directoryOpenButtonToolTipText;
 
   /** An icon representing a file. */
-  protected Icon fileIcon = new Icon()
-    {
-      public int getIconHeight()
-      {
-       return ICON_SIZE;
-      }
-
-      public int getIconWidth()
-      {
-       return ICON_SIZE;
-      }
-
-      public void paintIcon(Component c, Graphics g, int x, int y)
-      {
-       Color saved = g.getColor();
-       g.translate(x, y);
-
-       Point a = new Point(5, 4);
-       Point b = new Point(5, 20);
-       Point d = new Point(19, 20);
-       Point e = new Point(19, 7);
-       Point f = new Point(16, 4);
-
-       Polygon p = new Polygon(new int[] { a.x, b.x, d.x, e.x, f.x, },
-                               new int[] { a.y, b.y, d.y, e.y, f.y }, 5);
-
-       g.setColor(Color.WHITE);
-       g.fillPolygon(p);
-       g.setColor(Color.BLACK);
-       g.drawPolygon(p);
-
-       g.drawLine(16, 4, 14, 6);
-       g.drawLine(14, 6, 19, 7);
-
-       g.setColor(saved);
-       g.translate(-x, -y);
-      }
-    };
+  protected Icon fileIcon;
 
   /** An icon representing a floppy drive. */
-  protected Icon floppyDriveIcon = new Icon()
-    {
-      public int getIconHeight()
-      {
-       return ICON_SIZE;
-      }
-
-      public int getIconWidth()
-      {
-       return ICON_SIZE;
-      }
-
-      public void paintIcon(Component c, Graphics g, int x, int y)
-      {
-        // FIXME: is this not implemented, or is the icon intentionally blank?
-      }
-    };
+  protected Icon floppyDriveIcon;
 
   /** An icon representing a hard drive. */
-  protected Icon hardDriveIcon = new Icon()
-    {
-      public int getIconHeight()
-      {
-       return ICON_SIZE;
-      }
-
-      public int getIconWidth()
-      {
-       return ICON_SIZE;
-      }
-
-      public void paintIcon(Component c, Graphics g, int x, int y)
-      {
-        // FIXME: is this not implemented, or is the icon intentionally blank?
-      }
-    };
+  protected Icon hardDriveIcon;
 
   /** The localised mnemonic for the "help" button. */
   protected int helpButtonMnemonic;
@@ -759,86 +602,10 @@
   protected String helpButtonToolTipText;
 
   /** An icon representing the user's home folder. */
-  protected Icon homeFolderIcon = new Icon()
-    {
-      public int getIconHeight()
-      {
-       return ICON_SIZE;
-      }
-
-      public int getIconWidth()
-      {
-       return ICON_SIZE;
-      }
-
-      public void paintIcon(Component c, Graphics g, int x, int y)
-      {
-       Color saved = g.getColor();
-       g.translate(x, y);
-
-       Point a = new Point(12, 3);
-       Point b = new Point(4, 10);
-       Point d = new Point(20, 10);
-
-       Polygon p = new Polygon(new int[] { a.x, b.x, d.x },
-                               new int[] { a.y, b.y, d.y }, 3);
-
-       g.setColor(new Color(104, 51, 0));
-       g.fillPolygon(p);
-       g.setColor(Color.BLACK);
-       g.drawPolygon(p);
-
-       g.setColor(Color.WHITE);
-       g.fillRect(8, 10, 8, 10);
-       g.setColor(Color.BLACK);
-       g.drawRect(8, 10, 8, 10);
-
-       g.setColor(saved);
-       g.translate(-x, -y);
-      }
-    };
+  protected Icon homeFolderIcon;
 
   /** An icon for the "list view" button. */
-  protected Icon listViewIcon = new Icon()
-    {
-      public int getIconHeight()
-      {
-       return ICON_SIZE;
-      }
-
-      public int getIconWidth()
-      {
-       return ICON_SIZE;
-      }
-
-      // Not needed. Only simplifies things until we get real icons.
-      private void paintPartial(Graphics g, int x, int y)
-      {
-       Color saved = g.getColor();
-       g.translate(x, y);
-
-       g.setColor(Color.GRAY);
-       g.drawRect(1, 1, 7, 10);
-       g.drawLine(8, 6, 11, 6);
-
-       g.setColor(saved);
-       g.translate(-x, -y);
-      }
-
-      public void paintIcon(Component c, Graphics g, int x, int y)
-      {
-       Color saved = g.getColor();
-       g.translate(x, y);
-
-       paintPartial(g, 0, 0);
-       paintPartial(g, 12, 0);
-       paintPartial(g, 0, 12);
-       paintPartial(g, 12, 12);
-
-       g.setColor(saved);
-       g.translate(-x, -y);
-      }
-    };
+  protected Icon listViewIcon;
 
   /** An icon for the "new folder" button. */
   protected Icon newFolderIcon = directoryIcon;
@@ -871,65 +638,13 @@
   protected String updateButtonToolTipText;
 
   /** An icon for the "up folder" button. */
-  protected Icon upFolderIcon = new Icon()
-    {
-      public int getIconHeight()
-      {
-       return ICON_SIZE;
-      }
-
-      public int getIconWidth()
-      {
-       return ICON_SIZE;
-      }
-
-      public void paintIcon(Component comp, Graphics g, int x, int y)
-      {
-       Color saved = g.getColor();
-       g.translate(x, y);
-
-       Point a = new Point(3, 7);
-       Point b = new Point(3, 21);
-       Point c = new Point(21, 21);
-       Point d = new Point(21, 12);
-       Point e = new Point(16, 12);
-       Point f = new Point(13, 7);
-
-       Polygon dir = new Polygon(new int[] { a.x, b.x, c.x, d.x, e.x, f.x },
-                                 new int[] { a.y, b.y, c.y, d.y, e.y, f.y }, 
6);
-
-       g.setColor(new Color(153, 204, 255));
-       g.fillPolygon(dir);
-       g.setColor(Color.BLACK);
-       g.drawPolygon(dir);
-
-       a = new Point(12, 15);
-       b = new Point(9, 18);
-       c = new Point(15, 18);
-
-       Polygon arrow = new Polygon(new int[] { a.x, b.x, c.x },
-                                   new int[] { a.y, b.y, c.y }, 3);
-
-       g.fillPolygon(arrow);
-
-       g.drawLine(12, 15, 12, 22);
-
-       g.translate(-x, -y);
-       g.setColor(saved);
-      }
-    };
+  protected Icon upFolderIcon;
 
   // -- begin private, but package local since used in inner classes --
 
   /** The file chooser component represented by this UI delegate. */
   JFileChooser filechooser;
 
-  /** The file list. */
-  JList filelist;
-
-  /** The combo box used to display/select file filters. */
-  JComboBox filters;
-
   /** The model for the directory list. */
   BasicDirectoryModel model;
 
@@ -939,30 +654,9 @@
   /** The default file view. */
   FileView fv = new BasicFileView();
 
-  /** The icon size. */
-  static final int ICON_SIZE = 24;
-
-  /** A combo box for display/selection of parent directories. */
-  JComboBox parents;
-
-  /** The current file name. */
-  String filename;
-
   /** The accept (open/save) button. */
   JButton accept;
 
-  /** The cancel button. */
-  JButton cancel;
-
-  /** The button to move up to the parent directory. */
-  JButton upFolderButton;
-
-  /** The button to create a new directory. */
-  JButton newFolderButton;
-
-  /** The button to move to the user's home directory. */
-  JButton homeFolderButton;
-
   /** An optional accessory panel. */
   JPanel accessoryPanel;
 
@@ -997,6 +691,42 @@
   /** Current parent path */
   String parentPath;
   
+  /**
+   * The action for the 'approve' button.
+   * @see #getApproveSelectionAction()
+   */
+  private ApproveSelectionAction approveSelectionAction;
+  
+  /**
+   * The action for the 'cancel' button.
+   * @see #getCancelSelectionAction()
+   */
+  private CancelSelectionAction cancelSelectionAction;
+  
+  /**
+   * The action for the 'go home' control button.
+   * @see #getGoHomeAction()
+   */
+  private GoHomeAction goHomeAction;
+  
+  /**
+   * The action for the 'up folder' control button.
+   * @see #getChangeToParentDirectoryAction()
+   */
+  private ChangeToParentDirectoryAction changeToParentDirectoryAction;
+  
+  /**
+   * The action for the 'new folder' control button.
+   * @see #getNewFolderAction()
+   */
+  private NewFolderAction newFolderAction;
+  
+  /**
+   * The action for ???.  // FIXME: what is this?
+   * @see #getUpdateAction()
+   */
+  private UpdateAction updateAction;
+  
   // -- end private --
   private class ListLabelRenderer extends JLabel implements ListCellRenderer
   {
@@ -1056,7 +786,6 @@
    */
   public BasicFileChooserUI(JFileChooser b)
   {
-    this.filechooser = b;
   }
 
   /**
@@ -1081,6 +810,7 @@
     if (c instanceof JFileChooser)
       {
         JFileChooser fc = (JFileChooser) c;
+        this.filechooser = fc;
         fc.resetChoosableFileFilters();
         createModel();
         clearIconCache();
@@ -1130,78 +860,7 @@
     if (parentFiles.size() == 0)
       return;
 
-    if (parents.getItemCount() > 0)
-      parents.removeAllItems();
-    for (int i = parentFiles.size() - 1; i >= 0; i--)
-      parents.addItem(parentFiles.get(i));
-    parents.setSelectedIndex(parentFiles.size() - 1);
-    parents.revalidate();
-    parents.repaint();
-  }
-
-  /**
-   * DOCUMENT ME!
-   *
-   * @return DOCUMENT ME!
-   */
-  private ItemListener createBoxListener()
-  {
-    return new ItemListener()
-      {
-       public void itemStateChanged(ItemEvent e)
-       {
-         if (parents.getItemCount() - 1 == parents.getSelectedIndex())
-           return;
-         StringBuffer dir = new StringBuffer();
-         for (int i = 0; i <= parents.getSelectedIndex(); i++)
-           {
-             dir.append(parents.getItemAt(i));
-             dir.append(File.separatorChar);
-           }
-         filechooser.setCurrentDirectory(filechooser.getFileSystemView()
-                                                    .createFileObject(dir
-                                                                      
.toString()));
-       }
-      };
-  }
-
-  /**
-   * DOCUMENT ME!
-   *
-   * @return DOCUMENT ME!
-   */
-  private ItemListener createFilterListener()
-  {
-    return new ItemListener()
-      {
-       public void itemStateChanged(ItemEvent e)
-       {
-         int index = filters.getSelectedIndex();
-         if (index == -1)
-           return;
-         
filechooser.setFileFilter(filechooser.getChoosableFileFilters()[index]);
-       }
-      };
-  }
-
-  void filterEntries()
-  {
-    FileFilter[] list = filechooser.getChoosableFileFilters();
-    if (filters.getItemCount() > 0)
-      filters.removeAllItems();
-
-    int index = -1;
-    String selected = filechooser.getFileFilter().getDescription();
-    for (int i = 0; i < list.length; i++)
-      {
-       if (selected.equals(list[i].getDescription()))
-         index = i;
-       filters.addItem(list[i].getDescription());
-      }
-    filters.setSelectedIndex(index);
-    filters.revalidate();
-    filters.repaint();
-  }
+  }  
 
   /**
    * Creates and install the subcomponents for the file chooser.
@@ -1210,121 +869,6 @@
    */
   public void installComponents(JFileChooser fc)
   {
-    JLabel look = new JLabel("Look In:");
-
-    parents = new JComboBox();
-    parents.setRenderer(new BasicComboBoxRenderer());
-    boxEntries();
-    look.setLabelFor(parents);
-    JPanel parentsPanel = new JPanel();
-    parentsPanel.add(look);
-    parentsPanel.add(parents);
-    JPanel buttonPanel = new JPanel();
-
-    upFolderButton = new JButton();
-    upFolderButton.setIcon(upFolderIcon);
-    buttonPanel.add(upFolderButton);
-
-    homeFolderButton = new JButton();
-    homeFolderButton = new JButton(homeFolderIcon);
-    buttonPanel.add(homeFolderButton);
-
-    newFolderButton = new JButton();
-    newFolderButton.setIcon(newFolderIcon);
-    buttonPanel.add(newFolderButton);
-
-    ButtonGroup toggles = new ButtonGroup();
-    JToggleButton listViewButton = new JToggleButton();
-    listViewButton.setIcon(listViewIcon);
-    toggles.add(listViewButton);
-    buttonPanel.add(listViewButton);
-
-    JToggleButton detailsViewButton = new JToggleButton();
-    detailsViewButton.setIcon(detailsViewIcon);
-    toggles.add(detailsViewButton);
-    buttonPanel.add(detailsViewButton);
-
-    JPanel topPanel = new JPanel();
-    parentsPanel.add(buttonPanel);
-    topPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT, 0, 
0));
-    topPanel.add(parentsPanel);
-
-    accessoryPanel = new JPanel();
-    if (filechooser.getAccessory() != null)
-      accessoryPanel.add(filechooser.getAccessory(), BorderLayout.CENTER);
-
-    filelist = new JList(model);
-    filelist.setVisibleRowCount(6);
-    JScrollPane scrollp = new JScrollPane(filelist);
-    scrollp.setPreferredSize(new Dimension(400, 175));
-    filelist.setBackground(Color.WHITE);
-
-    filelist.setLayoutOrientation(JList.VERTICAL_WRAP);
-    filelist.setCellRenderer(new ListLabelRenderer());
-
-    GridBagConstraints c = new GridBagConstraints();
-    c.gridx = 0;
-    c.gridy = 0;
-    c.fill = GridBagConstraints.BOTH;
-    c.weightx = 1;
-    c.weighty = 1;
-
-    JPanel centrePanel = new JPanel();
-    centrePanel.setLayout(new GridBagLayout());
-    centrePanel.add(scrollp, c);
-
-    c.gridx = 1;
-    centrePanel.add(accessoryPanel, c);
-
-    JLabel fileNameLabel = new JLabel("File Name:");
-    JLabel fileTypesLabel = new JLabel("Files of Type:");
-
-    entry = new JTextField();
-    filters = new JComboBox();
-    filterEntries();
-
-    fileNameLabel.setLabelFor(entry);
-    fileNameLabel.setHorizontalTextPosition(SwingConstants.LEFT);
-    fileTypesLabel.setLabelFor(filters);
-    fileTypesLabel.setHorizontalTextPosition(SwingConstants.LEFT);
-
-    closePanel = new JPanel();
-    accept = getApproveButton(filechooser);
-    cancel = new JButton(cancelButtonText);
-    cancel.setMnemonic(cancelButtonMnemonic);
-    cancel.setToolTipText(cancelButtonToolTipText);
-    closePanel.add(accept);
-    closePanel.add(cancel);
-
-    c.anchor = GridBagConstraints.WEST;
-    c.weighty = 0;
-    c.weightx = 0;
-    c.gridx = 0;
-
-    bottomPanel = new JPanel();
-    bottomPanel.setLayout(new GridBagLayout());
-    bottomPanel.add(fileNameLabel, c);
-
-    c.gridy = 1;
-    bottomPanel.add(fileTypesLabel, c);
-    c.gridx = 1;
-    c.gridy = 0;
-    c.weightx = 1;
-    c.weighty = 1;
-    bottomPanel.add(entry, c);
-
-    c.gridy = 1;
-    bottomPanel.add(filters, c);
-
-    c.fill = GridBagConstraints.NONE;
-    c.gridy = 2;
-    c.anchor = GridBagConstraints.EAST;
-    bottomPanel.add(closePanel, c);
-
-    filechooser.setLayout(new BorderLayout());
-    filechooser.add(topPanel, BorderLayout.NORTH);
-    filechooser.add(centrePanel, BorderLayout.CENTER);
-    filechooser.add(bottomPanel, BorderLayout.SOUTH);
   }
 
   /**
@@ -1334,15 +878,6 @@
    */
   public void uninstallComponents(JFileChooser fc)
   {
-    parents = null;
-
-    accept = null;
-    cancel = null;
-    upFolderButton = null;
-    homeFolderButton = null;
-    newFolderButton = null;
-
-    filelist = null;
   }
 
   /**
@@ -1354,17 +889,6 @@
   {
     propertyChangeListener = createPropertyChangeListener(filechooser);
     filechooser.addPropertyChangeListener(propertyChangeListener);
-
-    //parents.addItemListener(createBoxListener());
-    accept.addActionListener(getApproveSelectionAction());
-    cancel.addActionListener(getCancelSelectionAction());
-    upFolderButton.addActionListener(getChangeToParentDirectoryAction());
-    homeFolderButton.addActionListener(getGoHomeAction());
-    newFolderButton.addActionListener(getNewFolderAction());
-    filters.addItemListener(createFilterListener());
-
-    filelist.addMouseListener(createDoubleClickListener(filechooser, 
filelist));
-    
filelist.addListSelectionListener(createListSelectionListener(filechooser));
   }
 
   /**
@@ -1401,24 +925,42 @@
   }
 
   /**
-   * Installs the icons for this UI delegate (NOT YET IMPLEMENTED).
+   * Installs the icons for this UI delegate.
    *
-   * @param fc  the file chooser.
+   * @param fc  the file chooser (ignored).
    */
   protected void installIcons(JFileChooser fc)
   {
-    // FIXME: Implement.
+    UIDefaults defaults = UIManager.getLookAndFeelDefaults();
+    computerIcon = MetalIconFactory.getTreeComputerIcon();
+    detailsViewIcon = defaults.getIcon("FileChooser.detailsViewIcon");
+    directoryIcon = new MetalIconFactory.TreeFolderIcon();
+    fileIcon = new MetalIconFactory.TreeLeafIcon();
+    floppyDriveIcon = MetalIconFactory.getTreeFloppyDriveIcon();
+    hardDriveIcon = MetalIconFactory.getTreeHardDriveIcon();
+    homeFolderIcon = defaults.getIcon("FileChooser.homeFolderIcon");
+    listViewIcon = defaults.getIcon("FileChooser.listViewIcon");
+    newFolderIcon = defaults.getIcon("FileChooser.newFolderIcon");
+    upFolderIcon = defaults.getIcon("FileChooser.upFolderIcon");
   }
 
   /**
-   * Uninstalls the icons previously added by this UI delegate (NOT YET
-   * IMPLEMENTED).
+   * Uninstalls the icons previously added by this UI delegate.
    *
    * @param fc  the file chooser.
    */
   protected void uninstallIcons(JFileChooser fc)
   {
-    // FIXME: Implement.
+    computerIcon = null;
+    detailsViewIcon = null;
+    directoryIcon = null;
+    fileIcon = null;
+    floppyDriveIcon = null;
+    hardDriveIcon = null;
+    homeFolderIcon = null;
+    listViewIcon = null;
+    newFolderIcon = null;
+    upFolderIcon = null;
   }
 
   /**
@@ -1428,25 +970,36 @@
    */
   protected void installStrings(JFileChooser fc)
   {
-    acceptAllFileFilterText = 
UIManager.getString("FileChooser.acceptAllFileFilterText");
-    cancelButtonMnemonic = 
UIManager.getInt("FileChooser.cancelButtonMnemonic");
-    cancelButtonText = UIManager.getString("FileChooser.cancelButtonText");
-    cancelButtonToolTipText = 
UIManager.getString("FileChooser.cancelButtonToolTipText");
-
-    dirDescText = UIManager.getString("FileChooser.directoryDescriptionText");
-    fileDescText = UIManager.getString("FileChooser.fileDescriptionText");
-
-    helpButtonMnemonic = UIManager.getInt("FileChooser.helpButtonMnemonic");
-    helpButtonText = UIManager.getString("FileChooser.helpButtonText");
-    helpButtonToolTipText = 
UIManager.getString("FileChooser.helpButtonToolTipText");
-
-    openButtonMnemonic = UIManager.getInt("FileChooser.openButtonMnemonic");
-    openButtonText = UIManager.getString("FileChooser.openButtonText");
-    openButtonToolTipText = 
UIManager.getString("FileChooser.openButtonToolTipText");
+    UIDefaults defaults = UIManager.getLookAndFeelDefaults();
+
+    dirDescText = defaults.getString("FileChooser.directoryDescriptionText");
+    fileDescText = defaults.getString("FileChooser.fileDescriptionText");
+
+    acceptAllFileFilterText = 
defaults.getString("FileChooser.acceptAllFileFilterText");
+    cancelButtonText = "Cancel";
+    cancelButtonToolTipText = "Abort file chooser dialog";
+    cancelButtonMnemonic = defaults.getInt("FileChooser.cancelButtonMnemonic");
+
+    directoryOpenButtonText = "Open";
+    directoryOpenButtonToolTipText = "Open selected directory";
+    directoryOpenButtonMnemonic 
+        = defaults.getInt("FileChooser.directoryOpenButtonMnemonic");
+    
+    helpButtonText = "Help";
+    helpButtonToolTipText = "FileChooser help";
+    helpButtonMnemonic = defaults.getInt("FileChooser.helpButtonMnemonic");
+
+    openButtonText = "Open";
+    openButtonToolTipText = "Open selected file";
+    openButtonMnemonic = defaults.getInt("FileChooser.openButtonMnemonic");
 
+    saveButtonText = "Save";
+    saveButtonToolTipText = "Save selected file";
     saveButtonMnemonic = UIManager.getInt("FileChooser.saveButtonMnemonic");
-    saveButtonText = UIManager.getString("FileChooser.saveButtonText");
-    saveButtonToolTipText = 
UIManager.getString("FileChooser.saveButtonToolTipText");
+  
+    updateButtonText = "Update";
+    updateButtonToolTipText = "Update directory listing";
+    updateButtonMnemonic = defaults.getInt("FileChooser.updateButtonMnemonic");
   }
 
   /**
@@ -1457,24 +1010,26 @@
   protected void uninstallStrings(JFileChooser fc)
   {
     acceptAllFileFilterText = null;
-    cancelButtonMnemonic = 0;
+    dirDescText = null;
+    fileDescText = null;
+
     cancelButtonText = null;
     cancelButtonToolTipText = null;
 
-    dirDescText = null;
-    fileDescText = null;
+    directoryOpenButtonText = null;
+    directoryOpenButtonToolTipText = null;
 
-    helpButtonMnemonic = 0;
     helpButtonText = null;
     helpButtonToolTipText = null;
 
-    openButtonMnemonic = 0;
     openButtonText = null;
     openButtonToolTipText = null;
 
-    saveButtonMnemonic = 0;
     saveButtonText = null;
     saveButtonToolTipText = null;
+    
+    updateButtonText = null;
+    updateButtonToolTipText = null;
   }
 
   /**
@@ -1509,110 +1064,6 @@
     {
       public void propertyChange(PropertyChangeEvent e)
       {
-        // FIXME: Multiple file selection waiting on JList multiple selection
-        // bug.
-        if (e.getPropertyName().equals(
-                                       
JFileChooser.SELECTED_FILE_CHANGED_PROPERTY))
-          {
-            if (filechooser.getSelectedFile() == null)
-              setFileName(null);
-            else
-              setFileName(filechooser.getSelectedFile().toString());
-            int index = -1;
-            File file = filechooser.getSelectedFile();
-            for (index = 0; index < model.getSize(); index++)
-              if (((File) model.getElementAt(index)).equals(file))
-                break;
-            if (index == -1)
-              return;
-            filelist.setSelectedIndex(index);
-            filelist.ensureIndexIsVisible(index);
-            filelist.revalidate();
-            filelist.repaint();
-          }
-        else if (e.getPropertyName().equals(
-                                            
JFileChooser.DIRECTORY_CHANGED_PROPERTY))
-          {
-            filelist.clearSelection();
-            filelist.revalidate();
-            filelist.repaint();
-            setDirectorySelected(false);
-            setDirectory(filechooser.getCurrentDirectory());
-            boxEntries();
-          }
-        else if (e.getPropertyName().equals(
-                                            
JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY)
-                 || e.getPropertyName().equals(
-                                               
JFileChooser.FILE_FILTER_CHANGED_PROPERTY))
-          filterEntries();
-        else if (e.getPropertyName().equals(
-                                            
JFileChooser.DIALOG_TYPE_CHANGED_PROPERTY)
-                 || e.getPropertyName().equals(
-                                               
JFileChooser.DIALOG_TITLE_CHANGED_PROPERTY))
-          {
-            Window owner = SwingUtilities.windowForComponent(filechooser);
-            if (owner instanceof JDialog)
-              ((JDialog) owner).setTitle(getDialogTitle(filechooser));
-            accept.setText(getApproveButtonText(filechooser));
-            accept.setToolTipText(getApproveButtonToolTipText(filechooser));
-            accept.setMnemonic(getApproveButtonMnemonic(filechooser));
-          }
-        else if (e.getPropertyName().equals(
-                                            
JFileChooser.APPROVE_BUTTON_TEXT_CHANGED_PROPERTY))
-          accept.setText(getApproveButtonText(filechooser));
-        else if (e.getPropertyName().equals(
-                                            
JFileChooser.APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY))
-          accept.setToolTipText(getApproveButtonToolTipText(filechooser));
-        else if (e.getPropertyName().equals(
-                                            
JFileChooser.APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY))
-          accept.setMnemonic(getApproveButtonMnemonic(filechooser));
-        else if (e.getPropertyName().equals(
-                                            
JFileChooser.CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY))
-          {
-            if (filechooser.getControlButtonsAreShown())
-              {
-                GridBagConstraints c = new GridBagConstraints();
-                c.gridy = 1;
-                bottomPanel.add(filters, c);
-
-                c.fill = GridBagConstraints.BOTH;
-                c.gridy = 2;
-                c.anchor = GridBagConstraints.EAST;
-                bottomPanel.add(closePanel, c);
-                bottomPanel.revalidate();
-                bottomPanel.repaint();
-                bottomPanel.doLayout();
-              }
-            else
-              bottomPanel.remove(closePanel);
-          }
-        else if (e.getPropertyName().equals(
-                                            
JFileChooser.ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY))
-          {
-            if (filechooser.isAcceptAllFileFilterUsed())
-              
filechooser.addChoosableFileFilter(getAcceptAllFileFilter(filechooser));
-            else
-              
filechooser.removeChoosableFileFilter(getAcceptAllFileFilter(filechooser));
-          }
-        else if (e.getPropertyName().equals(
-                                            
JFileChooser.ACCESSORY_CHANGED_PROPERTY))
-          {
-            JComponent old = (JComponent) e.getOldValue();
-            if (old != null)
-              getAccessoryPanel().remove(old);
-            JComponent newval = (JComponent) e.getNewValue();
-            if (newval != null)
-              getAccessoryPanel().add(newval);
-          }
-        if (e.getPropertyName().equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)
-            || e.getPropertyName().equals(
-                                          
JFileChooser.FILE_FILTER_CHANGED_PROPERTY)
-            || e.getPropertyName().equals(
-                                          
JFileChooser.FILE_HIDING_CHANGED_PROPERTY))
-          rescanCurrentDirectory(filechooser);
-
-        filechooser.revalidate();
-        filechooser.repaint();
       }
     };
   }
@@ -1624,7 +1075,9 @@
    */
   public String getFileName()
   {
-    return filename;
+    // FIXME: I'm thinking that this method just provides access to the
+    // text value in the JTextField component...but not sure yet
+    return null;  //filename;
   }
 
   /**
@@ -1649,7 +1102,9 @@
    */
   public void setFileName(String filename)
   {
-    this.filename = filename;
+    // FIXME:  it might be the case that this method provides an access 
+    // point for the JTextField (or whatever) a subclass is using...
+    //this.filename = filename;
   }
 
   /**
@@ -1672,7 +1127,6 @@
   public void rescanCurrentDirectory(JFileChooser fc)
   {
     getModel().validateFileCache();
-    filelist.revalidate();
   }
 
   /**
@@ -1708,17 +1162,14 @@
   }
 
   /**
-   * Creates and returns an approve (open or save) button for the dialog.
+   * Returns the approve (open or save) button for the dialog.
    *
    * @param fc  the file chooser.
    *
    * @return The button.
    */
-  public JButton getApproveButton(JFileChooser fc)
+  protected JButton getApproveButton(JFileChooser fc)
   {
-    accept = new JButton(getApproveButtonText(fc));
-    accept.setMnemonic(getApproveButtonMnemonic(fc));
-    accept.setToolTipText(getApproveButtonToolTipText(fc));
     return accept;
   }
 
@@ -1830,9 +1281,8 @@
   }
 
   /**
-   * Returns the file view for the file chooser.  This returns either the
-   * file view that has been explicitly set for the address@hidden 
JFileChooser}, or
-   * a default file view.
+   * Returns the default file view (NOT the file view from the file chooser,
+   * if there is one).
    *
    * @param fc  the file chooser component.
    *
@@ -1856,24 +1306,10 @@
    */
   public String getDialogTitle(JFileChooser fc)
   {
-    String ret = fc.getDialogTitle();
-    if (ret != null)
-      return ret;
-    switch (fc.getDialogType())
-      {
-      case JFileChooser.OPEN_DIALOG:
-       ret = openButtonText;
-       break;
-      case JFileChooser.SAVE_DIALOG:
-       ret = saveButtonText;
-       break;
-      default:
-       ret = fc.getApproveButtonText();
-       break;
-      }
-    if (ret == null)
-      ret = openButtonText;
-    return ret;
+    String result = fc.getDialogTitle();
+    if (result == null)
+      result = getApproveButtonText(fc);
+    return result;
   }
 
   /**
@@ -1906,23 +1342,28 @@
    */
   public String getApproveButtonText(JFileChooser fc)
   {
-    if (fc.getApproveButtonText() != null)
-      return fc.getApproveButtonText();
-    else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG)
-      return saveButtonText;
-    else
-      return openButtonText;
+    String result = fc.getApproveButtonText();
+    if (result == null)
+      {
+        if (fc.getDialogType() == JFileChooser.SAVE_DIALOG)
+          result = saveButtonText;
+        else
+          result = openButtonText;
+      }
+    return result;
   }
 
   /**
    * Creates and returns a new action that will be used with the "new folder" 
    * button.
    *
-   * @return A new instance of address@hidden GoHomeAction}.
+   * @return A new instance of address@hidden NewFolderAction}.
    */
   public Action getNewFolderAction()
   {
-    return new NewFolderAction();
+    if (newFolderAction == null)
+      newFolderAction = new NewFolderAction();
+    return newFolderAction;
   }
 
   /**
@@ -1933,49 +1374,56 @@
    */
   public Action getGoHomeAction()
   {
-    return new GoHomeAction();
+    if (goHomeAction == null)
+      goHomeAction = new GoHomeAction();
+    return goHomeAction;
   }
 
   /**
-   * Creates and returns a new action that will be used with the "up folder" 
-   * button.
+   * Returns the action that handles events for the "up folder" control button.
    *
-   * @return A new instance of address@hidden ChangeToParentDirectoryAction}.
+   * @return An instance of address@hidden ChangeToParentDirectoryAction}.
    */
   public Action getChangeToParentDirectoryAction()
   {
-    return new ChangeToParentDirectoryAction();
+    if (changeToParentDirectoryAction == null)
+      changeToParentDirectoryAction = new ChangeToParentDirectoryAction();
+    return changeToParentDirectoryAction;
   }
 
   /**
-   * Creates and returns a new action that will be used with the "approve" 
-   * button.
+   * Returns the action that handles events for the "approve" button.
    *
-   * @return A new instance of address@hidden ApproveSelectionAction}.
+   * @return An instance of address@hidden ApproveSelectionAction}.
    */
   public Action getApproveSelectionAction()
   {
-    return new ApproveSelectionAction();
+    if (approveSelectionAction == null)
+      approveSelectionAction = new ApproveSelectionAction();
+    return approveSelectionAction;
   }
 
   /**
-   * Creates and returns a new action that will be used with the "cancel" 
-   * button.
+   * Returns the action that handles events for the "cancel" button.
    *
-   * @return A new instance of address@hidden CancelSelectionAction}.
+   * @return An instance of address@hidden CancelSelectionAction}.
    */
   public Action getCancelSelectionAction()
   {
-    return new CancelSelectionAction();
+    if (cancelSelectionAction == null)
+      cancelSelectionAction = new CancelSelectionAction();
+    return cancelSelectionAction;
   }
 
   /**
-   * Creates and returns a new instance of address@hidden UpdateAction}.
+   * Returns the update action (an instance of address@hidden UpdateAction}).
    *
    * @return An action. 
    */
   public Action getUpdateAction()
   {
-    return new UpdateAction();
+    if (updateAction == null)
+      updateAction = new UpdateAction();
+    return updateAction;
   }
 }
Index: javax/swing/plaf/metal/MetalFileChooserUI.java
===================================================================
RCS file: 
/cvsroot/classpath/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java,v
retrieving revision 1.3
diff -u -r1.3 MetalFileChooserUI.java
--- javax/swing/plaf/metal/MetalFileChooserUI.java      19 Oct 2005 13:46:02 
-0000      1.3
+++ javax/swing/plaf/metal/MetalFileChooserUI.java      25 Nov 2005 10:21:11 
-0000
@@ -38,8 +38,17 @@
 
 package javax.swing.plaf.metal;
 
+import java.awt.BorderLayout;
 import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.GridLayout;
+import java.awt.Insets;
+import java.awt.LayoutManager;
+import java.awt.Window;
 import java.awt.event.ActionEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.io.File;
@@ -47,12 +56,26 @@
 
 import javax.swing.AbstractAction;
 import javax.swing.AbstractListModel;
+import javax.swing.ActionMap;
+import javax.swing.BorderFactory;
+import javax.swing.ButtonGroup;
 import javax.swing.ComboBoxModel;
 import javax.swing.DefaultListCellRenderer;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
 import javax.swing.JComponent;
+import javax.swing.JDialog;
 import javax.swing.JFileChooser;
+import javax.swing.JLabel;
 import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.JToggleButton;
+import javax.swing.SwingUtilities;
 import javax.swing.UIManager;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
 import javax.swing.filechooser.FileFilter;
 import javax.swing.filechooser.FileSystemView;
 import javax.swing.filechooser.FileView;
@@ -64,13 +87,147 @@
  * A UI delegate for the address@hidden JFileChooser} component.  This class 
is only
  * partially implemented and is not usable yet.
  */
-public class MetalFileChooserUI extends BasicFileChooserUI
+public class MetalFileChooserUI 
+  extends BasicFileChooserUI
 {
+  
+  /**
+   * A property change listener.
+   */
+  class MetalFileChooserPropertyChangeListener 
+    implements PropertyChangeListener
+  {
+    /**
+     * Default constructor.
+     */
+    public MetalFileChooserPropertyChangeListener()
+    {
+    }
+    
+    /**
+     * Handles a property change event.
+     * 
+     * @param e  the event.
+     */
+    public void propertyChange(PropertyChangeEvent e)
+    {
+      JFileChooser filechooser = getFileChooser();
+      // FIXME: Multiple file selection waiting on JList multiple selection
+      // bug.
+      String n = e.getPropertyName();
+
+      if (n.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY))
+        {
+          File file = filechooser.getSelectedFile();
+          if (file == null)
+            setFileName(null);
+          else
+            setFileName(file.getName());
+          int index = -1;
+          index = getModel().indexOf(file);
+          if (index >= 0)
+            {
+              fileList.setSelectedIndex(index);
+              fileList.ensureIndexIsVisible(index);
+              fileList.revalidate();
+              fileList.repaint();
+            }
+        }
+      
+      else if (n.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY))
+        {
+          fileList.clearSelection();
+          fileList.revalidate();
+          fileList.repaint();
+          setDirectorySelected(false);
+          File currentDirectory = filechooser.getCurrentDirectory();
+          setDirectory(currentDirectory);
+          boolean hasParent = (currentDirectory.getParentFile() != null);
+          getChangeToParentDirectoryAction().setEnabled(hasParent);
+          //boxEntries();
+        }
+      
+      else if (n.equals(JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY))
+        {
+          filterModel.propertyChange(e);
+        }
+      else if (n.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY))
+        {
+          filterModel.propertyChange(e);
+        }
+      else if (n.equals(JFileChooser.DIALOG_TYPE_CHANGED_PROPERTY)
+                 || n.equals(JFileChooser.DIALOG_TITLE_CHANGED_PROPERTY))
+        {
+          Window owner = SwingUtilities.windowForComponent(filechooser);
+          if (owner instanceof JDialog)
+            ((JDialog) owner).setTitle(getDialogTitle(filechooser));
+          approveButton.setText(getApproveButtonText(filechooser));
+          approveButton.setToolTipText(
+                  getApproveButtonToolTipText(filechooser));
+          approveButton.setMnemonic(getApproveButtonMnemonic(filechooser));
+        }
+      
+      else if (n.equals(JFileChooser.APPROVE_BUTTON_TEXT_CHANGED_PROPERTY))
+        approveButton.setText(getApproveButtonText(filechooser));
+      
+      else if (n.equals(
+              JFileChooser.APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY))
+        approveButton.setToolTipText(getApproveButtonToolTipText(filechooser));
+      
+      else if (n.equals(JFileChooser.APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY))
+        approveButton.setMnemonic(getApproveButtonMnemonic(filechooser));
+
+      else if (n.equals(
+              JFileChooser.CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY))
+        {
+          if (filechooser.getControlButtonsAreShown())
+            {
+              topPanel.add(controls, BorderLayout.EAST);
+            }
+          else
+            topPanel.remove(controls);
+          topPanel.revalidate();
+          topPanel.repaint();
+          topPanel.doLayout();
+        }
+      
+      else if (n.equals(
+              JFileChooser.ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY))
+        {
+          if (filechooser.isAcceptAllFileFilterUsed())
+            filechooser.addChoosableFileFilter(
+                    getAcceptAllFileFilter(filechooser));
+          else
+            filechooser.removeChoosableFileFilter(
+                    getAcceptAllFileFilter(filechooser));
+        }
+      
+      else if (n.equals(JFileChooser.ACCESSORY_CHANGED_PROPERTY))
+        {
+          JComponent old = (JComponent) e.getOldValue();
+          if (old != null)
+            getAccessoryPanel().remove(old);
+          JComponent newval = (JComponent) e.getNewValue();
+          if (newval != null)
+            getAccessoryPanel().add(newval);
+        }
+      
+      if (n.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)
+          || n.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)
+          || n.equals(JFileChooser.FILE_HIDING_CHANGED_PROPERTY))
+        rescanCurrentDirectory(filechooser);
+      
+      filechooser.revalidate();
+      filechooser.repaint();
+    }
+  };
+  
   /** 
    * A combo box model containing the selected directory and all its parent
    * directories.
    */
-  protected class DirectoryComboBoxModel extends AbstractListModel
+  protected class DirectoryComboBoxModel
+    extends AbstractListModel
     implements ComboBoxModel
   {
     /** Storage for the items in the model. */
@@ -161,7 +318,8 @@
   /**
    * Handles changes to the selection in the directory combo box.
    */
-  protected class DirectoryComboBoxAction extends AbstractAction
+  protected class DirectoryComboBoxAction
+    extends AbstractAction
   {
     /**
      * Creates a new action.
@@ -184,9 +342,62 @@
   }
 
   /**
+   * A renderer for the items in the directory combo box.
+   */
+  class DirectoryComboBoxRenderer
+    extends DefaultListCellRenderer
+  {
+    /**
+     * Creates a new renderer.
+     */
+    public DirectoryComboBoxRenderer(JFileChooser fc)
+    { 
+    }
+    
+    /**
+     * Returns a component that can be used to paint the given value within 
+     * the list.
+     * 
+     * @param list  the list.
+     * @param value  the value (a address@hidden File}).
+     * @param index  the item index.
+     * @param isSelected  is the item selected?
+     * @param cellHasFocus  does the list cell have focus?
+     * 
+     * @return The list cell renderer.
+     */
+    public Component getListCellRendererComponent(JList list, Object value,
+        int index, boolean isSelected, boolean cellHasFocus)
+    {
+      FileView fileView = getFileView(getFileChooser());
+      File file = (File) value;
+      setIcon(fileView.getIcon(file));
+      setText(fileView.getName(file));
+      
+      // FIXME: we can't go creating a new border here every time...
+      //setBorder(BorderFactory.createEmptyBorder(0, index * 8, 0, 0));
+      if (isSelected)
+        {
+          setBackground(list.getSelectionBackground());
+          setForeground(list.getSelectionForeground());
+        }
+      else
+        {
+          setBackground(list.getBackground());
+          setForeground(list.getForeground());
+        }
+
+      setEnabled(list.isEnabled());
+      setFont(list.getFont());
+      return this;
+    }
+  }
+
+  /**
    * A renderer for the files and directories in the file chooser.
    */
-  protected class FileRenderer extends DefaultListCellRenderer
+  protected class FileRenderer
+    extends DefaultListCellRenderer
   {
     
     /**
@@ -249,7 +460,7 @@
     protected FileFilter[] filters;
 
     /** The index of the selected file filter. */
-    private int selectedIndex;
+    private Object selected;
     
     /**
      * Creates a new model.
@@ -258,7 +469,7 @@
     {
       filters = new FileFilter[1];
       filters[0] = getAcceptAllFileFilter(getFileChooser());
-      selectedIndex = 0;
+      selected = filters[0];
     }
     
     /**
@@ -270,11 +481,11 @@
     {
       if 
(e.getPropertyName().equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY))
         {
-          selectedIndex = -1;
-          FileFilter selected = (FileFilter) e.getNewValue();
-          for (int i = 0; i < filters.length; i++)
-            if (filters[i].equals(selected))
-              selectedIndex = i;
+          JFileChooser fc = getFileChooser();
+          FileFilter[] choosableFilters = fc.getChoosableFileFilters();
+          filters = choosableFilters;
+          fireContentsChanged(this, 0, filters.length);
+          selected = e.getNewValue();
           fireContentsChanged(this, -1, -1);
         }
       else if (e.getPropertyName().equals(
@@ -291,13 +502,15 @@
     /**
      * Sets the selected filter.
      * 
-     * @param filter  the filter.
+     * @param filter  the filter (<code>null</code> ignored).
      */
     public void setSelectedItem(Object filter)
     {
-      // change the filter in the file chooser and let the property change
-      // event trigger the change to the selected item
-      getFileChooser().setFileFilter((FileFilter) filter);
+      if (filter != null)
+      {
+          selected = filter;
+          fireContentsChanged(this, -1, -1);
+      }
     }
     
     /**
@@ -307,9 +520,7 @@
      */
     public Object getSelectedItem()
     {
-      if (selectedIndex >= 0) 
-        return filters[selectedIndex];
-      return null;
+      return selected;
     }
     
     /**
@@ -339,7 +550,8 @@
   /**
    * A renderer for the items in the file filter combo box.
    */
-  public class FilterComboBoxRenderer extends DefaultListCellRenderer
+  public class FilterComboBoxRenderer
+    extends DefaultListCellRenderer
   {
     /**
      * Creates a new renderer.
@@ -359,20 +571,126 @@
      * @param isSelected  is the item selected?
      * @param cellHasFocus  does the list cell have focus?
      * 
-     * @return A component.
+     * @return This component as the renderer.
      */
     public Component getListCellRendererComponent(JList list, Object value,
         int index, boolean isSelected, boolean cellHasFocus)
     {
+      super.getListCellRendererComponent(list, value, index, isSelected, 
+                                         cellHasFocus);
       FileFilter filter = (FileFilter) value;
-      return super.getListCellRendererComponent(list, filter.getDescription(),
-              index, isSelected, cellHasFocus);
+      setText(filter.getDescription());
+      return this;
     }
   }
 
+  /**
+   * A listener for selection events in the file list.
+   * 
+   * @see #createListSelectionListener(JFileChooser)
+   */
+  class MetalFileChooserSelectionListener 
+    implements ListSelectionListener
+  {
+    /**
+     * Creates a new <code>SelectionListener</code> object.
+     */
+    protected MetalFileChooserSelectionListener()
+    {
+    }
+
+    /**
+     * DOCUMENT ME!
+     *
+     * @param e DOCUMENT ME!
+     */
+    public void valueChanged(ListSelectionEvent e)
+    {
+      File f = (File) fileList.getSelectedValue();
+      if (f == null)
+        return;
+      JFileChooser filechooser = getFileChooser();
+      if (! filechooser.isTraversable(f))
+        filechooser.setSelectedFile(f);
+      else
+        filechooser.setSelectedFile(null);
+    }
+  }
+
+  /**
+   * A mouse listener for the address@hidden JFileChooser}.  This class is not 
yet
+   * implemented.
+   */
+  protected class SingleClickListener
+    extends MouseAdapter
+  {
+    /**
+     * Creates a new listener.
+     * 
+     * @param list  the directory/file list.
+     */
+    public SingleClickListener(JList list)
+    {
+      // FIXME: implement
+    }
+    
+    /**
+     * Receives notification of a mouse click event.
+     * 
+     * @param e  the event.
+     */
+    public void mouseClicked(MouseEvent e)
+    {
+      // FIXME: implement
+    }
+  }
+
+  /** The text for a label describing the directory combo box. */
+  private String directoryLabel;
+  
+  private JComboBox directoryComboBox;
+  
   /** The model for the directory combo box. */
   DirectoryComboBoxModel directoryModel;
   
+  /** The text for a label describing the file text field. */
+  private String fileLabel;
+  
+  /** The file name text field. */
+  private JTextField fileTextField;
+  
+  /** The text for a label describing the filter combo box. */
+  private String filterLabel;
+
+  /** 
+   * The top panel (contains the directory combo box and the control buttons). 
+   */
+  private JPanel topPanel;
+  
+  /** A panel containing the control buttons ('up', 'home' etc.). */
+  private JPanel controls;
+
+  /** 
+   * The panel that contains the filename field and the filter combobox. 
+   */
+  private JPanel bottomPanel;
+
+  /** 
+   * The panel that contains the 'Open' (or 'Save') and 'Cancel' buttons. 
+   */
+  private JPanel buttonPanel;
+  
+  private JButton approveButton;
+  
+  /** The file list. */
+  private JList fileList;
+  
+  /** The panel containing the file list. */
+  private JPanel fileListPanel;
+  
+  /** The filter combo box model. */
+  private FilterComboBoxModel filterModel;
+  
   /**
    * A factory method that returns a UI delegate for the specified
    * component.
@@ -393,9 +711,304 @@
   public MetalFileChooserUI(JFileChooser filechooser)
   {
     super(filechooser);
+    bottomPanel = new JPanel(new GridLayout(3, 2));
+    buttonPanel = new JPanel();
+  }
+
+  public void installUI(JComponent c)
+  {
+    // FIXME: do something here
+    super.installUI(c);
+  }
+  
+  public void uninstallUI(JComponent c)
+  {
+    // FIXME: do something here
+    super.uninstallUI(c);
+  }
+  
+  /**
+   * Installs the sub-components of the file chooser.
+   * 
+   * @param fc  the file chooser component.
+   */
+  public void installComponents(JFileChooser fc)
+  {
+    fc.setLayout(new BorderLayout());
+    topPanel = new JPanel(new BorderLayout());
+    topPanel.add(new JLabel(directoryLabel), BorderLayout.WEST);
+    this.controls = new JPanel();
+    addControlButtons();
+    
+    JPanel dirPanel = new JPanel(new VerticalMidLayout());
+    dirPanel.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0));
+    directoryModel = createDirectoryComboBoxModel(fc);
+    directoryComboBox = new JComboBox(directoryModel);
+    directoryComboBox.setRenderer(createDirectoryComboBoxRenderer(fc));
+    dirPanel.add(directoryComboBox);
+    topPanel.add(dirPanel);
+    topPanel.add(controls, BorderLayout.EAST);
+    fc.add(topPanel, BorderLayout.NORTH);
+    fileListPanel = createList(fc);
+    fc.add(fileListPanel);
+    JPanel bottomPanel = getBottomPanel();
+    filterModel = createFilterComboBoxModel();
+    JComboBox fileFilterCombo = new JComboBox(filterModel);
+    fileFilterCombo.setRenderer(createFilterComboBoxRenderer());
+    
+    fileTextField = new JTextField();
+    JPanel fileNamePanel = new JPanel(new VerticalMidLayout());
+    fileNamePanel.add(fileTextField);
+    JPanel row1 = new JPanel(new BorderLayout());
+    row1.add(new JLabel(this.fileLabel), BorderLayout.WEST);
+    row1.add(fileNamePanel);
+    bottomPanel.add(row1);
+    
+    JPanel filterPanel = new JPanel(new VerticalMidLayout());
+    filterPanel.add(fileFilterCombo);    
+    JPanel row2 = new JPanel(new BorderLayout());
+    row2.add(new JLabel(this.filterLabel), BorderLayout.WEST);
+    row2.add(filterPanel);
+    bottomPanel.add(row2);
+    JPanel buttonPanel = new JPanel(new ButtonLayout());
+    buttonPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 0));
+    
+    approveButton = new JButton(getApproveSelectionAction());
+    approveButton.setText(getApproveButtonText(fc));
+    approveButton.setToolTipText(getApproveButtonToolTipText(fc));
+    approveButton.setMnemonic(getApproveButtonMnemonic(fc));
+    buttonPanel.add(approveButton);
+    
+    JButton cancelButton = new JButton(getCancelSelectionAction());
+    cancelButton.setText(cancelButtonText);
+    cancelButton.setToolTipText(cancelButtonToolTipText);
+    cancelButton.setMnemonic(cancelButtonMnemonic);
+    buttonPanel.add(cancelButton);
+    bottomPanel.add(buttonPanel);
+    fc.add(bottomPanel, BorderLayout.SOUTH);
+  }
+  
+  /**
+   * Uninstalls the components added by 
+   * address@hidden #installComponents(JFileChooser)}.
+   * 
+   * @param fc  the file chooser.
+   */
+  public void uninstallComponents(JFileChooser fc)
+  {
+    fc.remove(bottomPanel);
+    bottomPanel = null;
+    fc.remove(fileListPanel);
+    fileListPanel = null;
+    fc.remove(topPanel);
+    topPanel = null;
+    
+    directoryModel = null;
+    fileTextField = null;
+    directoryComboBox = null;
+  }
+  
+  /**
+   * Returns the panel that contains the 'Open' (or 'Save') and 'Cancel' 
+   * buttons.
+   * 
+   * @return The panel.
+   */
+  protected JPanel getButtonPanel()
+  {
+    return buttonPanel;    
   }
   
   /**
+   * Creates and returns a new panel that will be used for the controls at
+   * the bottom of the file chooser.
+   * 
+   * @return A new panel.
+   */
+  protected JPanel getBottomPanel()
+  {
+    if (bottomPanel == null)
+      bottomPanel = new JPanel(new GridLayout(3, 2));
+    return bottomPanel;
+  }
+  
+  /**
+   * Fetches localised strings for use by the labels and buttons on the
+   * file chooser.
+   * 
+   * @param fc  the file chooser.
+   */
+  protected void installStrings(JFileChooser fc)
+  { 
+     super.installStrings(fc);
+     directoryLabel = "Look In: ";  // FIXME: localise
+     fileLabel = "File Name: ";  // FIXME: localise
+     filterLabel = "Files of Type: ";  // FIXME: localise
+     
+     this.cancelButtonMnemonic = 0;
+     this.cancelButtonText = "Cancel";
+     this.cancelButtonToolTipText = "Cancel ToolTip Text";
+     
+     this.directoryOpenButtonMnemonic = 0;
+     this.directoryOpenButtonText = "Open";
+     this.directoryOpenButtonToolTipText = "Open ToolTip Text";
+     
+     this.helpButtonMnemonic = 0;
+     this.helpButtonText = "Help";
+     this.helpButtonToolTipText = "Help";
+     
+     this.openButtonMnemonic = 0;
+     this.openButtonText = "Open";
+     this.openButtonToolTipText = "Open ToolTip Text";
+     
+     this.saveButtonMnemonic = 0;
+     this.saveButtonText = "Save";
+     this.saveButtonToolTipText = "Save ToolTip Text";
+     
+     this.updateButtonMnemonic = 0;
+     this.updateButtonText = "Update";
+     this.updateButtonToolTipText = "Update ToolTip Text";   
+  }
+  
+  /**
+   * Installs the listeners required.
+   * 
+   * @param fc  the file chooser.
+   */
+  protected void installListeners(JFileChooser fc)
+  {
+    directoryComboBox.setAction(new DirectoryComboBoxAction());
+    fileList.addListSelectionListener(createListSelectionListener(fc));
+    fileList.addMouseListener(this.createDoubleClickListener(fc, fileList));
+    fileList.addMouseListener(new SingleClickListener(fileList));
+    fc.addPropertyChangeListener(filterModel);
+    super.installListeners(fc);
+  }
+  
+  protected void uninstallListeners(JFileChooser fc) 
+  {
+    super.uninstallListeners(fc);
+    fc.removePropertyChangeListener(filterModel);
+  }
+  
+  protected ActionMap getActionMap()
+  {
+    // FIXME: implement this
+    return null;
+  }
+  
+  /**
+   * Creates and returns an action map.
+   * 
+   * @return The action map.
+   */
+  protected ActionMap createActionMap()
+  {
+    ActionMap map = new ActionMap();
+    map.put("approveSelection", getApproveSelectionAction());
+    map.put("cancelSelection", null);  // FIXME: implement this one
+    map.put("Go Up", getChangeToParentDirectoryAction());
+    return map;
+  }
+
+  /**
+   * Creates a panel containing a list of files.
+   * 
+   * @param fc  the file chooser.
+   * 
+   * @return A panel.
+   */
+  protected JPanel createList(JFileChooser fc)
+  {
+    JPanel panel = new JPanel(new BorderLayout());
+    fileList = new JList(getModel());
+    // a bug is preventing the vertical wrap from working right now,
+    // uncomment the next line once that is fixed...
+    //fileList.setLayoutOrientation(JList.VERTICAL_WRAP);
+    fileList.setVisibleRowCount(0);
+    fileList.setCellRenderer(new FileRenderer());
+    panel.add(new JScrollPane(fileList));
+    return panel;    
+  }
+  
+  /**
+   * Creates a panel containing a table within a scroll pane.
+   * 
+   * @param fc  the file chooser.
+   * 
+   * @return The details view.
+   */
+  protected JPanel createDetailsView(JFileChooser fc)
+  {
+    // FIXME: implement this.  The details view is a panel containing a table
+    // inside a JScrollPane - it gets displayed when the user clicks on the
+    // "details" button.
+    return new JPanel();
+  }
+  
+  /**
+   * Creates a listener that monitors selections in the directory/file list
+   * and keeps the address@hidden JFileChooser} component up to date.
+   * 
+   * @param fc  the file chooser.
+   * 
+   * @return The listener.
+   * 
+   * @see #installListeners(JFileChooser)
+   */
+  public ListSelectionListener createListSelectionListener(JFileChooser fc)
+  {
+    return new MetalFileChooserSelectionListener();
+  }
+  
+  /**
+   * Returns the preferred size for the file chooser component.
+   * 
+   * @return The preferred size.
+   */
+  public Dimension getPreferredSize(JComponent c)
+  {
+    // FIXME: not likely to be a fixed value
+    return new Dimension(500, 326);
+  }
+  
+  /**
+   * Returns the minimum size for the file chooser component.
+   * 
+   * @return The minimum size.
+   */
+  public Dimension getMinimumSize(JComponent c)
+  {
+    // FIXME: not likely to be a fixed value
+    return new Dimension(506, 326);      
+  }
+  
+  /**
+   * Returns the maximum size for the file chooser component.
+   * 
+   * @return The maximum size.
+   */
+  public Dimension getMaximumSize(JComponent c)
+  {
+    return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
+  }
+  
+  /**
+   * Creates a property change listener that monitors the address@hidden 
JFileChooser}
+   * for property change events and updates the component display accordingly.
+   * 
+   * @param fc  the file chooser.
+   * 
+   * @return The property change listener.
+   * 
+   * @see #installListeners(JFileChooser)
+   */
+  public PropertyChangeListener createPropertyChangeListener(JFileChooser fc)
+  {
+    return new MetalFileChooserPropertyChangeListener();
+  }
+
+  /**
    * Creates and returns a new instance of address@hidden 
DirectoryComboBoxModel}.
    * 
    * @return A new instance of address@hidden DirectoryComboBoxModel}.
@@ -407,6 +1020,20 @@
   }
 
   /**
+   * Creates a new instance of the renderer used in the directory
+   * combo box.
+   * 
+   * @param fc  the file chooser.
+   * 
+   * @return The renderer.
+   */
+  protected DirectoryComboBoxRenderer createDirectoryComboBoxRenderer(
+          JFileChooser fc)
+  {
+    return new DirectoryComboBoxRenderer(fc);
+  }
+
+  /**
    * Creates and returns a new instance of address@hidden FilterComboBoxModel}.
    * 
    * @return A new instance of address@hidden FilterComboBoxModel}.
@@ -425,6 +1052,307 @@
       createFilterComboBoxRenderer()
   {
     return new FilterComboBoxRenderer(); 
+  }
+
+  /**
+   * Adds the control buttons ('up', 'home' etc.) to the panel.
+   */
+  protected void addControlButtons()
+  {
+    JButton upButton = new JButton(getChangeToParentDirectoryAction());
+    upButton.setText(null);
+    upButton.setIcon(this.upFolderIcon);
+    upButton.setMargin(new Insets(0, 0, 0, 0));
+    controls.add(upButton);
+    
+    JButton homeButton = new JButton(getGoHomeAction());
+    homeButton.setText(null);
+    homeButton.setIcon(this.homeFolderIcon);
+    homeButton.setMargin(new Insets(0, 0, 0, 0));
+    controls.add(homeButton);
+    
+    JButton newFolderButton = new JButton(getNewFolderAction());
+    newFolderButton.setText(null);
+    newFolderButton.setIcon(this.newFolderIcon);
+    newFolderButton.setMargin(new Insets(0, 0, 0, 0));
+    controls.add(newFolderButton);
+    
+    JToggleButton listButton = new JToggleButton();
+    listButton.setIcon(this.listViewIcon);
+    listButton.setMargin(new Insets(0, 0, 0, 0));
+    // FIXME: this button needs an action that handles a click
+    controls.add(listButton);
+    
+    JToggleButton detailButton = new JToggleButton(this.detailsViewIcon);
+    detailButton.setMargin(new Insets(0, 0, 0, 0));
+    // FIXME: this button needs an action that handles a click
+    controls.add(detailButton);
+
+    ButtonGroup buttonGroup = new ButtonGroup();
+    buttonGroup.add(listButton);
+    buttonGroup.add(detailButton);
+  }
+  
+  protected void removeControlButtons()
+  {
+    // FIXME: implement this
+  }
+  
+  public void ensureFileIsVisible(JFileChooser fc, File f)
+  {
+    // FIXME: do something here - probably this figures out whether the
+    // list or table view is current, and forwards the request to the 
+    // appropriate one...
+    super.ensureFileIsVisible(fc, f);
+  }
+  
+  public void rescanCurrentDirectory(JFileChooser fc)
+  {
+    // FIXME: this will need to take into account whether the list view or
+    // the table view is current
+    directoryModel.setSelectedItem(fc.getCurrentDirectory());
+    getModel().validateFileCache();
+    fileList.revalidate();
+  }
+  
+  /**
+   * Returns the file name in the text field.
+   * 
+   * @return The file name.
+   */
+  public String getFileName()
+  {
+    String result = null;
+    if (fileTextField != null) 
+      result = fileTextField.getText();
+    return result;
+  }
+  
+  /**
+   * Sets the file name in the text field.
+   * 
+   * @param filename  the file name.
+   */
+  public void setFileName(String filename)
+  {
+    fileTextField.setText(filename);
+  }
+
+  protected void setDirectorySelected(boolean directorySelected)
+  {
+    // FIXME: do something here
+    super.setDirectorySelected(directorySelected);
+  }
+  
+  public String getDirectoryName()
+  {
+    // FIXME: do something here
+    return super.getDirectoryName();      
+  }
+
+  public void setDirectoryName(String dirname)
+  {
+    // FIXME: do something here
+    super.setDirectoryName(dirname);    
+  }
+  
+  public void valueChanged(ListSelectionEvent e)
+  {
+    // FIXME: implement
+  }
+  
+  /**
+   * Returns the approve button.
+   * 
+   * @return The approve button.
+   */
+  protected JButton getApproveButton(JFileChooser fc)
+  {
+    return approveButton;
+  }
+
+  /**
+   * A layout manager that is used to arrange the subcomponents of the
+   * address@hidden JFileChooser}.
+   */
+  class VerticalMidLayout implements LayoutManager
+  {
+    /**
+     * Performs the layout.
+     * 
+     * @param parent  the container.
+     */
+    public void layoutContainer(Container parent) 
+    {
+      int count = parent.getComponentCount();
+      if (count > 0)
+        {
+          Insets insets = parent.getInsets();
+          Component c = parent.getComponent(0);
+          Dimension prefSize = c.getPreferredSize();
+          int h = parent.getHeight() - insets.top - insets.bottom;
+          int adj = Math.max(0, (h - prefSize.height) / 2);
+          c.setBounds(insets.left, insets.top + adj, parent.getWidth() 
+              - insets.left - insets.right, 
+              (int) Math.min(prefSize.getHeight(), h));
+        }
+    }
+    
+    /**
+     * Returns the minimum layout size.
+     * 
+     * @param parent  the container.
+     * 
+     * @return The minimum layout size.
+     */
+    public Dimension minimumLayoutSize(Container parent) 
+    {
+      return preferredLayoutSize(parent);
+    }
+    
+    /**
+     * Returns the preferred layout size.
+     * 
+     * @param parent  the container.
+     * 
+     * @return The preferred layout size.
+     */
+    public Dimension preferredLayoutSize(Container parent) 
+    {
+      if (parent.getComponentCount() > 0)
+        {
+          return parent.getComponent(0).getPreferredSize();
+        }
+      else return null;
+    }
+    
+    /**
+     * This layout manager does not need to track components, so this 
+     * method does nothing.
+     * 
+     * @param name  the name the component is associated with.
+     * @param component  the component.
+     */
+    public void addLayoutComponent(String name, Component component) 
+    {
+      // do nothing
+    }
+    
+    /**
+     * This layout manager does not need to track components, so this 
+     * method does nothing.
+     * 
+     * @param component  the component.
+     */
+    public void removeLayoutComponent(Component component) {
+      // do nothing
+    }
+  }
+
+  /**
+   * A layout manager that is used to arrange buttons for the
+   * address@hidden JFileChooser}.
+   */
+  class ButtonLayout implements LayoutManager
+  {
+    static final int GAP = 4;
+      
+    /**
+     * Performs the layout.
+     * 
+     * @param parent  the container.
+     */
+    public void layoutContainer(Container parent) 
+    {
+      int count = parent.getComponentCount();
+      if (count > 0)
+        {
+          // first find the widest button
+          int maxW = 0;
+          for (int i = 0; i < count; i++)
+            {
+              Component c = parent.getComponent(i);
+              Dimension prefSize = c.getPreferredSize();
+              maxW = Math.max(prefSize.width, maxW);
+            }
+  
+          // then position the buttons
+          Insets insets = parent.getInsets();
+          int availableH = parent.getHeight() - insets.top - insets.bottom;
+          int currentX = parent.getWidth() - insets.right;
+          for (int i = count - 1; i >= 0; i--)
+            {
+              Component c = parent.getComponent(i);
+              Dimension prefSize = c.getPreferredSize();      
+              int adj = Math.max(0, (availableH - prefSize.height) / 2);
+              currentX = currentX - prefSize.width;
+              c.setBounds(currentX, insets.top + adj, prefSize.width, 
+                  (int) Math.min(prefSize.getHeight(), availableH));
+              currentX = currentX - GAP;
+            }
+        }
+    }
+    
+    /**
+     * Returns the minimum layout size.
+     * 
+     * @param parent  the container.
+     * 
+     * @return The minimum layout size.
+     */
+    public Dimension minimumLayoutSize(Container parent) 
+    {
+      return preferredLayoutSize(parent);
+    }
+    
+    /**
+     * Returns the preferred layout size.
+     * 
+     * @param parent  the container.
+     * 
+     * @return The preferred layout size.
+     */
+    public Dimension preferredLayoutSize(Container parent) 
+    {
+      Insets insets = parent.getInsets();
+      int maxW = 0;
+      int maxH = 0;
+      int count = parent.getComponentCount();
+      if (count > 0) 
+        {
+          for (int i = 0; i < count; i++)
+            {
+              Component c = parent.getComponent(i);
+              Dimension d = c.getPreferredSize();
+              maxW = Math.max(d.width, maxW);
+              maxH = Math.max(d.height, maxH);
+            }
+        }
+      return new Dimension(maxW * count + GAP * (count - 1) + insets.left 
+              + insets.right, maxH + insets.top + insets.bottom);
+    }
+    
+    /**
+     * This layout manager does not need to track components, so this 
+     * method does nothing.
+     * 
+     * @param name  the name the component is associated with.
+     * @param component  the component.
+     */
+    public void addLayoutComponent(String name, Component component) 
+    {
+      // do nothing
+    }
+    
+    /**
+     * This layout manager does not need to track components, so this 
+     * method does nothing.
+     * 
+     * @param component  the component.
+     */
+    public void removeLayoutComponent(Component component) {
+      // do nothing
+    }
   }
 
 }
Index: javax/swing/plaf/metal/MetalLookAndFeel.java
===================================================================
RCS file: 
/cvsroot/classpath/classpath/javax/swing/plaf/metal/MetalLookAndFeel.java,v
retrieving revision 1.72
diff -u -r1.72 MetalLookAndFeel.java
--- javax/swing/plaf/metal/MetalLookAndFeel.java        23 Nov 2005 19:45:43 
-0000      1.72
+++ javax/swing/plaf/metal/MetalLookAndFeel.java        25 Nov 2005 10:21:12 
-0000
@@ -54,7 +54,17 @@
 
 /**
  * A custom look and feel that is designed to look similar across different
- * operating systems.
+ * operating systems.  To install this look and feel, add the following code 
+ * (or something similar) near the start of your application:</p>
+ * <pre>
+ * try
+ * {
+ * &nbsp;&nbsp;UIManager.setLookAndFeel(new MetalLookAndFeel());
+ * }
+ * catch (UnsupportedLookAndFeelException e)
+ * {
+ * &nbsp;&nbsp;e.printStackTrace();
+ * }</pre>
  */
 public class MetalLookAndFeel extends BasicLookAndFeel
 {         
@@ -690,6 +700,7 @@
       "CheckBoxUI", "javax.swing.plaf.metal.MetalCheckBoxUI",
       "ComboBoxUI", "javax.swing.plaf.metal.MetalComboBoxUI",
       "DesktopIconUI", "javax.swing.plaf.metal.MetalDesktopIconUI",
+      "FileChooserUI", "javax.swing.plaf.metal.MetalFileChooserUI",
       "InternalFrameUI", "javax.swing.plaf.metal.MetalInternalFrameUI",
       "LabelUI", "javax.swing.plaf.metal.MetalLabelUI",
       "MenuBarUI", "javax.swing.plaf.metal.MetalMenuBarUI",
@@ -856,6 +867,17 @@
       "FormattedTextField.inactiveForeground",  getInactiveSystemTextColor(),
       "FormattedTextField.selectionBackground", getTextHighlightColor(),
       "FormattedTextField.selectionForeground", getHighlightedTextColor(),
+
+      "FileChooser.upFolderIcon", 
+          MetalIconFactory.getFileChooserUpFolderIcon(),
+      "FileChooser.listViewIcon", 
+          MetalIconFactory.getFileChooserListViewIcon(),
+      "FileChooser.newFolderIcon", 
+          MetalIconFactory.getFileChooserNewFolderIcon(),
+      "FileChooser.homeFolderIcon", 
+          MetalIconFactory.getFileChooserHomeFolderIcon(),
+      "FileChooser.detailsViewIcon", 
+          MetalIconFactory.getFileChooserDetailViewIcon(),
 
       "FileView.computerIcon", MetalIconFactory.getTreeComputerIcon(),
       "FileView.directoryIcon", MetalIconFactory.getTreeFolderIcon(),

reply via email to

[Prev in Thread] Current Thread [Next in Thread]