001/* BasicFileChooserUI.java --
002   Copyright (C) 2005  Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038package javax.swing.plaf.basic;
039
040import java.awt.Window;
041import java.awt.event.ActionEvent;
042import java.awt.event.MouseAdapter;
043import java.awt.event.MouseEvent;
044import java.awt.event.MouseListener;
045import java.beans.PropertyChangeListener;
046import java.io.File;
047import java.io.IOException;
048import java.util.ArrayList;
049import java.util.Hashtable;
050
051import javax.swing.AbstractAction;
052import javax.swing.Action;
053import javax.swing.Icon;
054import javax.swing.JButton;
055import javax.swing.JComponent;
056import javax.swing.JDialog;
057import javax.swing.JFileChooser;
058import javax.swing.JList;
059import javax.swing.JPanel;
060import javax.swing.JTextField;
061import javax.swing.SwingUtilities;
062import javax.swing.UIDefaults;
063import javax.swing.UIManager;
064import javax.swing.event.ListSelectionEvent;
065import javax.swing.event.ListSelectionListener;
066import javax.swing.filechooser.FileFilter;
067import javax.swing.filechooser.FileSystemView;
068import javax.swing.filechooser.FileView;
069import javax.swing.plaf.ComponentUI;
070import javax.swing.plaf.FileChooserUI;
071import javax.swing.plaf.metal.MetalIconFactory;
072
073
074/**
075 * A UI delegate for the {@link JFileChooser} component under the 
076 * {@link BasicLookAndFeel}.
077 */
078public 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}