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 = defaults.getIcon("FileChooser.homeFolderIcon");
 957:     listViewIcon = defaults.getIcon("FileChooser.listViewIcon");
 958:     newFolderIcon = defaults.getIcon("FileChooser.newFolderIcon");
 959:     upFolderIcon = defaults.getIcon("FileChooser.upFolderIcon");
 960:   }
 961: 
 962:   /**
 963:    * Uninstalls the icons previously added by this UI delegate.
 964:    *
 965:    * @param fc  the file chooser.
 966:    */
 967:   protected void uninstallIcons(JFileChooser fc)
 968:   {
 969:     computerIcon = null;
 970:     detailsViewIcon = null;
 971:     directoryIcon = null;
 972:     fileIcon = null;
 973:     floppyDriveIcon = null;
 974:     hardDriveIcon = null;
 975:     homeFolderIcon = null;
 976:     listViewIcon = null;
 977:     newFolderIcon = null;
 978:     upFolderIcon = null;
 979:   }
 980: 
 981:   /**
 982:    * Installs the strings used by this UI delegate.
 983:    *
 984:    * @param fc  the file chooser.
 985:    */
 986:   protected void installStrings(JFileChooser fc)
 987:   {
 988:     UIDefaults defaults = UIManager.getLookAndFeelDefaults();
 989: 
 990:     dirDescText = defaults.getString("FileChooser.directoryDescriptionText");
 991:     fileDescText = defaults.getString("FileChooser.fileDescriptionText");
 992: 
 993:     acceptAllFileFilterText = defaults.getString("FileChooser.acceptAllFileFilterText");
 994:     cancelButtonText = "Cancel";
 995:     cancelButtonToolTipText = "Abort file chooser dialog";
 996:     cancelButtonMnemonic = new Integer((String) UIManager.get("FileChooser.cancelButtonMnemonic")).intValue();
 997: 
 998:     directoryOpenButtonText = "Open";
 999:     directoryOpenButtonToolTipText = "Open selected directory";
1000:     directoryOpenButtonMnemonic 
1001:         = new Integer((String) UIManager.get("FileChooser.directoryOpenButtonMnemonic")).intValue();
1002:     
1003:     helpButtonText = "Help";
1004:     helpButtonToolTipText = "FileChooser help";
1005:     helpButtonMnemonic = new Integer((String) UIManager.get("FileChooser.helpButtonMnemonic")).intValue();
1006: 
1007:     openButtonText = "Open";
1008:     openButtonToolTipText = "Open selected file";
1009:     openButtonMnemonic = new Integer((String) UIManager.get("FileChooser.openButtonMnemonic")).intValue();
1010: 
1011:     saveButtonText = "Save";
1012:     saveButtonToolTipText = "Save selected file";
1013:     saveButtonMnemonic = new Integer((String) UIManager.get("FileChooser.saveButtonMnemonic")).intValue();
1014:   
1015:     updateButtonText = "Update";
1016:     updateButtonToolTipText = "Update directory listing";
1017:     updateButtonMnemonic = new Integer((String) UIManager.get("FileChooser.updateButtonMnemonic")).intValue();
1018:   }
1019: 
1020:   /**
1021:    * Uninstalls the strings previously added by this UI delegate.
1022:    *
1023:    * @param fc  the file chooser.
1024:    */
1025:   protected void uninstallStrings(JFileChooser fc)
1026:   {
1027:     acceptAllFileFilterText = null;
1028:     dirDescText = null;
1029:     fileDescText = null;
1030: 
1031:     cancelButtonText = null;
1032:     cancelButtonToolTipText = null;
1033: 
1034:     directoryOpenButtonText = null;
1035:     directoryOpenButtonToolTipText = null;
1036: 
1037:     helpButtonText = null;
1038:     helpButtonToolTipText = null;
1039: 
1040:     openButtonText = null;
1041:     openButtonToolTipText = null;
1042: 
1043:     saveButtonText = null;
1044:     saveButtonToolTipText = null;
1045:     
1046:     updateButtonText = null;
1047:     updateButtonToolTipText = null;
1048:   }
1049: 
1050:   /**
1051:    * Creates a new directory model.
1052:    */
1053:   protected void createModel()
1054:   {
1055:     model = new BasicDirectoryModel(filechooser);
1056:   }
1057: 
1058:   /**
1059:    * Returns the directory model.
1060:    *
1061:    * @return The directory model.
1062:    */
1063:   public BasicDirectoryModel getModel()
1064:   {
1065:     return model;
1066:   }
1067: 
1068:   /**
1069:    * Creates a listener to handle changes to the properties of the given
1070:    * file chooser component.
1071:    * 
1072:    * @param fc  the file chooser component.
1073:    * 
1074:    * @return A new listener.
1075:    */
1076:   public PropertyChangeListener createPropertyChangeListener(JFileChooser fc)
1077:   {
1078:     // The RI returns null here, so do we.
1079:     return null;
1080:   }
1081: 
1082:   /**
1083:    * Returns the current file name.
1084:    * 
1085:    * @return The current file name.
1086:    */
1087:   public String getFileName()
1088:   {
1089:     return entry.getText();
1090:   }
1091: 
1092:   /**
1093:    * Returns the current directory name.
1094:    *
1095:    * @return The directory name.
1096:    * 
1097:    * @see #setDirectoryName(String)
1098:    */
1099:   public String getDirectoryName()
1100:   {
1101:     // XXX: I don't see a case where the thing returns something non-null..
1102:     return null;
1103:   }
1104: 
1105:   /**
1106:    * Sets the file name.
1107:    *
1108:    * @param filename  the file name.
1109:    * 
1110:    * @see #getFileName()
1111:    */
1112:   public void setFileName(String filename)
1113:   {
1114:     // FIXME:  it might be the case that this method provides an access 
1115:     // point for the JTextField (or whatever) a subclass is using...
1116:     //this.filename = filename;
1117:   }
1118: 
1119:   /**
1120:    * Sets the directory name (NOT IMPLEMENTED).
1121:    *
1122:    * @param dirname  the directory name.
1123:    * 
1124:    * @see #getDirectoryName()
1125:    */
1126:   public void setDirectoryName(String dirname)
1127:   {
1128:     // FIXME: Implement
1129:   }
1130: 
1131:   /**
1132:    * Rescans the current directory.
1133:    *
1134:    * @param fc  the file chooser.
1135:    */
1136:   public void rescanCurrentDirectory(JFileChooser fc)
1137:   {
1138:     getModel().validateFileCache();
1139:   }
1140: 
1141:   /**
1142:    * NOT YET IMPLEMENTED.
1143:    *
1144:    * @param fc  the file chooser.
1145:    * @param f  the file.
1146:    */
1147:   public void ensureFileIsVisible(JFileChooser fc, File f)
1148:   {
1149:     // XXX: Not sure what this does.
1150:   }
1151: 
1152:   /**
1153:    * Returns the {@link JFileChooser} component that this UI delegate 
1154:    * represents.
1155:    *
1156:    * @return The component represented by this UI delegate.
1157:    */
1158:   public JFileChooser getFileChooser()
1159:   {
1160:     return filechooser;
1161:   }
1162: 
1163:   /**
1164:    * Returns the optional accessory panel.
1165:    *
1166:    * @return The optional accessory panel.
1167:    */
1168:   public JPanel getAccessoryPanel()
1169:   {
1170:     return accessoryPanel;
1171:   }
1172: 
1173:   /**
1174:    * Returns the approve (open or save) button for the dialog.
1175:    *
1176:    * @param fc  the file chooser.
1177:    *
1178:    * @return The button.
1179:    */
1180:   protected JButton getApproveButton(JFileChooser fc)
1181:   {
1182:     return accept;
1183:   }
1184: 
1185:   /**
1186:    * Returns the tool tip text for the approve (open/save) button.  This first
1187:    * checks the file chooser to see if a value has been explicitly set - if
1188:    * not, a default value appropriate for the type of file chooser is 
1189:    * returned.
1190:    *
1191:    * @param fc  the file chooser.
1192:    *
1193:    * @return The tool tip text.
1194:    */
1195:   public String getApproveButtonToolTipText(JFileChooser fc)
1196:   {
1197:     if (fc.getApproveButtonToolTipText() != null)
1198:       return fc.getApproveButtonToolTipText();
1199:     else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG)
1200:       return saveButtonToolTipText;
1201:     else
1202:       return openButtonToolTipText;
1203:   }
1204: 
1205:   /**
1206:    * Clears the icon cache.
1207:    */
1208:   public void clearIconCache()
1209:   {
1210:     if (fv instanceof BasicFileView)
1211:       ((BasicFileView) fv).clearIconCache();
1212:   }
1213: 
1214:   /**
1215:    * Creates a new listener to handle selections in the file list.
1216:    *
1217:    * @param fc  the file chooser component.
1218:    *
1219:    * @return A new instance of {@link SelectionListener}.
1220:    */
1221:   public ListSelectionListener createListSelectionListener(JFileChooser fc)
1222:   {
1223:     return new SelectionListener();
1224:   }
1225: 
1226:   /**
1227:    * Creates a new listener to handle double-click events.
1228:    *
1229:    * @param fc  the file chooser component.
1230:    * @param list  the list.
1231:    *
1232:    * @return A new instance of {@link DoubleClickListener}.
1233:    */
1234:   protected MouseListener createDoubleClickListener(JFileChooser fc, JList list)
1235:   {
1236:     return new DoubleClickListener(list);
1237:   }
1238: 
1239:   /**
1240:    * Returns <code>true</code> if a directory is selected, and 
1241:    * <code>false</code> otherwise.
1242:    *
1243:    * @return A boolean.
1244:    */
1245:   protected boolean isDirectorySelected()
1246:   {
1247:     return dirSelected;
1248:   }
1249: 
1250:   /**
1251:    * Sets the flag that indicates whether the current directory is selected.
1252:    *
1253:    * @param selected  the new flag value.
1254:    */
1255:   protected void setDirectorySelected(boolean selected)
1256:   {
1257:     dirSelected = selected;
1258:   }
1259: 
1260:   /**
1261:    * Returns the current directory.
1262:    *
1263:    * @return The current directory.
1264:    */
1265:   protected File getDirectory()
1266:   {
1267:     return currDir;
1268:   }
1269: 
1270:   /**
1271:    * Sets the current directory.
1272:    *
1273:    * @param f  the directory.
1274:    */
1275:   protected void setDirectory(File f)
1276:   {
1277:     currDir = f;
1278:   }
1279: 
1280:   /**
1281:    * Returns the "accept all" file filter.
1282:    *
1283:    * @param fc  the file chooser component.
1284:    *
1285:    * @return The "accept all" file filter.
1286:    */
1287:   public FileFilter getAcceptAllFileFilter(JFileChooser fc)
1288:   {
1289:     return acceptAll;
1290:   }
1291: 
1292:   /**
1293:    * Returns the default file view (NOT the file view from the file chooser,
1294:    * if there is one).
1295:    *
1296:    * @param fc  the file chooser component.
1297:    *
1298:    * @return The file view.
1299:    * 
1300:    * @see JFileChooser#getFileView()
1301:    */
1302:   public FileView getFileView(JFileChooser fc)
1303:   {
1304:     return fv;
1305:   }
1306: 
1307:   /**
1308:    * Returns the dialog title.
1309:    *
1310:    * @param fc  the file chooser (<code>null</code> not permitted).
1311:    *
1312:    * @return The dialog title.
1313:    * 
1314:    * @see JFileChooser#getDialogTitle()
1315:    */
1316:   public String getDialogTitle(JFileChooser fc)
1317:   {
1318:     String result = fc.getDialogTitle();
1319:     if (result == null)
1320:       result = getApproveButtonText(fc);
1321:     return result;
1322:   }
1323: 
1324:   /**
1325:    * Returns the approve button mnemonic.
1326:    *
1327:    * @param fc  the file chooser (<code>null</code> not permitted).
1328:    *
1329:    * @return The approve button mnemonic.
1330:    * 
1331:    * @see JFileChooser#getApproveButtonMnemonic()
1332:    */
1333:   public int getApproveButtonMnemonic(JFileChooser fc)
1334:   {
1335:     if (fc.getApproveButtonMnemonic() != 0)
1336:       return fc.getApproveButtonMnemonic();
1337:     else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG)
1338:       return saveButtonMnemonic;
1339:     else
1340:       return openButtonMnemonic;
1341:   }
1342: 
1343:   /**
1344:    * Returns the approve button text.
1345:    *
1346:    * @param fc  the file chooser (<code>null</code> not permitted).
1347:    *
1348:    * @return The approve button text.
1349:    * 
1350:    * @see JFileChooser#getApproveButtonText()
1351:    */
1352:   public String getApproveButtonText(JFileChooser fc)
1353:   {
1354:     String result = fc.getApproveButtonText();
1355:     if (result == null)
1356:       {
1357:         if (fc.getDialogType() == JFileChooser.SAVE_DIALOG)
1358:           result = saveButtonText;
1359:         else
1360:           result = openButtonText;
1361:       }
1362:     return result;
1363:   }
1364: 
1365:   /**
1366:    * Creates and returns a new action that will be used with the "new folder" 
1367:    * button.
1368:    *
1369:    * @return A new instance of {@link NewFolderAction}.
1370:    */
1371:   public Action getNewFolderAction()
1372:   {
1373:     if (newFolderAction == null)
1374:       newFolderAction = new NewFolderAction();
1375:     return newFolderAction;
1376:   }
1377: 
1378:   /**
1379:    * Creates and returns a new action that will be used with the "home folder" 
1380:    * button.
1381:    *
1382:    * @return A new instance of {@link GoHomeAction}.
1383:    */
1384:   public Action getGoHomeAction()
1385:   {
1386:     if (goHomeAction == null)
1387:       goHomeAction = new GoHomeAction();
1388:     return goHomeAction;
1389:   }
1390: 
1391:   /**
1392:    * Returns the action that handles events for the "up folder" control button.
1393:    *
1394:    * @return An instance of {@link ChangeToParentDirectoryAction}.
1395:    */
1396:   public Action getChangeToParentDirectoryAction()
1397:   {
1398:     if (changeToParentDirectoryAction == null)
1399:       changeToParentDirectoryAction = new ChangeToParentDirectoryAction();
1400:     return changeToParentDirectoryAction;
1401:   }
1402: 
1403:   /**
1404:    * Returns the action that handles events for the "approve" button.
1405:    *
1406:    * @return An instance of {@link ApproveSelectionAction}.
1407:    */
1408:   public Action getApproveSelectionAction()
1409:   {
1410:     if (approveSelectionAction == null)
1411:       approveSelectionAction = new ApproveSelectionAction();
1412:     return approveSelectionAction;
1413:   }
1414: 
1415:   /**
1416:    * Returns the action that handles events for the "cancel" button.
1417:    *
1418:    * @return An instance of {@link CancelSelectionAction}.
1419:    */
1420:   public Action getCancelSelectionAction()
1421:   {
1422:     if (cancelSelectionAction == null)
1423:       cancelSelectionAction = new CancelSelectionAction();
1424:     return cancelSelectionAction;
1425:   }
1426: 
1427:   /**
1428:    * Returns the update action (an instance of {@link UpdateAction}).
1429:    *
1430:    * @return An action. 
1431:    */
1432:   public Action getUpdateAction()
1433:   {
1434:     if (updateAction == null)
1435:       updateAction = new UpdateAction();
1436:     return updateAction;
1437:   }
1438: }