Source for javax.swing.plaf.basic.BasicFileChooserUI

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