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:       else
 161:         {
 162:           File f = new File(filechooser.getCurrentDirectory(), getFileName());
 163:       if ( selectedDir != null )
 164:         f = selectedDir;
 165:           if (filechooser.isTraversable(f))
 166:             {
 167:               filechooser.setCurrentDirectory(f);
 168:               filechooser.rescanCurrentDirectory();
 169:             }
 170:           else
 171:             {
 172:               filechooser.setSelectedFile(f);
 173:               filechooser.approveSelection();
 174:               closeDialog();
 175:             }
 176:         }
 177:     }
 178:   }
 179: 
 180:   /**
 181:    * Provides presentation information about files and directories.
 182:    */
 183:   protected class BasicFileView extends FileView
 184:   {
 185:     /** Storage for cached icons. */
 186:     protected Hashtable<File, Icon> iconCache = new Hashtable<File, Icon>();
 187: 
 188:     /**
 189:      * Creates a new instance.
 190:      */
 191:     public BasicFileView()
 192:     {
 193:       // Nothing to do here.
 194:     }
 195: 
 196:     /**
 197:      * Adds an icon to the cache, associating it with the given file/directory.
 198:      *
 199:      * @param f  the file/directory.
 200:      * @param i  the icon.
 201:      */
 202:     public void cacheIcon(File f, Icon i)
 203:     {
 204:       iconCache.put(f, i);
 205:     }
 206: 
 207:     /**
 208:      * Clears the icon cache.
 209:      */
 210:     public void clearIconCache()
 211:     {
 212:       iconCache.clear();
 213:     }
 214: 
 215:     /**
 216:      * Retrieves the icon associated with the specified file/directory, if 
 217:      * there is one.
 218:      *
 219:      * @param f  the file/directory.
 220:      *
 221:      * @return The cached icon (or <code>null</code>).
 222:      */
 223:     public Icon getCachedIcon(File f)
 224:     {
 225:       return (Icon) iconCache.get(f);
 226:     }
 227: 
 228:     /**
 229:      * Returns a description of the given file/directory.  In this 
 230:      * implementation, the description is the same as the name returned by 
 231:      * {@link #getName(File)}.
 232:      *
 233:      * @param f  the file/directory.
 234:      *
 235:      * @return A description of the given file/directory.
 236:      */
 237:     public String getDescription(File f)
 238:     {
 239:       return getName(f);
 240:     }
 241: 
 242:     /**
 243:      * Returns an icon appropriate for the given file or directory.
 244:      *
 245:      * @param f  the file/directory.
 246:      *
 247:      * @return An icon.
 248:      */
 249:     public Icon getIcon(File f)
 250:     {
 251:       Icon val = getCachedIcon(f);
 252:       if (val != null)
 253:     return val;
 254:       if (filechooser.isTraversable(f))
 255:     val = directoryIcon;
 256:       else
 257:     val = fileIcon;
 258:       cacheIcon(f, val);
 259:       return val;
 260:     }
 261: 
 262:     /**
 263:      * Returns the name for the given file/directory.
 264:      *
 265:      * @param f  the file/directory.
 266:      *
 267:      * @return The name of the file/directory.
 268:      */
 269:     public String getName(File f)
 270:     {
 271:       String name = null;
 272:       if (f != null)
 273:         {
 274:           JFileChooser c = getFileChooser();
 275:           FileSystemView v = c.getFileSystemView();
 276:           name = v.getSystemDisplayName(f);
 277:         }
 278:       return name;
 279:     }
 280: 
 281:     /**
 282:      * Returns a localised description for the type of file/directory.
 283:      *
 284:      * @param f  the file/directory.
 285:      *
 286:      * @return A type description for the given file/directory.
 287:      */
 288:     public String getTypeDescription(File f)
 289:     {
 290:       if (filechooser.isTraversable(f))
 291:     return dirDescText;
 292:       else
 293:     return fileDescText;
 294:     }
 295: 
 296:     /**
 297:      * Returns {@link Boolean#TRUE} if the given file/directory is hidden,
 298:      * and {@link Boolean#FALSE} otherwise.
 299:      *
 300:      * @param f  the file/directory.
 301:      *
 302:      * @return {@link Boolean#TRUE} or {@link Boolean#FALSE}.
 303:      */
 304:     public Boolean isHidden(File f)
 305:     {
 306:       return Boolean.valueOf(filechooser.getFileSystemView().isHiddenFile(f));
 307:     }
 308:   }
 309: 
 310:   /**
 311:    * Handles an action to cancel the file chooser.
 312:    * 
 313:    * @see BasicFileChooserUI#getCancelSelectionAction()
 314:    */
 315:   protected class CancelSelectionAction extends AbstractAction
 316:   {
 317:     /**
 318:      * Creates a new <code>CancelSelectionAction</code> object.
 319:      */
 320:     protected CancelSelectionAction()
 321:     {
 322:       super(null);
 323:     }
 324: 
 325:     /**
 326:      * Cancels the selection and closes the dialog.
 327:      *
 328:      * @param e  the action event (ignored).
 329:      */
 330:     public void actionPerformed(ActionEvent e)
 331:     {
 332:       filechooser.setSelectedFile(null);
 333:       filechooser.setSelectedFiles(null);
 334:       filechooser.cancelSelection();
 335:       closeDialog();
 336:     }
 337:   }
 338: 
 339:   /**
 340:    * An action to handle changes to the parent directory (for example, via
 341:    * a click on the "up folder" button).
 342:    * 
 343:    * @see BasicFileChooserUI#getChangeToParentDirectoryAction()
 344:    */
 345:   protected class ChangeToParentDirectoryAction extends AbstractAction
 346:   {
 347:     /**
 348:      * Creates a new <code>ChangeToParentDirectoryAction</code> object.
 349:      */
 350:     protected ChangeToParentDirectoryAction()
 351:     {
 352:       super("Go Up");
 353:     }
 354: 
 355:     /**
 356:      * Handles the action event.
 357:      *
 358:      * @param e  the action event.
 359:      */
 360:     public void actionPerformed(ActionEvent e)
 361:     {
 362:       filechooser.changeToParentDirectory();
 363:       filechooser.revalidate();
 364:       filechooser.repaint();
 365:     }
 366:   }
 367: 
 368:   /**
 369:    * A mouse listener that handles double-click events.
 370:    * 
 371:    * @see BasicFileChooserUI#createDoubleClickListener(JFileChooser, JList)
 372:    */
 373:   protected class DoubleClickListener extends MouseAdapter
 374:   {
 375: 
 376:     /** DOCUMENT ME! */
 377:     private Object lastSelected;
 378: 
 379:     /** DOCUMENT ME! */
 380:     private JList list;
 381: 
 382:     /**
 383:      * Creates a new DoubleClickListener object.
 384:      *
 385:      * @param list DOCUMENT ME!
 386:      */
 387:     public DoubleClickListener(JList list)
 388:     {
 389:       this.list = list;
 390:       lastSelected = list.getSelectedValue();
 391:       setDirectorySelected(false);
 392:     }
 393: 
 394:     /**
 395:      * Handles a mouse click event.
 396:      * 
 397:      * @param e  the event.
 398:      */
 399:     public void mouseClicked(MouseEvent e)
 400:     {
 401:       Object p = list.getSelectedValue();
 402:       if (p == null)
 403:         return;
 404:       FileSystemView fsv = filechooser.getFileSystemView();
 405:       if (e.getClickCount() >= 2 && lastSelected != null &&
 406:           p.toString().equals(lastSelected.toString()))
 407:         {
 408:           File f = fsv.createFileObject(lastSelected.toString());
 409:           if (filechooser.isTraversable(f))
 410:             {
 411:               filechooser.setCurrentDirectory(f);
 412:               filechooser.rescanCurrentDirectory();
 413:             }
 414:           else
 415:             {
 416:               filechooser.setSelectedFile(f);
 417:               filechooser.approveSelection();
 418:               closeDialog();
 419:             }
 420:         }
 421:       else // single click
 422:         {
 423:           String path = p.toString();
 424:           File f = fsv.createFileObject(path);
 425:           filechooser.setSelectedFile(f);
 426:           
 427:           if (filechooser.isMultiSelectionEnabled())
 428:             {
 429:               int[] inds = list.getSelectedIndices();
 430:               File[] allFiles = new File[inds.length];
 431:               for (int i = 0; i < inds.length; i++)
 432:                 allFiles[i] = (File) list.getModel().getElementAt(inds[i]);
 433:               filechooser.setSelectedFiles(allFiles);
 434:             }
 435:           
 436:           if (filechooser.isTraversable(f))
 437:             {
 438:               setDirectorySelected(true);
 439:               setDirectory(f);
 440:             }
 441:           else
 442:             {
 443:               setDirectorySelected(false);
 444:               setDirectory(null);
 445:             }
 446:           lastSelected = path;
 447:           parentPath = f.getParent();
 448:         
 449:           if (f.isFile())
 450:             setFileName(f.getName());
 451:           else if (filechooser.getFileSelectionMode() != 
 452:            JFileChooser.FILES_ONLY)
 453:             setFileName(path);
 454:         }
 455:     }
 456: 
 457:     /**
 458:      * Handles a mouse entered event (NOT IMPLEMENTED).
 459:      * 
 460:      * @param e  the mouse event.
 461:      */
 462:     public void mouseEntered(MouseEvent e)
 463:     {
 464:       // FIXME: Implement
 465:     }
 466:   }
 467: 
 468:   /**
 469:    * An action that changes the file chooser to display the user's home 
 470:    * directory. 
 471:    * 
 472:    * @see BasicFileChooserUI#getGoHomeAction()
 473:    */
 474:   protected class GoHomeAction extends AbstractAction
 475:   {
 476:     /**
 477:      * Creates a new <code>GoHomeAction</code> object.
 478:      */
 479:     protected GoHomeAction()
 480:     {
 481:       super("Go Home");
 482:     }
 483: 
 484:     /**
 485:      * Sets the directory to the user's home directory, and repaints the
 486:      * file chooser component.
 487:      *
 488:      * @param e  the action event (ignored).
 489:      */
 490:     public void actionPerformed(ActionEvent e)
 491:     {
 492:       filechooser.setCurrentDirectory(filechooser.getFileSystemView()
 493:                                                  .getHomeDirectory());
 494:       filechooser.revalidate();
 495:       filechooser.repaint();
 496:     }
 497:   }
 498: 
 499:   /**
 500:    * An action that handles the creation of a new folder/directory.
 501:    * 
 502:    * @see BasicFileChooserUI#getNewFolderAction()
 503:    */
 504:   protected class NewFolderAction extends AbstractAction
 505:   {
 506:     /**
 507:      * Creates a new <code>NewFolderAction</code> object.
 508:      */
 509:     protected NewFolderAction()
 510:     {
 511:       super("New Folder");
 512:     }
 513: 
 514:     /**
 515:      * Handles the event by creating a new folder.
 516:      *
 517:      * @param e  the action event (ignored).
 518:      */
 519:     public void actionPerformed(ActionEvent e)
 520:     {
 521:       try
 522:         {
 523:       filechooser.getFileSystemView().createNewFolder(filechooser
 524:                                                       .getCurrentDirectory());
 525:         }
 526:       catch (IOException ioe)
 527:         {
 528:       return;
 529:         }
 530:       filechooser.rescanCurrentDirectory();
 531:       filechooser.repaint();
 532:     }
 533:   }
 534: 
 535:   /**
 536:    * A listener for selection events in the file list.
 537:    * 
 538:    * @see BasicFileChooserUI#createListSelectionListener(JFileChooser)
 539:    */
 540:   protected class SelectionListener implements ListSelectionListener
 541:   {
 542:     /**
 543:      * Creates a new <code>SelectionListener</code> object.
 544:      */
 545:     protected SelectionListener()
 546:     {
 547:       // Nothing to do here.
 548:     }
 549: 
 550:     /**
 551:      * Sets the JFileChooser to the selected file on an update
 552:      *
 553:      * @param e DOCUMENT ME!
 554:      */
 555:     public void valueChanged(ListSelectionEvent e)
 556:     {
 557:       JList list = (JList) e.getSource();
 558:       Object f = list.getSelectedValue();
 559:       if (f == null)
 560:     return;
 561:       File file = filechooser.getFileSystemView().createFileObject(f.toString());
 562:       if (! filechooser.isTraversable(file))
 563:     {
 564:       selectedDir = null;
 565:       filechooser.setSelectedFile(file);
 566:     }
 567:       else
 568:     {
 569:       selectedDir = file;
 570:       filechooser.setSelectedFile(null);
 571:     }
 572:     }
 573:   }
 574: 
 575:   /**
 576:    * DOCUMENT ME!
 577:    * 
 578:    * @see BasicFileChooserUI#getUpdateAction()
 579:    */
 580:   protected class UpdateAction extends AbstractAction
 581:   {
 582:     /**
 583:      * Creates a new UpdateAction object.
 584:      */
 585:     protected UpdateAction()
 586:     {
 587:       super(null);
 588:     }
 589: 
 590:     /**
 591:      * NOT YET IMPLEMENTED.
 592:      *
 593:      * @param e  the action event.
 594:      */
 595:     public void actionPerformed(ActionEvent e)
 596:     {
 597:       // FIXME: implement this
 598:     }
 599:   }
 600: 
 601:   /** The localised mnemonic for the cancel button. */
 602:   protected int cancelButtonMnemonic;
 603: 
 604:   /** The localised text for the cancel button. */
 605:   protected String cancelButtonText;
 606: 
 607:   /** The localised tool tip text for the cancel button. */
 608:   protected String cancelButtonToolTipText;
 609: 
 610:   /** An icon representing a computer. */
 611:   protected Icon computerIcon;
 612: 
 613:   /** An icon for the "details view" button. */
 614:   protected Icon detailsViewIcon;
 615: 
 616:   /** An icon representing a directory. */
 617:   protected Icon directoryIcon;
 618: 
 619:   /** The localised Mnemonic for the open button. */
 620:   protected int directoryOpenButtonMnemonic;
 621: 
 622:   /** The localised text for the open button. */
 623:   protected String directoryOpenButtonText;
 624: 
 625:   /** The localised tool tip text for the open button. */
 626:   protected String directoryOpenButtonToolTipText;
 627: 
 628:   /** An icon representing a file. */
 629:   protected Icon fileIcon;
 630: 
 631:   /** An icon representing a floppy drive. */
 632:   protected Icon floppyDriveIcon;
 633: 
 634:   /** An icon representing a hard drive. */
 635:   protected Icon hardDriveIcon;
 636: 
 637:   /** The localised mnemonic for the "help" button. */
 638:   protected int helpButtonMnemonic;
 639: 
 640:   /** The localised text for the "help" button. */
 641:   protected String helpButtonText;
 642: 
 643:   /** The localised tool tip text for the help button. */
 644:   protected String helpButtonToolTipText;
 645: 
 646:   /** An icon representing the user's home folder. */
 647:   protected Icon homeFolderIcon;
 648: 
 649:   /** An icon for the "list view" button. */
 650:   protected Icon listViewIcon;
 651: 
 652:   /** An icon for the "new folder" button. */
 653:   protected Icon newFolderIcon = directoryIcon;
 654: 
 655:   /** The localised mnemonic for the "open" button. */
 656:   protected int openButtonMnemonic;
 657: 
 658:   /** The localised text for the "open" button. */
 659:   protected String openButtonText;
 660: 
 661:   /** The localised tool tip text for the "open" button. */
 662:   protected String openButtonToolTipText;
 663: 
 664:   /** The localised mnemonic for the "save" button. */
 665:   protected int saveButtonMnemonic;
 666: 
 667:   /** The localised text for the "save" button. */
 668:   protected String saveButtonText;
 669: 
 670:   /** The localised tool tip text for the save button. */
 671:   protected String saveButtonToolTipText;
 672: 
 673:   /** The localised mnemonic for the "update" button. */
 674:   protected int updateButtonMnemonic;
 675: 
 676:   /** The localised text for the "update" button. */
 677:   protected String updateButtonText;
 678: 
 679:   /** The localised tool tip text for the "update" button. */
 680:   protected String updateButtonToolTipText;
 681: 
 682:   /** An icon for the "up folder" button. */
 683:   protected Icon upFolderIcon;
 684: 
 685:   // -- begin private, but package local since used in inner classes --
 686: 
 687:   /** The file chooser component represented by this UI delegate. */
 688:   JFileChooser filechooser;
 689: 
 690:   /** The model for the directory list. */
 691:   BasicDirectoryModel model;
 692: 
 693:   /** The file filter for all files. */
 694:   FileFilter acceptAll = new AcceptAllFileFilter();
 695: 
 696:   /** The default file view. */
 697:   FileView fv = new BasicFileView();
 698: 
 699:   /** The accept (open/save) button. */
 700:   JButton accept;
 701: 
 702:   /** An optional accessory panel. */
 703:   JPanel accessoryPanel = new JPanel();
 704: 
 705:   /** A property change listener. */
 706:   PropertyChangeListener propertyChangeListener;
 707: 
 708:   /** The text describing the filter for "all files". */
 709:   String acceptAllFileFilterText;
 710: 
 711:   /** The text describing a directory type. */
 712:   String dirDescText;
 713: 
 714:   /** The text describing a file type. */
 715:   String fileDescText;
 716: 
 717:   /** Is a directory selected? */
 718:   boolean dirSelected;
 719: 
 720:   /** The current directory. */
 721:   File currDir;
 722: 
 723:   // FIXME: describe what is contained in the bottom panel
 724:   /** The bottom panel. */
 725:   JPanel bottomPanel;
 726:   
 727:   /** The close panel. */
 728:   JPanel closePanel;
 729: 
 730:   /** Text box that displays file name */
 731:   JTextField entry;
 732:     
 733:   /** Current parent path */
 734:   String parentPath;
 735:   
 736:   /**
 737:    * The action for the 'approve' button.
 738:    * @see #getApproveSelectionAction()
 739:    */
 740:   private ApproveSelectionAction approveSelectionAction;
 741:   
 742:   /**
 743:    * The action for the 'cancel' button.
 744:    * @see #getCancelSelectionAction()
 745:    */
 746:   private CancelSelectionAction cancelSelectionAction;
 747:   
 748:   /**
 749:    * The action for the 'go home' control button.
 750:    * @see #getGoHomeAction()
 751:    */
 752:   private GoHomeAction goHomeAction;
 753:   
 754:   /**
 755:    * The action for the 'up folder' control button.
 756:    * @see #getChangeToParentDirectoryAction()
 757:    */
 758:   private ChangeToParentDirectoryAction changeToParentDirectoryAction;
 759:   
 760:   /**
 761:    * The action for the 'new folder' control button.
 762:    * @see #getNewFolderAction()
 763:    */
 764:   private NewFolderAction newFolderAction;
 765:   
 766:   /**
 767:    * The action for ???.  // FIXME: what is this?
 768:    * @see #getUpdateAction()
 769:    */
 770:   private UpdateAction updateAction;
 771: 
 772:   /**
 773:    * When in FILES_ONLY, mode a directory cannot be selected, so
 774:    * we save a reference to any it here. This is used to enter
 775:    * the directory on "Open" when in that mode.
 776:    */
 777:   private File selectedDir;
 778:   
 779:   // -- end private --
 780: 
 781:   /**
 782:    * Closes the dialog.
 783:    */
 784:   void closeDialog()
 785:   {
 786:     Window owner = SwingUtilities.windowForComponent(filechooser);
 787:     if (owner instanceof JDialog)
 788:       ((JDialog) owner).dispose();
 789:   }
 790: 
 791:   /**
 792:    * Creates a new <code>BasicFileChooserUI</code> object.
 793:    *
 794:    * @param b  the file chooser component.
 795:    */
 796:   public BasicFileChooserUI(JFileChooser b)
 797:   {
 798:   }
 799: 
 800:   /**
 801:    * Returns a UI delegate for the given component.
 802:    *
 803:    * @param c  the component (should be a {@link JFileChooser}).
 804:    *
 805:    * @return A new UI delegate.
 806:    */
 807:   public static ComponentUI createUI(JComponent c)
 808:   {
 809:     return new BasicFileChooserUI((JFileChooser) c);
 810:   }
 811: 
 812:   /**
 813:    * Installs the UI for the specified component.
 814:    * 
 815:    * @param c  the component (should be a {@link JFileChooser}).
 816:    */
 817:   public void installUI(JComponent c)
 818:   {
 819:     if (c instanceof JFileChooser)
 820:       {
 821:         JFileChooser fc = (JFileChooser) c;
 822:         this.filechooser = fc;
 823:         fc.resetChoosableFileFilters();
 824:         createModel();
 825:         clearIconCache();
 826:         installDefaults(fc);
 827:         installComponents(fc);
 828:         installListeners(fc);
 829:         
 830:         File path = filechooser.getCurrentDirectory();
 831:         if (path != null)
 832:           parentPath = path.getParent();
 833:       }
 834:   }
 835: 
 836:   /**
 837:    * Uninstalls this UI from the given component.
 838:    * 
 839:    * @param c  the component (should be a {@link JFileChooser}).
 840:    */
 841:   public void uninstallUI(JComponent c)
 842:   {
 843:     model = null;
 844:     uninstallListeners(filechooser);
 845:     uninstallComponents(filechooser);
 846:     uninstallDefaults(filechooser);
 847:     filechooser = null;
 848:   }
 849: 
 850:   // FIXME: Indent the entries in the combobox
 851:   // Made this method package private to access it from within inner classes
 852:   // with better performance
 853:   void boxEntries()
 854:   {
 855:     ArrayList parentFiles = new ArrayList();
 856:     File parent = filechooser.getCurrentDirectory();
 857:     if (parent == null)
 858:       parent = filechooser.getFileSystemView().getDefaultDirectory();
 859:     while (parent != null)
 860:       {
 861:         String name = parent.getName();
 862:         if (name.equals(""))
 863:           name = parent.getAbsolutePath();
 864: 
 865:         parentFiles.add(parentFiles.size(), name);
 866:         parent = parent.getParentFile();
 867:       }
 868: 
 869:     if (parentFiles.size() == 0)
 870:       return;
 871: 
 872:   }  
 873: 
 874:   /**
 875:    * Creates and install the subcomponents for the file chooser.
 876:    *
 877:    * @param fc  the file chooser.
 878:    */
 879:   public void installComponents(JFileChooser fc)
 880:   {
 881:   }
 882: 
 883:   /**
 884:    * Uninstalls the components from the file chooser.
 885:    *
 886:    * @param fc  the file chooser.
 887:    */
 888:   public void uninstallComponents(JFileChooser fc)
 889:   {
 890:   }
 891: 
 892:   /**
 893:    * Installs the listeners required by this UI delegate.
 894:    *
 895:    * @param fc  the file chooser.
 896:    */
 897:   protected void installListeners(JFileChooser fc)
 898:   {
 899:     propertyChangeListener = createPropertyChangeListener(filechooser);
 900:     if (propertyChangeListener != null)
 901:       filechooser.addPropertyChangeListener(propertyChangeListener);
 902:     fc.addPropertyChangeListener(getModel());
 903:   }
 904: 
 905:   /**
 906:    * Uninstalls the listeners previously installed by this UI delegate.
 907:    *
 908:    * @param fc  the file chooser.
 909:    */
 910:   protected void uninstallListeners(JFileChooser fc)
 911:   {
 912:     if (propertyChangeListener != null)
 913:       {
 914:         filechooser.removePropertyChangeListener(propertyChangeListener);
 915:         propertyChangeListener = null;
 916:       }
 917:     fc.removePropertyChangeListener(getModel());
 918:   }
 919: 
 920:   /**
 921:    * Installs the defaults for this UI delegate.
 922:    *
 923:    * @param fc  the file chooser.
 924:    */
 925:   protected void installDefaults(JFileChooser fc)
 926:   {
 927:     installIcons(fc);
 928:     installStrings(fc);
 929:   }
 930: 
 931:   /**
 932:    * Uninstalls the defaults previously added by this UI delegate.
 933:    *
 934:    * @param fc  the file chooser.
 935:    */
 936:   protected void uninstallDefaults(JFileChooser fc)
 937:   {
 938:     uninstallStrings(fc);
 939:     uninstallIcons(fc);
 940:   }
 941: 
 942:   /**
 943:    * Installs the icons for this UI delegate.
 944:    *
 945:    * @param fc  the file chooser (ignored).
 946:    */
 947:   protected void installIcons(JFileChooser fc)
 948:   {
 949:     UIDefaults defaults = UIManager.getLookAndFeelDefaults();
 950:     computerIcon = MetalIconFactory.getTreeComputerIcon();
 951:     detailsViewIcon = defaults.getIcon("FileChooser.detailsViewIcon");
 952:     directoryIcon = new MetalIconFactory.TreeFolderIcon();
 953:     fileIcon = new MetalIconFactory.TreeLeafIcon();
 954:     floppyDriveIcon = MetalIconFactory.getTreeFloppyDriveIcon();
 955:     hardDriveIcon = MetalIconFactory.getTreeHardDriveIcon();
 956:     homeFolderIcon = d