001    /* BasicFileChooserUI.java --
002       Copyright (C) 2005  Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    package javax.swing.plaf.basic;
039    
040    import java.awt.Window;
041    import java.awt.event.ActionEvent;
042    import java.awt.event.MouseAdapter;
043    import java.awt.event.MouseEvent;
044    import java.awt.event.MouseListener;
045    import java.beans.PropertyChangeEvent;
046    import java.beans.PropertyChangeListener;
047    import java.io.File;
048    import java.io.IOException;
049    import java.util.ArrayList;
050    import java.util.Hashtable;
051    
052    import javax.swing.AbstractAction;
053    import javax.swing.Action;
054    import javax.swing.Icon;
055    import javax.swing.JButton;
056    import javax.swing.JComponent;
057    import javax.swing.JDialog;
058    import javax.swing.JFileChooser;
059    import javax.swing.JList;
060    import javax.swing.JPanel;
061    import javax.swing.JTextField;
062    import javax.swing.SwingUtilities;
063    import javax.swing.UIDefaults;
064    import javax.swing.UIManager;
065    import javax.swing.event.ListSelectionEvent;
066    import javax.swing.event.ListSelectionListener;
067    import javax.swing.filechooser.FileFilter;
068    import javax.swing.filechooser.FileSystemView;
069    import javax.swing.filechooser.FileView;
070    import javax.swing.plaf.ComponentUI;
071    import javax.swing.plaf.FileChooserUI;
072    import javax.swing.plaf.metal.MetalIconFactory;
073    
074    
075    /**
076     * A UI delegate for the {@link JFileChooser} component under the 
077     * {@link BasicLookAndFeel}.
078     */
079    public class BasicFileChooserUI extends FileChooserUI
080    {
081      /**
082       * A file filter that accepts all files.
083       */
084      protected class AcceptAllFileFilter extends FileFilter
085      {
086        /**
087         * Creates a new instance.
088         */
089        public AcceptAllFileFilter()
090        {
091          // Nothing to do here.
092        }
093        
094        /**
095         * Returns <code>true</code> always, as all files are accepted by this
096         * filter.
097         *
098         * @param f  the file.
099         *
100         * @return Always <code>true</code>.
101         */
102        public boolean accept(File f)
103        {
104          return true;
105        }
106    
107        /**
108         * Returns a description for this filter.
109         *
110         * @return A description for the file filter.
111         */
112        public String getDescription()
113        {
114          return acceptAllFileFilterText;
115        }
116      }
117    
118      /**
119       * Handles a user action to approve the dialog selection.
120       * 
121       * @see BasicFileChooserUI#getApproveSelectionAction()
122       */
123      protected class ApproveSelectionAction extends AbstractAction
124      {
125        /**
126         * Creates a new ApproveSelectionAction object.
127         */
128        protected ApproveSelectionAction()
129        {
130          super("approveSelection");
131        }
132    
133        /**
134         * Sets the current selection and closes the dialog.
135         * 
136         * @param e  the action event.
137         */
138        public void actionPerformed(ActionEvent e)
139        {
140          Object obj = null;
141          if (parentPath != null)
142            obj = new String(parentPath + getFileName());
143          else
144            obj = filechooser.getSelectedFile();
145          if (obj != null)
146            {
147              File f = filechooser.getFileSystemView().createFileObject(obj.toString());
148              File currSelected = filechooser.getSelectedFile();
149              if (filechooser.isTraversable(f))
150                {
151                  filechooser.setCurrentDirectory(currSelected);
152                  filechooser.rescanCurrentDirectory();
153                }
154              else
155                {
156                  filechooser.approveSelection();
157                  closeDialog();
158                }
159            }
160          else
161            {
162              File f = new File(filechooser.getCurrentDirectory(), getFileName());
163              if ( selectedDir != null )
164                f = selectedDir;
165              if (filechooser.isTraversable(f))
166                {
167                  filechooser.setCurrentDirectory(f);
168                  filechooser.rescanCurrentDirectory();
169                }
170              else
171                {
172                  filechooser.setSelectedFile(f);
173                  filechooser.approveSelection();
174                  closeDialog();
175                }
176            }
177        }
178      }
179    
180      /**
181       * Provides presentation information about files and directories.
182       */
183      protected class BasicFileView extends FileView
184      {
185        /** Storage for cached icons. */
186        protected Hashtable<File, Icon> iconCache = new Hashtable<File, Icon>();
187    
188        /**
189         * Creates a new instance.
190         */
191        public BasicFileView()
192        {
193          // Nothing to do here.
194        }
195    
196        /**
197         * Adds an icon to the cache, associating it with the given file/directory.
198         *
199         * @param f  the file/directory.
200         * @param i  the icon.
201         */
202        public void cacheIcon(File f, Icon i)
203        {
204          iconCache.put(f, i);
205        }
206    
207        /**
208         * Clears the icon cache.
209         */
210        public void clearIconCache()
211        {
212          iconCache.clear();
213        }
214    
215        /**
216         * Retrieves the icon associated with the specified file/directory, if 
217         * there is one.
218         *
219         * @param f  the file/directory.
220         *
221         * @return The cached icon (or <code>null</code>).
222         */
223        public Icon getCachedIcon(File f)
224        {
225          return (Icon) iconCache.get(f);
226        }
227    
228        /**
229         * Returns a description of the given file/directory.  In this 
230         * implementation, the description is the same as the name returned by 
231         * {@link #getName(File)}.
232         *
233         * @param f  the file/directory.
234         *
235         * @return A description of the given file/directory.
236         */
237        public String getDescription(File f)
238        {
239          return getName(f);
240        }
241    
242        /**
243         * Returns an icon appropriate for the given file or directory.
244         *
245         * @param f  the file/directory.
246         *
247         * @return An icon.
248         */
249        public Icon getIcon(File f)
250        {
251          Icon val = getCachedIcon(f);
252          if (val != null)
253            return val;
254          if (filechooser.isTraversable(f))
255            val = directoryIcon;
256          else
257            val = fileIcon;
258          cacheIcon(f, val);
259          return val;
260        }
261    
262        /**
263         * Returns the name for the given file/directory.
264         *
265         * @param f  the file/directory.
266         *
267         * @return The name of the file/directory.
268         */
269        public String getName(File f)
270        {
271          String name = null;
272          if (f != null)
273            {
274              JFileChooser c = getFileChooser();
275              FileSystemView v = c.getFileSystemView();
276              name = v.getSystemDisplayName(f);
277            }
278          return name;
279        }
280    
281        /**
282         * Returns a localised description for the type of file/directory.
283         *
284         * @param f  the file/directory.
285         *
286         * @return A type description for the given file/directory.
287         */
288        public String getTypeDescription(File f)
289        {
290          if (filechooser.isTraversable(f))
291            return dirDescText;
292          else
293            return fileDescText;
294        }
295    
296        /**
297         * Returns {@link Boolean#TRUE} if the given file/directory is hidden,
298         * and {@link Boolean#FALSE} otherwise.
299         *
300         * @param f  the file/directory.
301         *
302         * @return {@link Boolean#TRUE} or {@link Boolean#FALSE}.
303         */
304        public Boolean isHidden(File f)
305        {
306          return Boolean.valueOf(filechooser.getFileSystemView().isHiddenFile(f));
307        }
308      }
309    
310      /**
311       * Handles an action to cancel the file chooser.
312       * 
313       * @see BasicFileChooserUI#getCancelSelectionAction()
314       */
315      protected class CancelSelectionAction extends AbstractAction
316      {
317        /**
318         * Creates a new <code>CancelSelectionAction</code> object.
319         */
320        protected CancelSelectionAction()
321        {
322          super(null);
323        }
324    
325        /**
326         * Cancels the selection and closes the dialog.
327         *
328         * @param e  the action event (ignored).
329         */
330        public void actionPerformed(ActionEvent e)
331        {
332          filechooser.setSelectedFile(null);
333          filechooser.setSelectedFiles(null);
334          filechooser.cancelSelection();
335          closeDialog();
336        }
337      }
338    
339      /**
340       * An action to handle changes to the parent directory (for example, via
341       * a click on the "up folder" button).
342       * 
343       * @see BasicFileChooserUI#getChangeToParentDirectoryAction()
344       */
345      protected class ChangeToParentDirectoryAction extends AbstractAction
346      {
347        /**
348         * Creates a new <code>ChangeToParentDirectoryAction</code> object.
349         */
350        protected ChangeToParentDirectoryAction()
351        {
352          super("Go Up");
353        }
354    
355        /**
356         * Handles the action event.
357         *
358         * @param e  the action event.
359         */
360        public void actionPerformed(ActionEvent e)
361        {
362          filechooser.changeToParentDirectory();
363          filechooser.revalidate();
364          filechooser.repaint();
365        }
366      }
367    
368      /**
369       * A mouse listener that handles double-click events.
370       * 
371       * @see BasicFileChooserUI#createDoubleClickListener(JFileChooser, JList)
372       */
373      protected class DoubleClickListener extends MouseAdapter
374      {
375    
376        /** DOCUMENT ME! */
377        private Object lastSelected;
378    
379        /** DOCUMENT ME! */
380        private JList list;
381    
382        /**
383         * Creates a new DoubleClickListener object.
384         *
385         * @param list DOCUMENT ME!
386         */
387        public DoubleClickListener(JList list)
388        {
389          this.list = list;
390          lastSelected = list.getSelectedValue();
391          setDirectorySelected(false);
392        }
393    
394        /**
395         * Handles a mouse click event.
396         * 
397         * @param e  the event.
398         */
399        public void mouseClicked(MouseEvent e)
400        {
401          Object p = list.getSelectedValue();
402          if (p == null)
403            return;
404          FileSystemView fsv = filechooser.getFileSystemView();
405          if (e.getClickCount() >= 2 && lastSelected != null &&
406              p.toString().equals(lastSelected.toString()))
407            {
408              File f = fsv.createFileObject(lastSelected.toString());
409              if (filechooser.isTraversable(f))
410                {
411                  filechooser.setCurrentDirectory(f);
412                  filechooser.rescanCurrentDirectory();
413                }
414              else
415                {
416                  filechooser.setSelectedFile(f);
417                  filechooser.approveSelection();
418                  closeDialog();
419                }
420            }
421          else // single click
422            {
423              String path = p.toString();
424              File f = fsv.createFileObject(path);
425              filechooser.setSelectedFile(f);
426              
427              if (filechooser.isMultiSelectionEnabled())
428                {
429                  int[] inds = list.getSelectedIndices();
430                  File[] allFiles = new File[inds.length];
431                  for (int i = 0; i < inds.length; i++)
432                    allFiles[i] = (File) list.getModel().getElementAt(inds[i]);
433                  filechooser.setSelectedFiles(allFiles);
434                }
435              
436              if (filechooser.isTraversable(f))
437                {
438                  setDirectorySelected(true);
439                  setDirectory(f);
440                }
441              else
442                {
443                  setDirectorySelected(false);
444                  setDirectory(null);
445                }
446              lastSelected = path;
447              parentPath = f.getParent();
448                
449              if (f.isFile())
450                setFileName(f.getName());
451              else if (filechooser.getFileSelectionMode() != 
452                       JFileChooser.FILES_ONLY)
453                setFileName(path);
454            }
455        }
456    
457        /**
458         * Handles a mouse entered event (NOT IMPLEMENTED).
459         * 
460         * @param e  the mouse event.
461         */
462        public void mouseEntered(MouseEvent e)
463        {
464          // FIXME: Implement
465        }
466      }
467    
468      /**
469       * An action that changes the file chooser to display the user's home 
470       * directory. 
471       * 
472       * @see BasicFileChooserUI#getGoHomeAction()
473       */
474      protected class GoHomeAction extends AbstractAction
475      {
476        /**
477         * Creates a new <code>GoHomeAction</code> object.
478         */
479        protected GoHomeAction()
480        {
481          super("Go Home");
482        }
483    
484        /**
485         * Sets the directory to the user's home directory, and repaints the
486         * file chooser component.
487         *
488         * @param e  the action event (ignored).
489         */
490        public void actionPerformed(ActionEvent e)
491        {
492          filechooser.setCurrentDirectory(filechooser.getFileSystemView()
493                                                     .getHomeDirectory());
494          filechooser.revalidate();
495          filechooser.repaint();
496        }
497      }
498    
499      /**
500       * An action that handles the creation of a new folder/directory.
501       * 
502       * @see BasicFileChooserUI#getNewFolderAction()
503       */
504      protected class NewFolderAction extends AbstractAction
505      {
506        /**
507         * Creates a new <code>NewFolderAction</code> object.
508         */
509        protected NewFolderAction()
510        {
511          super("New Folder");
512        }
513    
514        /**
515         * Handles the event by creating a new folder.
516         *
517         * @param e  the action event (ignored).
518         */
519        public void actionPerformed(ActionEvent e)
520        {
521          try
522            {
523              filechooser.getFileSystemView().createNewFolder(filechooser
524                                                              .getCurrentDirectory());
525            }
526          catch (IOException ioe)
527            {
528              return;
529            }
530          filechooser.rescanCurrentDirectory();
531          filechooser.repaint();
532        }
533      }
534    
535      /**
536       * A listener for selection events in the file list.
537       * 
538       * @see BasicFileChooserUI#createListSelectionListener(JFileChooser)
539       */
540      protected class SelectionListener implements ListSelectionListener
541      {
542        /**
543         * Creates a new <code>SelectionListener</code> object.
544         */
545        protected SelectionListener()
546        {
547          // Nothing to do here.
548        }
549    
550        /**
551         * Sets the JFileChooser to the selected file on an update
552         *
553         * @param e DOCUMENT ME!
554         */
555        public void valueChanged(ListSelectionEvent e)
556        {
557          JList list = (JList) e.getSource();
558          Object f = list.getSelectedValue();
559          if (f == null)
560            return;
561          File file = filechooser.getFileSystemView().createFileObject(f.toString());
562          if (! filechooser.isTraversable(file))
563            {
564              selectedDir = null;
565              filechooser.setSelectedFile(file);
566            }
567          else
568            {
569              selectedDir = file;
570              filechooser.setSelectedFile(null);
571            }
572        }
573      }
574    
575      /**
576       * DOCUMENT ME!
577       * 
578       * @see BasicFileChooserUI#getUpdateAction()
579       */
580      protected class UpdateAction extends AbstractAction
581      {
582        /**
583         * Creates a new UpdateAction object.
584         */
585        protected UpdateAction()
586        {
587          super(null);
588        }
589    
590        /**
591         * NOT YET IMPLEMENTED.
592         *
593         * @param e  the action event.
594         */
595        public void actionPerformed(ActionEvent e)
596        {
597          // FIXME: implement this
598        }
599      }
600    
601      /** The localised mnemonic for the cancel button. */
602      protected int cancelButtonMnemonic;
603    
604      /** The localised text for the cancel button. */
605      protected String cancelButtonText;
606    
607      /** The localised tool tip text for the cancel button. */
608      protected String cancelButtonToolTipText;
609    
610      /** An icon representing a computer. */
611      protected Icon computerIcon;
612    
613      /** An icon for the "details view" button. */
614      protected Icon detailsViewIcon;
615    
616      /** An icon representing a directory. */
617      protected Icon directoryIcon;
618    
619      /** The localised Mnemonic for the open button. */
620      protected int directoryOpenButtonMnemonic;
621    
622      /** The localised text for the open button. */
623      protected String directoryOpenButtonText;
624    
625      /** The localised tool tip text for the open button. */
626      protected String directoryOpenButtonToolTipText;
627    
628      /** An icon representing a file. */
629      protected Icon fileIcon;
630    
631      /** An icon representing a floppy drive. */
632      protected Icon floppyDriveIcon;
633    
634      /** An icon representing a hard drive. */
635      protected Icon hardDriveIcon;
636    
637      /** The localised mnemonic for the "help" button. */
638      protected int helpButtonMnemonic;
639    
640      /** The localised text for the "help" button. */
641      protected String helpButtonText;
642    
643      /** The localised tool tip text for the help button. */
644      protected String helpButtonToolTipText;
645    
646      /** An icon representing the user's home folder. */
647      protected Icon homeFolderIcon;
648    
649      /** An icon for the "list view" button. */
650      protected Icon listViewIcon;
651    
652      /** An icon for the "new folder" button. */
653      protected Icon newFolderIcon = directoryIcon;
654    
655      /** The localised mnemonic for the "open" button. */
656      protected int openButtonMnemonic;
657    
658      /** The localised text for the "open" button. */
659      protected String openButtonText;
660    
661      /** The localised tool tip text for the "open" button. */
662      protected String openButtonToolTipText;
663    
664      /** The localised mnemonic for the "save" button. */
665      protected int saveButtonMnemonic;
666    
667      /** The localised text for the "save" button. */
668      protected String saveButtonText;
669    
670      /** The localised tool tip text for the save button. */
671      protected String saveButtonToolTipText;
672    
673      /** The localised mnemonic for the "update" button. */
674      protected int updateButtonMnemonic;
675    
676      /** The localised text for the "update" button. */
677      protected String updateButtonText;
678    
679      /** The localised tool tip text for the "update" button. */
680      protected String updateButtonToolTipText;
681    
682      /** An icon for the "up folder" button. */
683      protected Icon upFolderIcon;
684    
685      // -- begin private, but package local since used in inner classes --
686    
687      /** The file chooser component represented by this UI delegate. */
688      JFileChooser filechooser;
689    
690      /** The model for the directory list. */
691      BasicDirectoryModel model;
692    
693      /** The file filter for all files. */
694      FileFilter acceptAll = new AcceptAllFileFilter();
695    
696      /** The default file view. */
697      FileView fv = new BasicFileView();
698    
699      /** The accept (open/save) button. */
700      JButton accept;
701    
702      /** An optional accessory panel. */
703      JPanel accessoryPanel = new JPanel();
704    
705      /** A property change listener. */
706      PropertyChangeListener propertyChangeListener;
707    
708      /** The text describing the filter for "all files". */
709      String acceptAllFileFilterText;
710    
711      /** The text describing a directory type. */
712      String dirDescText;
713    
714      /** The text describing a file type. */
715      String fileDescText;
716    
717      /** Is a directory selected? */
718      boolean dirSelected;
719    
720      /** The current directory. */
721      File currDir;
722    
723      // FIXME: describe what is contained in the bottom panel
724      /** The bottom panel. */
725      JPanel bottomPanel;
726      
727      /** The close panel. */
728      JPanel closePanel;
729    
730      /** Text box that displays file name */
731      JTextField entry;
732        
733      /** Current parent path */
734      String parentPath;
735      
736      /**
737       * The action for the 'approve' button.
738       * @see #getApproveSelectionAction()
739       */
740      private ApproveSelectionAction approveSelectionAction;
741      
742      /**
743       * The action for the 'cancel' button.
744       * @see #getCancelSelectionAction()
745       */
746      private CancelSelectionAction cancelSelectionAction;
747      
748      /**
749       * The action for the 'go home' control button.
750       * @see #getGoHomeAction()
751       */
752      private GoHomeAction goHomeAction;
753      
754      /**
755       * The action for the 'up folder' control button.
756       * @see #getChangeToParentDirectoryAction()
757       */
758      private ChangeToParentDirectoryAction changeToParentDirectoryAction;
759      
760      /**
761       * The action for the 'new folder' control button.
762       * @see #getNewFolderAction()
763       */
764      private NewFolderAction newFolderAction;
765      
766      /**
767       * The action for ???.  // FIXME: what is this?
768       * @see #getUpdateAction()
769       */
770      private UpdateAction updateAction;
771    
772      /**
773       * When in FILES_ONLY, mode a directory cannot be selected, so
774       * we save a reference to any it here. This is used to enter
775       * the directory on "Open" when in that mode.
776       */
777      private File selectedDir;
778      
779      // -- end private --
780    
781      /**
782       * Closes the dialog.
783       */
784      void closeDialog()
785      {
786        Window owner = SwingUtilities.windowForComponent(filechooser);
787        if (owner instanceof JDialog)
788          ((JDialog) owner).dispose();
789      }
790    
791      /**
792       * Creates a new <code>BasicFileChooserUI</code> object.
793       *
794       * @param b  the file chooser component.
795       */
796      public BasicFileChooserUI(JFileChooser b)
797      {
798      }
799    
800      /**
801       * Returns a UI delegate for the given component.
802       *
803       * @param c  the component (should be a {@link JFileChooser}).
804       *
805       * @return A new UI delegate.
806       */
807      public static ComponentUI createUI(JComponent c)
808      {
809        return new BasicFileChooserUI((JFileChooser) c);
810      }
811    
812      /**
813       * Installs the UI for the specified component.
814       * 
815       * @param c  the component (should be a {@link JFileChooser}).
816       */
817      public void installUI(JComponent c)
818      {
819        if (c instanceof JFileChooser)
820          {
821            JFileChooser fc = (JFileChooser) c;
822            this.filechooser = fc;
823            fc.resetChoosableFileFilters();
824            createModel();
825            clearIconCache();
826            installDefaults(fc);
827            installComponents(fc);
828            installListeners(fc);
829            
830            File path = filechooser.getCurrentDirectory();
831            if (path != null)
832              parentPath = path.getParent();
833          }
834      }
835    
836      /**
837       * Uninstalls this UI from the given component.
838       * 
839       * @param c  the component (should be a {@link JFileChooser}).
840       */
841      public void uninstallUI(JComponent c)
842      {
843        model = null;
844        uninstallListeners(filechooser);
845        uninstallComponents(filechooser);
846        uninstallDefaults(filechooser);
847        filechooser = null;
848      }
849    
850      // FIXME: Indent the entries in the combobox
851      // Made this method package private to access it from within inner classes
852      // with better performance
853      void boxEntries()
854      {
855        ArrayList parentFiles = new ArrayList();
856        File parent = filechooser.getCurrentDirectory();
857        if (parent == null)
858          parent = filechooser.getFileSystemView().getDefaultDirectory();
859        while (parent != null)
860          {
861            String name = parent.getName();
862            if (name.equals(""))
863              name = parent.getAbsolutePath();
864    
865            parentFiles.add(parentFiles.size(), name);
866            parent = parent.getParentFile();
867          }
868    
869        if (parentFiles.size() == 0)
870          return;
871    
872      }  
873    
874      /**
875       * Creates and install the subcomponents for the file chooser.
876       *
877       * @param fc  the file chooser.
878       */
879      public void installComponents(JFileChooser fc)
880      {
881      }
882    
883      /**
884       * Uninstalls the components from the file chooser.
885       *
886       * @param fc  the file chooser.
887       */
888      public void uninstallComponents(JFileChooser fc)
889      {
890      }
891    
892      /**
893       * Installs the listeners required by this UI delegate.
894       *
895       * @param fc  the file chooser.
896       */
897      protected void installListeners(JFileChooser fc)
898      {
899        propertyChangeListener = createPropertyChangeListener(filechooser);
900        if (propertyChangeListener != null)
901          filechooser.addPropertyChangeListener(propertyChangeListener);
902        fc.addPropertyChangeListener(getModel());
903      }
904    
905      /**
906       * Uninstalls the listeners previously installed by this UI delegate.
907       *
908       * @param fc  the file chooser.
909       */
910      protected void uninstallListeners(JFileChooser fc)
911      {
912        if (propertyChangeListener != null)
913          {
914            filechooser.removePropertyChangeListener(propertyChangeListener);
915            propertyChangeListener = null;
916          }
917        fc.removePropertyChangeListener(getModel());
918      }
919    
920      /**
921       * Installs the defaults for this UI delegate.
922       *
923       * @param fc  the file chooser.
924       */
925      protected void installDefaults(JFileChooser fc)
926      {
927        installIcons(fc);
928        installStrings(fc);
929      }
930    
931      /**
932       * Uninstalls the defaults previously added by this UI delegate.
933       *
934       * @param fc  the file chooser.
935       */
936      protected void uninstallDefaults(JFileChooser fc)
937      {
938        uninstallStrings(fc);
939        uninstallIcons(fc);
940      }
941    
942      /**
943       * Installs the icons for this UI delegate.
944       *
945       * @param fc  the file chooser (ignored).
946       */
947      protected void installIcons(JFileChooser fc)
948      {
949        UIDefaults defaults = UIManager.getLookAndFeelDefaults();
950        computerIcon = MetalIconFactory.getTreeComputerIcon();
951        detailsViewIcon = defaults.getIcon("FileChooser.detailsViewIcon");
952        directoryIcon = new MetalIconFactory.TreeFolderIcon();
953        fileIcon = new MetalIconFactory.TreeLeafIcon();
954        floppyDriveIcon = MetalIconFactory.getTreeFloppyDriveIcon();
955        hardDriveIcon = MetalIconFactory.getTreeHardDriveIcon();
956        homeFolderIcon = defaults.getIcon("FileChooser.homeFolderIcon");
957        listViewIcon = defaults.getIcon("FileChooser.listViewIcon");
958        newFolderIcon = defaults.getIcon("FileChooser.newFolderIcon");
959        upFolderIcon = defaults.getIcon("FileChooser.upFolderIcon");
960      }
961    
962      /**
963       * Uninstalls the icons previously added by this UI delegate.
964       *
965       * @param fc  the file chooser.
966       */
967      protected void uninstallIcons(JFileChooser fc)
968      {
969        computerIcon = null;
970        detailsViewIcon = null;
971        directoryIcon = null;
972        fileIcon = null;
973        floppyDriveIcon = null;
974        hardDriveIcon = null;
975        homeFolderIcon = null;
976        listViewIcon = null;
977        newFolderIcon = null;
978        upFolderIcon = null;
979      }
980    
981      /**
982       * Installs the strings used by this UI delegate.
983       *
984       * @param fc  the file chooser.
985       */
986      protected void installStrings(JFileChooser fc)
987      {
988        UIDefaults defaults = UIManager.getLookAndFeelDefaults();
989    
990        dirDescText = defaults.getString("FileChooser.directoryDescriptionText");
991        fileDescText = defaults.getString("FileChooser.fileDescriptionText");
992    
993        acceptAllFileFilterText = defaults.getString("FileChooser.acceptAllFileFilterText");
994        cancelButtonText = "Cancel";
995        cancelButtonToolTipText = "Abort file chooser dialog";
996        cancelButtonMnemonic = new Integer((String) UIManager.get("FileChooser.cancelButtonMnemonic")).intValue();
997    
998        directoryOpenButtonText = "Open";
999        directoryOpenButtonToolTipText = "Open selected directory";
1000        directoryOpenButtonMnemonic 
1001            = new Integer((String) UIManager.get("FileChooser.directoryOpenButtonMnemonic")).intValue();
1002        
1003        helpButtonText = "Help";
1004        helpButtonToolTipText = "FileChooser help";
1005        helpButtonMnemonic = new Integer((String) UIManager.get("FileChooser.helpButtonMnemonic")).intValue();
1006    
1007        openButtonText = "Open";
1008        openButtonToolTipText = "Open selected file";
1009        openButtonMnemonic = new Integer((String) UIManager.get("FileChooser.openButtonMnemonic")).intValue();
1010    
1011        saveButtonText = "Save";
1012        saveButtonToolTipText = "Save selected file";
1013        saveButtonMnemonic = new Integer((String) UIManager.get("FileChooser.saveButtonMnemonic")).intValue();
1014      
1015        updateButtonText = "Update";
1016        updateButtonToolTipText = "Update directory listing";
1017        updateButtonMnemonic = new Integer((String) UIManager.get("FileChooser.updateButtonMnemonic")).intValue();
1018      }
1019    
1020      /**
1021       * Uninstalls the strings previously added by this UI delegate.
1022       *
1023       * @param fc  the file chooser.
1024       */
1025      protected void uninstallStrings(JFileChooser fc)
1026      {
1027        acceptAllFileFilterText = null;
1028        dirDescText = null;
1029        fileDescText = null;
1030    
1031        cancelButtonText = null;
1032        cancelButtonToolTipText = null;
1033    
1034        directoryOpenButtonText = null;
1035        directoryOpenButtonToolTipText = null;
1036    
1037        helpButtonText = null;
1038        helpButtonToolTipText = null;
1039    
1040        openButtonText = null;
1041        openButtonToolTipText = null;
1042    
1043        saveButtonText = null;
1044        saveButtonToolTipText = null;
1045        
1046        updateButtonText = null;
1047        updateButtonToolTipText = null;
1048      }
1049    
1050      /**
1051       * Creates a new directory model.
1052       */
1053      protected void createModel()
1054      {
1055        model = new BasicDirectoryModel(filechooser);
1056      }
1057    
1058      /**
1059       * Returns the directory model.
1060       *
1061       * @return The directory model.
1062       */
1063      public BasicDirectoryModel getModel()
1064      {
1065        return model;
1066      }
1067    
1068      /**
1069       * Creates a listener to handle changes to the properties of the given
1070       * file chooser component.
1071       * 
1072       * @param fc  the file chooser component.
1073       * 
1074       * @return A new listener.
1075       */
1076      public PropertyChangeListener createPropertyChangeListener(JFileChooser fc)
1077      {
1078        // The RI returns null here, so do we.
1079        return null;
1080      }
1081    
1082      /**
1083       * Returns the current file name.
1084       * 
1085       * @return The current file name.
1086       */
1087      public String getFileName()
1088      {
1089        return entry.getText();
1090      }
1091    
1092      /**
1093       * Returns the current directory name.
1094       *
1095       * @return The directory name.
1096       * 
1097       * @see #setDirectoryName(String)
1098       */
1099      public String getDirectoryName()
1100      {
1101        // XXX: I don't see a case where the thing returns something non-null..
1102        return null;
1103      }
1104    
1105      /**
1106       * Sets the file name.
1107       *
1108       * @param filename  the file name.
1109       * 
1110       * @see #getFileName()
1111       */
1112      public void setFileName(String filename)
1113      {
1114        // FIXME:  it might be the case that this method provides an access 
1115        // point for the JTextField (or whatever) a subclass is using...
1116        //this.filename = filename;
1117      }
1118    
1119      /**
1120       * Sets the directory name (NOT IMPLEMENTED).
1121       *
1122       * @param dirname  the directory name.
1123       * 
1124       * @see #getDirectoryName()
1125       */
1126      public void setDirectoryName(String dirname)
1127      {
1128        // FIXME: Implement
1129      }
1130    
1131      /**
1132       * Rescans the current directory.
1133       *
1134       * @param fc  the file chooser.
1135       */
1136      public void rescanCurrentDirectory(JFileChooser fc)
1137      {
1138        getModel().validateFileCache();
1139      }
1140    
1141      /**
1142       * NOT YET IMPLEMENTED.
1143       *
1144       * @param fc  the file chooser.
1145       * @param f  the file.
1146       */
1147      public void ensureFileIsVisible(JFileChooser fc, File f)
1148      {
1149        // XXX: Not sure what this does.
1150      }
1151    
1152      /**
1153       * Returns the {@link JFileChooser} component that this UI delegate 
1154       * represents.
1155       *
1156       * @return The component represented by this UI delegate.
1157       */
1158      public JFileChooser getFileChooser()
1159      {
1160        return filechooser;
1161      }
1162    
1163      /**
1164       * Returns the optional accessory panel.
1165       *
1166       * @return The optional accessory panel.
1167       */
1168      public JPanel getAccessoryPanel()
1169      {
1170        return accessoryPanel;
1171      }
1172    
1173      /**
1174       * Returns the approve (open or save) button for the dialog.
1175       *
1176       * @param fc  the file chooser.
1177       *
1178       * @return The button.
1179       */
1180      protected JButton getApproveButton(JFileChooser fc)
1181      {
1182        return accept;
1183      }
1184    
1185      /**
1186       * Returns the tool tip text for the approve (open/save) button.  This first
1187       * checks the file chooser to see if a value has been explicitly set - if
1188       * not, a default value appropriate for the type of file chooser is 
1189       * returned.
1190       *
1191       * @param fc  the file chooser.
1192       *
1193       * @return The tool tip text.
1194       */
1195      public String getApproveButtonToolTipText(JFileChooser fc)
1196      {
1197        if (fc.getApproveButtonToolTipText() != null)
1198          return fc.getApproveButtonToolTipText();
1199        else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG)
1200          return saveButtonToolTipText;
1201        else
1202          return openButtonToolTipText;
1203      }
1204    
1205      /**
1206       * Clears the icon cache.
1207       */
1208      public void clearIconCache()
1209      {
1210        if (fv instanceof BasicFileView)
1211          ((BasicFileView) fv).clearIconCache();
1212      }
1213    
1214      /**
1215       * Creates a new listener to handle selections in the file list.
1216       *
1217       * @param fc  the file chooser component.
1218       *
1219       * @return A new instance of {@link SelectionListener}.
1220       */
1221      public ListSelectionListener createListSelectionListener(JFileChooser fc)
1222      {
1223        return new SelectionListener();
1224      }
1225    
1226      /**
1227       * Creates a new listener to handle double-click events.
1228       *
1229       * @param fc  the file chooser component.
1230       * @param list  the list.
1231       *
1232       * @return A new instance of {@link DoubleClickListener}.
1233       */
1234      protected MouseListener createDoubleClickListener(JFileChooser fc, JList list)
1235      {
1236        return new DoubleClickListener(list);
1237      }
1238    
1239      /**
1240       * Returns <code>true</code> if a directory is selected, and 
1241       * <code>false</code> otherwise.
1242       *
1243       * @return A boolean.
1244       */
1245      protected boolean isDirectorySelected()
1246      {
1247        return dirSelected;
1248      }
1249    
1250      /**
1251       * Sets the flag that indicates whether the current directory is selected.
1252       *
1253       * @param selected  the new flag value.
1254       */
1255      protected void setDirectorySelected(boolean selected)
1256      {
1257        dirSelected = selected;
1258      }
1259    
1260      /**
1261       * Returns the current directory.
1262       *
1263       * @return The current directory.
1264       */
1265      protected File getDirectory()
1266      {
1267        return currDir;
1268      }
1269    
1270      /**
1271       * Sets the current directory.
1272       *
1273       * @param f  the directory.
1274       */
1275      protected void setDirectory(File f)
1276      {
1277        currDir = f;
1278      }
1279    
1280      /**
1281       * Returns the "accept all" file filter.
1282       *
1283       * @param fc  the file chooser component.
1284       *
1285       * @return The "accept all" file filter.
1286       */
1287      public FileFilter getAcceptAllFileFilter(JFileChooser fc)
1288      {
1289        return acceptAll;
1290      }
1291    
1292      /**
1293       * Returns the default file view (NOT the file view from the file chooser,
1294       * if there is one).
1295       *
1296       * @param fc  the file chooser component.
1297       *
1298       * @return The file view.
1299       * 
1300       * @see JFileChooser#getFileView()
1301       */
1302      public FileView getFileView(JFileChooser fc)
1303      {
1304        return fv;
1305      }
1306    
1307      /**
1308       * Returns the dialog title.
1309       *
1310       * @param fc  the file chooser (<code>null</code> not permitted).
1311       *
1312       * @return The dialog title.
1313       * 
1314       * @see JFileChooser#getDialogTitle()
1315       */
1316      public String getDialogTitle(JFileChooser fc)
1317      {
1318        String result = fc.getDialogTitle();
1319        if (result == null)
1320          result = getApproveButtonText(fc);
1321        return result;
1322      }
1323    
1324      /**
1325       * Returns the approve button mnemonic.
1326       *
1327       * @param fc  the file chooser (<code>null</code> not permitted).
1328       *
1329       * @return The approve button mnemonic.
1330       * 
1331       * @see JFileChooser#getApproveButtonMnemonic()
1332       */
1333      public int getApproveButtonMnemonic(JFileChooser fc)
1334      {
1335        if (fc.getApproveButtonMnemonic() != 0)
1336          return fc.getApproveButtonMnemonic();
1337        else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG)
1338          return saveButtonMnemonic;
1339        else
1340          return openButtonMnemonic;
1341      }
1342    
1343      /**
1344       * Returns the approve button text.
1345       *
1346       * @param fc  the file chooser (<code>null</code> not permitted).
1347       *
1348       * @return The approve button text.
1349       * 
1350       * @see JFileChooser#getApproveButtonText()
1351       */
1352      public String getApproveButtonText(JFileChooser fc)
1353      {
1354        String result = fc.getApproveButtonText();
1355        if (result == null)
1356          {
1357            if (fc.getDialogType() == JFileChooser.SAVE_DIALOG)
1358              result = saveButtonText;
1359            else
1360              result = openButtonText;
1361          }
1362        return result;
1363      }
1364    
1365      /**
1366       * Creates and returns a new action that will be used with the "new folder" 
1367       * button.
1368       *
1369       * @return A new instance of {@link NewFolderAction}.
1370       */
1371      public Action getNewFolderAction()
1372      {
1373        if (newFolderAction == null)
1374          newFolderAction = new NewFolderAction();
1375        return newFolderAction;
1376      }
1377    
1378      /**
1379       * Creates and returns a new action that will be used with the "home folder" 
1380       * button.
1381       *
1382       * @return A new instance of {@link GoHomeAction}.
1383       */
1384      public Action getGoHomeAction()
1385      {
1386        if (goHomeAction == null)
1387          goHomeAction = new GoHomeAction();
1388        return goHomeAction;
1389      }
1390    
1391      /**
1392       * Returns the action that handles events for the "up folder" control button.
1393       *
1394       * @return An instance of {@link ChangeToParentDirectoryAction}.
1395       */
1396      public Action getChangeToParentDirectoryAction()
1397      {
1398        if (changeToParentDirectoryAction == null)
1399          changeToParentDirectoryAction = new ChangeToParentDirectoryAction();
1400        return changeToParentDirectoryAction;
1401      }
1402    
1403      /**
1404       * Returns the action that handles events for the "approve" button.
1405       *
1406       * @return An instance of {@link ApproveSelectionAction}.
1407       */
1408      public Action getApproveSelectionAction()
1409      {
1410        if (approveSelectionAction == null)
1411          approveSelectionAction = new ApproveSelectionAction();
1412        return approveSelectionAction;
1413      }
1414    
1415      /**
1416       * Returns the action that handles events for the "cancel" button.
1417       *
1418       * @return An instance of {@link CancelSelectionAction}.
1419       */
1420      public Action getCancelSelectionAction()
1421      {
1422        if (cancelSelectionAction == null)
1423          cancelSelectionAction = new CancelSelectionAction();
1424        return cancelSelectionAction;
1425      }
1426    
1427      /**
1428       * Returns the update action (an instance of {@link UpdateAction}).
1429       *
1430       * @return An action. 
1431       */
1432      public Action getUpdateAction()
1433      {
1434        if (updateAction == null)
1435          updateAction = new UpdateAction();
1436        return updateAction;
1437      }
1438    }