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