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.BorderLayout;
  41: import java.awt.Color;
  42: import java.awt.Component;
  43: import java.awt.Dimension;
  44: import java.awt.Graphics;
  45: import java.awt.GridBagConstraints;
  46: import java.awt.GridBagLayout;
  47: import java.awt.Point;
  48: import java.awt.Polygon;
  49: import java.awt.Window;
  50: import java.awt.event.ActionEvent;
  51: import java.awt.event.ItemEvent;
  52: import java.awt.event.ItemListener;
  53: import java.awt.event.MouseAdapter;
  54: import java.awt.event.MouseEvent;
  55: import java.awt.event.MouseListener;
  56: import java.beans.PropertyChangeEvent;
  57: import java.beans.PropertyChangeListener;
  58: import java.io.File;
  59: import java.io.IOException;
  60: import java.util.ArrayList;
  61: import java.util.Hashtable;
  62: 
  63: import javax.swing.AbstractAction;
  64: import javax.swing.Action;
  65: import javax.swing.ButtonGroup;
  66: import javax.swing.Icon;
  67: import javax.swing.JButton;
  68: import javax.swing.JComboBox;
  69: import javax.swing.JComponent;
  70: import javax.swing.JDialog;
  71: import javax.swing.JFileChooser;
  72: import javax.swing.JLabel;
  73: import javax.swing.JList;
  74: import javax.swing.JPanel;
  75: import javax.swing.JScrollPane;
  76: import javax.swing.JTextField;
  77: import javax.swing.JToggleButton;
  78: import javax.swing.ListCellRenderer;
  79: import javax.swing.SwingConstants;
  80: import javax.swing.SwingUtilities;
  81: import javax.swing.Timer;
  82: import javax.swing.UIDefaults;
  83: import javax.swing.UIManager;
  84: import javax.swing.event.ListSelectionEvent;
  85: import javax.swing.event.ListSelectionListener;
  86: import javax.swing.filechooser.FileFilter;
  87: import javax.swing.filechooser.FileSystemView;
  88: import javax.swing.filechooser.FileView;
  89: import javax.swing.plaf.ComponentUI;
  90: import javax.swing.plaf.FileChooserUI;
  91: 
  92: 
  93: /**
  94:  * A UI delegate for the {@link JFileChooser} component under the 
  95:  * {@link BasicLookAndFeel}.
  96:  */
  97: public class BasicFileChooserUI extends FileChooserUI
  98: {
  99:   /**
 100:    * A file filter that accepts all files.
 101:    */
 102:   protected class AcceptAllFileFilter extends FileFilter
 103:   {
 104:     /**
 105:      * Creates a new instance.
 106:      */
 107:     public AcceptAllFileFilter()
 108:     {
 109:       // Nothing to do here.
 110:     }
 111:     
 112:     /**
 113:      * Returns <code>true</code> always, as all files are accepted by this
 114:      * filter.
 115:      *
 116:      * @param f  the file.
 117:      *
 118:      * @return Always <code>true</code>.
 119:      */
 120:     public boolean accept(File f)
 121:     {
 122:       return true;
 123:     }
 124: 
 125:     /**
 126:      * Returns a description for this filter.
 127:      *
 128:      * @return A description for the file filter.
 129:      */
 130:     public String getDescription()
 131:     {
 132:       return acceptAllFileFilterText;
 133:     }
 134:   }
 135: 
 136:   /**
 137:    * Handles a user action to approve the dialog selection.
 138:    * 
 139:    * @see BasicFileChooserUI#getApproveSelectionAction()
 140:    */
 141:   protected class ApproveSelectionAction extends AbstractAction
 142:   {
 143:     /**
 144:      * Creates a new ApproveSelectionAction object.
 145:      */
 146:     protected ApproveSelectionAction()
 147:     {
 148:       // Nothing to do here.
 149:     }
 150: 
 151:     /**
 152:      * Sets the current selection and closes the dialog.
 153:      * 
 154:      * @param e  the action event.
 155:      */
 156:     public void actionPerformed(ActionEvent e)
 157:     {
 158:       Object obj = new String(parentPath + entry.getText());
 159:       if (obj != null)
 160:         {
 161:           File f = filechooser.getFileSystemView().createFileObject(
 162:                                                                     obj.toString());
 163:           if (filechooser.isTraversable(f)
 164:               && filechooser.isDirectorySelectionEnabled())
 165:             filechooser.setCurrentDirectory(f);
 166:           else
 167:             {
 168:               filechooser.setSelectedFile(f);
 169:               filechooser.approveSelection();
 170:               closeDialog();
 171:             }
 172:         }
 173:     }
 174:   }
 175: 
 176:   /**
 177:    * Provides presentation information about files and directories.
 178:    */
 179:   protected class BasicFileView extends FileView
 180:   {
 181:     /** Storage for cached icons. */
 182:     protected Hashtable iconCache = new Hashtable();
 183: 
 184:     /**
 185:      * Creates a new instance.
 186:      */
 187:     public BasicFileView()
 188:     {
 189:       // Nothing to do here.
 190:     }
 191: 
 192:     /**
 193:      * Adds an icon to the cache, associating it with the given file/directory.
 194:      *
 195:      * @param f  the file/directory.
 196:      * @param i  the icon.
 197:      */
 198:     public void cacheIcon(File f, Icon i)
 199:     {
 200:       iconCache.put(f, i);
 201:     }
 202: 
 203:     /**
 204:      * Clears the icon cache.
 205:      */
 206:     public void clearIconCache()
 207:     {
 208:       iconCache.clear();
 209:     }
 210: 
 211:     /**
 212:      * Retrieves the icon associated with the specified file/directory, if 
 213:      * there is one.
 214:      *
 215:      * @param f  the file/directory.
 216:      *
 217:      * @return The cached icon (or <code>null</code>).
 218:      */
 219:     public Icon getCachedIcon(File f)
 220:     {
 221:       return (Icon) iconCache.get(f);
 222:     }
 223: 
 224:     /**
 225:      * Returns a description of the given file/directory.  In this 
 226:      * implementation, the description is the same as the name returned by 
 227:      * {@link #getName(File)}.
 228:      *
 229:      * @param f  the file/directory.
 230:      *
 231:      * @return A description of the given file/directory.
 232:      */
 233:     public String getDescription(File f)
 234:     {
 235:       return getName(f);
 236:     }
 237: 
 238:     /**
 239:      * Returns an icon appropriate for the given file or directory.
 240:      *
 241:      * @param f  the file/directory.
 242:      *
 243:      * @return An icon.
 244:      */
 245:     public Icon getIcon(File f)
 246:     {
 247:       Icon val = getCachedIcon(f);
 248:       if (val != null)
 249:     return val;
 250:       if (filechooser.isTraversable(f))
 251:     val = directoryIcon;
 252:       else
 253:     val = fileIcon;
 254:       cacheIcon(f, val);
 255:       return val;
 256:     }
 257: 
 258:     /**
 259:      * Returns the name for the given file/directory.
 260:      *
 261:      * @param f  the file/directory.
 262:      *
 263:      * @return The name of the file/directory.
 264:      */
 265:     public String getName(File f)
 266:     {
 267:       return f.getName();
 268:     }
 269: 
 270:     /**
 271:      * Returns a localised description for the type of file/directory.
 272:      *
 273:      * @param f  the file/directory.
 274:      *
 275:      * @return A type description for the given file/directory.
 276:      */
 277:     public String getTypeDescription(File f)
 278:     {
 279:       if (filechooser.isTraversable(f))
 280:     return dirDescText;
 281:       else
 282:     return fileDescText;
 283:     }
 284: 
 285:     /**
 286:      * Returns {@link Boolean#TRUE} if the given file/directory is hidden,
 287:      * and {@link Boolean#FALSE} otherwise.
 288:      *
 289:      * @param f  the file/directory.
 290:      *
 291:      * @return {@link Boolean#TRUE} or {@link Boolean#FALSE}.
 292:      */
 293:     public Boolean isHidden(File f)
 294:     {
 295:       return Boolean.valueOf(filechooser.getFileSystemView().isHiddenFile(f));
 296:     }
 297:   }
 298: 
 299:   /**
 300:    * Handles an action to cancel the file chooser.
 301:    * 
 302:    * @see BasicFileChooserUI#getCancelSelectionAction()
 303:    */
 304:   protected class CancelSelectionAction extends AbstractAction
 305:   {
 306:     /**
 307:      * Creates a new <code>CancelSelectionAction</code> object.
 308:      */
 309:     protected CancelSelectionAction()
 310:     {
 311:       // Nothing to do here.
 312:     }
 313: 
 314:     /**
 315:      * Cancels the selection and closes the dialog.
 316:      *
 317:      * @param e  the action event (ignored).
 318:      */
 319:     public void actionPerformed(ActionEvent e)
 320:     {
 321:       filechooser.cancelSelection();
 322:       closeDialog();
 323:     }
 324:   }
 325: 
 326:   /**
 327:    * An action to handle changes to the parent directory (for example, via
 328:    * a click on the "up folder" button).
 329:    * 
 330:    * @see BasicFileChooserUI#getChangeToParentDirectoryAction()
 331:    */
 332:   protected class ChangeToParentDirectoryAction extends AbstractAction
 333:   {
 334:     /**
 335:      * Creates a new <code>ChangeToParentDirectoryAction</code> object.
 336:      */
 337:     protected ChangeToParentDirectoryAction()
 338:     {
 339:       // Nothing to do here.
 340:     }
 341: 
 342:     /**
 343:      * Handles the action event.
 344:      *
 345:      * @param e  the action event.
 346:      */
 347:     public void actionPerformed(ActionEvent e)
 348:     {
 349:       filechooser.changeToParentDirectory();
 350:       filechooser.revalidate();
 351:       filechooser.repaint();
 352:     }
 353:   }
 354: 
 355:   /**
 356:    * A mouse listener that handles double-click events.
 357:    * 
 358:    * @see BasicFileChooserUI#createDoubleClickListener(JFileChooser, JList)
 359:    */
 360:   protected class DoubleClickListener extends MouseAdapter
 361:   {
 362:     /** A timer. */
 363:     private Timer timer = null;
 364: 
 365:     /** DOCUMENT ME! */
 366:     private Object lastSelected = null;
 367: 
 368:     /** DOCUMENT ME! */
 369:     private JList list = null;
 370: 
 371:     /**
 372:      * Creates a new DoubleClickListener object.
 373:      *
 374:      * @param list DOCUMENT ME!
 375:      */
 376:     public DoubleClickListener(JList list)
 377:     {
 378:       this.list = list;
 379:       timer = new Timer(1000, null);
 380:       timer.setRepeats(false);
 381:       lastSelected = list.getSelectedValue();
 382:       setDirectorySelected(false);
 383:     }
 384: 
 385:     /**
 386:      * Handles a mouse click event.
 387:      * 
 388:      * @param e  the event.
 389:      */
 390:     public void mouseClicked(MouseEvent e)
 391:     {
 392:       if (list.getSelectedValue() == null)
 393:         return;
 394:       FileSystemView fsv = filechooser.getFileSystemView();
 395:       if (timer.isRunning()
 396:           && list.getSelectedValue().toString().equals(lastSelected.toString()))
 397:         {
 398:           File f = fsv.createFileObject(lastSelected.toString());
 399:           timer.stop();
 400:           if (filechooser.isTraversable(f))
 401:             {
 402:               filechooser.setCurrentDirectory(f);
 403:               filechooser.rescanCurrentDirectory();
 404:             }
 405:           else
 406:             {
 407:               filechooser.setSelectedFile(f);
 408:               filechooser.approveSelection();
 409:               closeDialog();
 410:             }
 411:         }
 412:       else
 413:         {
 414:           String path = list.getSelectedValue().toString();
 415:           File f = fsv.createFileObject(path);
 416:           if (filechooser.isTraversable(f))
 417:             {
 418:               setDirectorySelected(true);
 419:               setDirectory(f);
 420:             }
 421:           else
 422:             {
 423:               setDirectorySelected(false);
 424:               setDirectory(null);
 425:             }
 426:           lastSelected = path;
 427:           parentPath = path.substring(0, path.lastIndexOf("/") + 1);
 428:           entry.setText(path.substring(path.lastIndexOf("/") + 1));
 429:           timer.restart();
 430:         }
 431:     }
 432: 
 433:     /**
 434:      * Handles a mouse entered event (NOT IMPLEMENTED).
 435:      * 
 436:      * @param e  the mouse event.
 437:      */
 438:     public void mouseEntered(MouseEvent e)
 439:     {
 440:       // FIXME: Implement
 441:     }
 442:   }
 443: 
 444:   /**
 445:    * An action that changes the file chooser to display the user's home 
 446:    * directory. 
 447:    * 
 448:    * @see BasicFileChooserUI#getGoHomeAction()
 449:    */
 450:   protected class GoHomeAction extends AbstractAction
 451:   {
 452:     /**
 453:      * Creates a new <code>GoHomeAction</code> object.
 454:      */
 455:     protected GoHomeAction()
 456:     {
 457:       // Nothing to do here.
 458:     }
 459: 
 460:     /**
 461:      * Sets the directory to the user's home directory, and repaints the
 462:      * file chooser component.
 463:      *
 464:      * @param e  the action event (ignored).
 465:      */
 466:     public void actionPerformed(ActionEvent e)
 467:     {
 468:       filechooser.setCurrentDirectory(filechooser.getFileSystemView()
 469:                                                  .getHomeDirectory());
 470:       filechooser.revalidate();
 471:       filechooser.repaint();
 472:     }
 473:   }
 474: 
 475:   /**
 476:    * An action that handles the creation of a new folder/directory.
 477:    * 
 478:    * @see BasicFileChooserUI#getNewFolderAction()
 479:    */
 480:   protected class NewFolderAction extends AbstractAction
 481:   {
 482:     /**
 483:      * Creates a new <code>NewFolderAction</code> object.
 484:      */
 485:     protected NewFolderAction()
 486:     {
 487:       // Nothing to do here.
 488:     }
 489: 
 490:     /**
 491:      * Handles the event by creating a new folder.
 492:      *
 493:      * @param e  the action event (ignored).
 494:      */
 495:     public void actionPerformed(ActionEvent e)
 496:     {
 497:       try
 498:         {
 499:       filechooser.getFileSystemView().createNewFolder(filechooser
 500:                                                       .getCurrentDirectory());
 501:         }
 502:       catch (IOException ioe)
 503:         {
 504:       return;
 505:         }
 506:       filechooser.rescanCurrentDirectory();
 507:       filechooser.repaint();
 508:     }
 509:   }
 510: 
 511:   /**
 512:    * A listener for selection events in the file list.
 513:    * 
 514:    * @see BasicFileChooserUI#createListSelectionListener(JFileChooser)
 515:    */
 516:   protected class SelectionListener implements ListSelectionListener
 517:   {
 518:     /**
 519:      * Creates a new <code>SelectionListener</code> object.
 520:      */
 521:     protected SelectionListener()
 522:     {
 523:       // Nothing to do here.
 524:     }
 525: 
 526:     /**
 527:      * DOCUMENT ME!
 528:      *
 529:      * @param e DOCUMENT ME!
 530:      */
 531:     public void valueChanged(ListSelectionEvent e)
 532:     {
 533:       Object f = filelist.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:       // Nothing to do here.
 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 = new Icon()
 581:     {
 582:       public int getIconHeight()
 583:       {
 584:     return ICON_SIZE;
 585:       }
 586: 
 587:       public int getIconWidth()
 588:       {
 589:     return ICON_SIZE;
 590:       }
 591: 
 592:       public void paintIcon(Component c, Graphics g, int x, int y)
 593:       {
 594:         // FIXME: is this not implemented, or is the icon intentionally blank?
 595:       }
 596:     };
 597: 
 598:   /** An icon for the "details view" button. */
 599:   protected Icon detailsViewIcon = new Icon()
 600:     {
 601:       public int getIconHeight()
 602:       {
 603:     return ICON_SIZE;
 604:       }
 605: 
 606:       public int getIconWidth()
 607:       {
 608:     return ICON_SIZE;
 609:       }
 610: 
 611:       public void paintIcon(Component c, Graphics g, int x, int y)
 612:       {
 613:     Color saved = g.getColor();
 614:     g.translate(x, y);
 615: 
 616:     g.setColor(Color.GRAY);
 617:     g.drawRect(1, 1, 15, 20);
 618:     g.drawLine(17, 6, 23, 6);
 619:     g.drawLine(17, 12, 23, 12);
 620:     g.drawLine(17, 18, 23, 18);
 621: 
 622:     g.setColor(saved);
 623:     g.translate(-x, -y);
 624:       }
 625:     };
 626: 
 627:   /** An icon representing a directory. */
 628:   protected Icon directoryIcon = new Icon()
 629:     {
 630:       public int getIconHeight()
 631:       {
 632:     return ICON_SIZE;
 633:       }
 634: 
 635:       public int getIconWidth()
 636:       {
 637:     return ICON_SIZE;
 638:       }
 639: 
 640:       public void paintIcon(Component c, Graphics g, int x, int y)
 641:       {
 642:     Color saved = g.getColor();
 643:     g.translate(x, y);
 644: 
 645:     Point ap = new Point(3, 7);
 646:     Point bp = new Point(3, 21);
 647:     Point cp = new Point(21, 21);
 648:     Point dp = new Point(21, 12);
 649:     Point ep = new Point(16, 12);
 650:     Point fp = new Point(13, 7);
 651: 
 652:     Polygon dir = new Polygon(new int[] { ap.x, bp.x, cp.x, dp.x, ep.x, fp.x },
 653:                               new int[] { ap.y, bp.y, cp.y, dp.y, ep.y, fp.y },
 654:                               6);
 655: 
 656:     g.setColor(new Color(153, 204, 255));
 657:     g.fillPolygon(dir);
 658:     g.setColor(Color.BLACK);
 659:     g.drawPolygon(dir);
 660: 
 661:     g.translate(-x, -y);
 662:     g.setColor(saved);
 663:       }
 664:     };
 665: 
 666:   /** The localised Mnemonic for the open button. */
 667:   protected int directoryOpenButtonMnemonic;
 668: 
 669:   /** The localised text for the open button. */
 670:   protected String directoryOpenButtonText;
 671: 
 672:   /** The localised tool tip text for the open button. */
 673:   protected String directoryOpenButtonToolTipText;
 674: 
 675:   /** An icon representing a file. */
 676:   protected Icon fileIcon = new Icon()
 677:     {
 678:       public int getIconHeight()
 679:       {
 680:     return ICON_SIZE;
 681:       }
 682: 
 683:       public int getIconWidth()
 684:       {
 685:     return ICON_SIZE;
 686:       }
 687: 
 688:       public void paintIcon(Component c, Graphics g, int x, int y)
 689:       {
 690:     Color saved = g.getColor();
 691:     g.translate(x, y);
 692: 
 693:     Point a = new Point(5, 4);
 694:     Point b = new Point(5, 20);
 695:     Point d = new Point(19, 20);
 696:     Point e = new Point(19, 7);
 697:     Point f = new Point(16, 4);
 698: 
 699:     Polygon p = new Polygon(new int[] { a.x, b.x, d.x, e.x, f.x, },
 700:                             new int[] { a.y, b.y, d.y, e.y, f.y }, 5);
 701: 
 702:     g.setColor(Color.WHITE);
 703:     g.fillPolygon(p);
 704:     g.setColor(Color.BLACK);
 705:     g.drawPolygon(p);
 706: 
 707:     g.drawLine(16, 4, 14, 6);
 708:     g.drawLine(14, 6, 19, 7);
 709: 
 710:     g.setColor(saved);
 711:     g.translate(-x, -y);
 712:       }
 713:     };
 714: 
 715:   /** An icon representing a floppy drive. */
 716:   protected Icon floppyDriveIcon = new Icon()
 717:     {
 718:       public int getIconHeight()
 719:       {
 720:     return ICON_SIZE;
 721:       }
 722: 
 723:       public int getIconWidth()
 724:       {
 725:     return ICON_SIZE;
 726:       }
 727: 
 728:       public void paintIcon(Component c, Graphics g, int x, int y)
 729:       {
 730:         // FIXME: is this not implemented, or is the icon intentionally blank?
 731:       }
 732:     };
 733: 
 734:   /** An icon representing a hard drive. */
 735:   protected Icon hardDriveIcon = new Icon()
 736:     {
 737:       public int getIconHeight()
 738:       {
 739:     return ICON_SIZE;
 740:       }
 741: 
 742:       public int getIconWidth()
 743:       {
 744:     return ICON_SIZE;
 745:       }
 746: 
 747:       public void paintIcon(Component c, Graphics g, int x, int y)
 748:       {
 749:         // FIXME: is this not implemented, or is the icon intentionally blank?
 750:       }
 751:     };
 752: 
 753:   /** The localised mnemonic for the "help" button. */
 754:   protected int helpButtonMnemonic;
 755: 
 756:   /** The localised text for the "help" button. */
 757:   protected String helpButtonText;
 758: 
 759:   /** The localised tool tip text for the help button. */
 760:   protected String helpButtonToolTipText;
 761: 
 762:   /** An icon representing the user's home folder. */
 763:   protected Icon homeFolderIcon = new Icon()
 764:     {
 765:       public int getIconHeight()
 766:       {
 767:     return ICON_SIZE;
 768:       }
 769: 
 770:       public int getIconWidth()
 771:       {
 772:     return ICON_SIZE;
 773:       }
 774: 
 775:       public void paintIcon(Component c, Graphics g, int x, int y)
 776:       {
 777:     Color saved = g.getColor();
 778:     g.translate(x, y);
 779: 
 780:     Point a = new Point(12, 3);
 781:     Point b = new Point(4, 10);
 782:     Point d = new Point(20, 10);
 783: 
 784:     Polygon p = new Polygon(new int[] { a.x, b.x, d.x },
 785:                             new int[] { a.y, b.y, d.y }, 3);
 786: 
 787:     g.setColor(new Color(104, 51, 0));
 788:     g.fillPolygon(p);
 789:     g.setColor(Color.BLACK);
 790:     g.drawPolygon(p);
 791: 
 792:     g.setColor(Color.WHITE);
 793:     g.fillRect(8, 10, 8, 10);
 794:     g.setColor(Color.BLACK);
 795:     g.drawRect(8, 10, 8, 10);
 796: 
 797:     g.setColor(saved);
 798:     g.translate(-x, -y);
 799:       }
 800:     };
 801: 
 802:   /** An icon for the "list view" button. */
 803:   protected Icon listViewIcon = new Icon()
 804:     {
 805:       public int getIconHeight()
 806:       {
 807:     return ICON_SIZE;
 808:       }
 809: 
 810:       public int getIconWidth()
 811:       {
 812:     return ICON_SIZE;
 813:       }
 814: 
 815:       // Not needed. Only simplifies things until we get real icons.
 816:       private void paintPartial(Graphics g, int x, int y)
 817:       {
 818:     Color saved = g.getColor();
 819:     g.translate(x, y);
 820: 
 821:     g.setColor(Color.GRAY);
 822:     g.drawRect(1, 1, 7, 10);
 823:     g.drawLine(8, 6, 11, 6);
 824: 
 825:     g.setColor(saved);
 826:     g.translate(-x, -y);
 827:       }
 828: 
 829:       public void paintIcon(Component c, Graphics g, int x, int y)
 830:       {
 831:     Color saved = g.getColor();
 832:     g.translate(x, y);
 833: 
 834:     paintPartial(g, 0, 0);
 835:     paintPartial(g, 12, 0);
 836:     paintPartial(g, 0, 12);
 837:     paintPartial(g, 12, 12);
 838: 
 839:     g.setColor(saved);
 840:     g.translate(-x, -y);
 841:       }
 842:     };
 843: 
 844:   /** An icon for the "new folder" button. */
 845:   protected Icon newFolderIcon = directoryIcon;
 846: 
 847:   /** The localised mnemonic for the "open" button. */
 848:   protected int openButtonMnemonic;
 849: 
 850:   /** The localised text for the "open" button. */
 851:   protected String openButtonText;
 852: 
 853:   /** The localised tool tip text for the "open" button. */
 854:   protected String openButtonToolTipText;
 855: 
 856:   /** The localised mnemonic for the "save" button. */
 857:   protected int saveButtonMnemonic;
 858: 
 859:   /** The localised text for the "save" button. */
 860:   protected String saveButtonText;
 861: 
 862:   /** The localised tool tip text for the save button. */
 863:   protected String saveButtonToolTipText;
 864: 
 865:   /** The localised mnemonic for the "update" button. */
 866:   protected int updateButtonMnemonic;
 867: 
 868:   /** The localised text for the "update" button. */
 869:   protected String updateButtonText;
 870: 
 871:   /** The localised tool tip text for the "update" button. */
 872:   protected String updateButtonToolTipText;
 873: 
 874:   /** An icon for the "up folder" button. */
 875:   protected Icon upFolderIcon = new Icon()
 876:     {
 877:       public int getIconHeight()
 878:       {
 879:     return ICON_SIZE;
 880:       }
 881: 
 882:       public int getIconWidth()
 883:       {
 884:     return ICON_SIZE;
 885:       }
 886: 
 887:       public void paintIcon(Component comp, Graphics g, int x, int y)
 888:       {
 889:     Color saved = g.getColor();
 890:     g.translate(x, y);
 891: 
 892:     Point a = new Point(3, 7);
 893:     Point b = new Point(3, 21);
 894:     Point c = new Point(21, 21);
 895:     Point d = new Point(21, 12);
 896:     Point e = new Point(16, 12);
 897:     Point f = new Point(13, 7);
 898: 
 899:     Polygon dir = new Polygon(new int[] { a.x, b.x, c.x, d.x, e.x, f.x },
 900:                               new int[] { a.y, b.y, c.y, d.y, e.y, f.y }, 6);
 901: 
 902:     g.setColor(new Color(153, 204, 255));
 903:     g.fillPolygon(dir);
 904:     g.setColor(Color.BLACK);
 905:     g.drawPolygon(dir);
 906: 
 907:     a = new Point(12, 15);
 908:     b = new Point(9, 18);
 909:     c = new Point(15, 18);
 910: 
 911:     Polygon arrow = new Polygon(new int[] { a.x, b.x, c.x },
 912:                                 new int[] { a.y, b.y, c.y }, 3);
 913: 
 914:     g.fillPolygon(arrow);
 915: 
 916:     g.drawLine(12, 15, 12, 22);
 917: 
 918:     g.translate(-x, -y);
 919:     g.setColor(saved);
 920:       }
 921:     };
 922: 
 923:   // -- begin private, but package local since used in inner classes --
 924: 
 925:   /** The file chooser component represented by this UI delegate. */
 926:   JFileChooser filechooser;
 927: 
 928:   /** The file list. */
 929:   JList filelist;
 930: 
 931:   /** The combo box used to display/select file filters. */
 932:   JComboBox filters;
 933: 
 934:   /** The model for the directory list. */
 935:   BasicDirectoryModel model;
 936: 
 937:   /** The file filter for all files. */
 938:   FileFilter acceptAll = new AcceptAllFileFilter();
 939: 
 940:   /** The default file view. */
 941:   FileView fv = new BasicFileView();
 942: 
 943:   /** The icon size. */
 944:   static final int ICON_SIZE = 24;
 945: 
 946:   /** A combo box for display/selection of parent directories. */
 947:   JComboBox parents;
 948: 
 949:   /** The current file name. */
 950:   String filename;
 951: 
 952:   /** The accept (open/save) button. */
 953:   JButton accept;
 954: 
 955:   /** The cancel button. */
 956:   JButton cancel;
 957: 
 958:   /** The button to move up to the parent directory. */
 959:   JButton upFolderButton;
 960: 
 961:   /** The button to create a new directory. */
 962:   JButton newFolderButton;
 963: 
 964:   /** The button to move to the user's home directory. */
 965:   JButton homeFolderButton;
 966: 
 967:   /** An optional accessory panel. */
 968:   JPanel accessoryPanel;
 969: 
 970:   /** A property change listener. */
 971:   PropertyChangeListener propertyChangeListener;
 972: 
 973:   /** The text describing the filter for "all files". */
 974:   String acceptAllFileFilterText;
 975: 
 976:   /** The text describing a directory type. */
 977:   String dirDescText;
 978: 
 979:   /** The text describing a file type. */
 980:   String fileDescText;
 981: 
 982:   /** Is a directory selected? */
 983:   boolean dirSelected = false;
 984: 
 985:   /** The current directory. */
 986:   File currDir = null;
 987: 
 988:   // FIXME: describe what is contained in the bottom panel
 989:   /** The bottom panel. */
 990:   JPanel bottomPanel;
 991:   
 992:   /** The close panel. */
 993:   JPanel closePanel;
 994: 
 995:   /** Text box that displays file name */
 996:   JTextField entry;
 997:     
 998:   /** Current parent path */
 999:   String parentPath;
1000:   
1001:   // -- end private --
1002:   private class ListLabelRenderer extends JLabel implements ListCellRenderer
1003:   {
1004:     /** DOCUMENT ME! */
1005:     final Color selected = new Color(153, 204, 255);
1006: 
1007:     /**
1008:      * Creates a new ListLabelRenderer object.
1009:      */
1010:     public ListLabelRenderer()
1011:     {
1012:       super();
1013:       setOpaque(true);
1014:     }
1015: 
1016:     /**
1017:      * DOCUMENT ME!
1018:      *
1019:      * @param list DOCUMENT ME!
1020:      * @param value DOCUMENT ME!
1021:      * @param index DOCUMENT ME!
1022:      * @param isSelected DOCUMENT ME!
1023:      * @param cellHasFocus DOCUMENT ME!
1024:      *
1025:      * @return DOCUMENT ME!
1026:      */
1027:     public Component getListCellRendererComponent(JList list, Object value,
1028:                                                   int index,
1029:                                                   boolean isSelected,
1030:                                                   boolean cellHasFocus)
1031:     {
1032:       setHorizontalAlignment(SwingConstants.LEFT);
1033:       File file = (File) value;
1034:       setText(filechooser.getName(file));
1035:       setIcon(filechooser.getIcon(file));
1036:       setBackground(isSelected ? selected : Color.WHITE);
1037:       setForeground(Color.BLACK);
1038: 
1039:       return this;
1040:     }
1041:   }
1042: 
1043:   /**
1044:    * Closes the dialog.
1045:    */
1046:   void closeDialog()
1047:   {
1048:     Window owner = SwingUtilities.windowForComponent(filechooser);
1049:     if (owner instanceof JDialog)
1050:       ((JDialog) owner).dispose();
1051:   }
1052: 
1053:   /**
1054:    * Creates a new <code>BasicFileChooserUI</code> object.
1055:    *
1056:    * @param b  the file chooser component.
1057:    */
1058:   public BasicFileChooserUI(JFileChooser b)
1059:   {
1060:     this.filechooser = b;
1061:   }
1062: 
1063:   /**
1064:    * Returns a UI delegate for the given component.
1065:    *
1066:    * @param c  the component (should be a {@link JFileChooser}).
1067:    *
1068:    * @return A new UI delegate.
1069:    */
1070:   public static ComponentUI createUI(JComponent c)
1071:   {
1072:     return new BasicFileChooserUI((JFileChooser) c);
1073:   }
1074: 
1075:   /**
1076:    * Installs the UI for the specified component.
1077:    * 
1078:    * @param c  the component (should be a {@link JFileChooser}).
1079:    */
1080:   public void installUI(JComponent c)
1081:   {
1082:     if (c instanceof JFileChooser)
1083:       {
1084:         JFileChooser fc = (JFileChooser) c;
1085:         fc.resetChoosableFileFilters();
1086:         createModel();
1087:         clearIconCache();
1088:         installDefaults(fc);
1089:         installComponents(fc);
1090:         installListeners(fc);
1091:         
1092:         Object path = filechooser.getCurrentDirectory();
1093:         if (path != null)
1094:           parentPath = path.toString().substring(path.toString().lastIndexOf("/"));
1095:       }
1096:   }
1097: 
1098:   /**
1099:    * Uninstalls this UI from the given component.
1100:    * 
1101:    * @param c  the component (should be a {@link JFileChooser}).
1102:    */
1103:   public void uninstallUI(JComponent c)
1104:   {
1105:     model = null;
1106:     uninstallListeners(filechooser);
1107:     uninstallComponents(filechooser);
1108:     uninstallDefaults(filechooser);
1109:     filechooser = null;
1110:   }
1111: 
1112:   // FIXME: Indent the entries in the combobox
1113:   // Made this method package private to access it from within inner classes
1114:   // with better performance
1115:   void boxEntries()
1116:   {
1117:     ArrayList parentFiles = new ArrayList();
1118:     File parent = filechooser.getCurrentDirectory();
1119:     if (parent == null)
1120:       parent = filechooser.getFileSystemView().getDefaultDirectory();
1121:     while (parent != null)
1122:       {
1123:         String name = parent.getName();
1124:         if (name.equals(""))
1125:           name = parent.getAbsolutePath();
1126: 
1127:         parentFiles.add(parentFiles.size(), name);
1128:         parent = parent.getParentFile();
1129:       }
1130: 
1131:     if (parentFiles.size() == 0)
1132:       return;
1133: 
1134:     if (parents.getItemCount() > 0)
1135:       parents.removeAllItems();
1136:     for (int i = parentFiles.size() - 1; i >= 0; i--)
1137:       parents.addItem(parentFiles.get(i));
1138:     parents.setSelectedIndex(parentFiles.size() - 1);
1139:     parents.revalidate();
1140:     parents.repaint();
1141:   }
1142: 
1143:   /**
1144:    * DOCUMENT ME!
1145:    *
1146:    * @return DOCUMENT ME!
1147:    */
1148:   private ItemListener createBoxListener()
1149:   {
1150:     return new ItemListener()
1151:       {
1152:     public void itemStateChanged(ItemEvent e)
1153:     {
1154:       if (parents.getItemCount() - 1 == parents.getSelectedIndex())
1155:         return;
1156:       StringBuffer dir = new StringBuffer();
1157:       for (int i = 0; i <= parents.getSelectedIndex(); i++)
1158:         {
1159:           dir.append(parents.getItemAt(i));
1160:           dir.append(File.separatorChar);
1161:         }
1162:       filechooser.setCurrentDirectory(filechooser.getFileSystemView()
1163:                                                  .createFileObject(dir
1164:                                                                    .toString()));
1165:     }
1166:       };
1167:   }
1168: 
1169:   /**
1170:    * DOCUMENT ME!
1171:    *
1172:    * @return DOCUMENT ME!
1173:    */
1174:   private ItemListener createFilterListener()
1175:   {
1176:     return new ItemListener()
1177:       {
1178:     public void itemStateChanged(ItemEvent e)
1179:     {
1180:       int index = filters.getSelectedIndex();
1181:       if (index == -1)
1182:         return;
1183:       filechooser.setFileFilter(filechooser.getChoosableFileFilters()[index]);
1184:     }
1185:       };
1186:   }
1187: 
1188:   void filterEntries()
1189:   {
1190:     FileFilter[] list = filechooser.getChoosableFileFilters();
1191:     if (filters.getItemCount() > 0)
1192:       filters.removeAllItems();
1193: 
1194:     int index = -1;
1195:     String selected = filechooser.getFileFilter().getDescription();
1196:     for (int i = 0; i < list.length; i++)
1197:       {
1198:     if (selected.equals(list[i].getDescription()))
1199:       index = i;
1200:     filters.addItem(list[i].getDescription());
1201:       }
1202:     filters.setSelectedIndex(index);
1203:     filters.revalidate();
1204:     filters.repaint();
1205:   }
1206: 
1207:   /**
1208:    * Creates and install the subcomponents for the file chooser.
1209:    *
1210:    * @param fc  the file chooser.
1211:    */
1212:   public void installComponents(JFileChooser fc)
1213:   {
1214:     JLabel look = new JLabel("Look In:");
1215: 
1216:     parents = new JComboBox();
1217:     parents.setRenderer(new BasicComboBoxRenderer());
1218:     boxEntries();
1219:     look.setLabelFor(parents);
1220:     JPanel parentsPanel = new JPanel();
1221:     parentsPanel.add(look);
1222:     parentsPanel.add(parents);
1223:     JPanel buttonPanel = new JPanel();
1224: 
1225:     upFolderButton = new JButton();
1226:     upFolderButton.setIcon(upFolderIcon);
1227:     buttonPanel.add(upFolderButton);
1228: 
1229:     homeFolderButton = new JButton();
1230:     homeFolderButton = new JButton(homeFolderIcon);
1231:     buttonPanel.add(homeFolderButton);
1232: 
1233:     newFolderButton = new JButton();
1234:     newFolderButton.setIcon(newFolderIcon);
1235:     buttonPanel.add(newFolderButton);
1236: 
1237:     ButtonGroup toggles = new ButtonGroup();
1238:     JToggleButton listViewButton = new JToggleButton();
1239:     listViewButton.setIcon(listViewIcon);
1240:     toggles.add(listViewButton);
1241:     buttonPanel.add(listViewButton);
1242: 
1243:     JToggleButton detailsViewButton = new JToggleButton();
1244:     detailsViewButton.setIcon(detailsViewIcon);
1245:     toggles.add(detailsViewButton);
1246:     buttonPanel.add(detailsViewButton);
1247: 
1248:     JPanel topPanel = new JPanel();
1249:     parentsPanel.add(buttonPanel);
1250:     topPanel.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT, 0, 0));
1251:     topPanel.add(parentsPanel);
1252: 
1253:     accessoryPanel = new JPanel();
1254:     if (filechooser.getAccessory() != null)
1255:       accessoryPanel.add(filechooser.getAccessory(), BorderLayout.CENTER);
1256: 
1257:     filelist = new JList(model);
1258:     filelist.setVisibleRowCount(6);
1259:     JScrollPane scrollp = new JScrollPane(filelist);
1260:     scrollp.setPreferredSize(new Dimension(400, 175));
1261:     filelist.setBackground(Color.WHITE);
1262: 
1263:     filelist.setLayoutOrientation(JList.VERTICAL_WRAP);
1264:     filelist.setCellRenderer(new ListLabelRenderer());
1265: 
1266:     GridBagConstraints c = new GridBagConstraints();
1267:     c.gridx = 0;
1268:     c.gridy = 0;
1269:     c.fill = GridBagConstraints.BOTH;
1270:     c.weightx = 1;
1271:     c.weighty = 1;
1272: 
1273:     JPanel centrePanel = new JPanel();
1274:     centrePanel.setLayout(new GridBagLayout());
1275:     centrePanel.add(scrollp, c);
1276: 
1277:     c.gridx = 1;
1278:     centrePanel.add(accessoryPanel, c);
1279: 
1280:     JLabel fileNameLabel = new JLabel("File Name:");
1281:     JLabel fileTypesLabel = new JLabel("Files of Type:");
1282: 
1283:     entry = new JTextField();
1284:     filters = new JComboBox();
1285:     filterEntries();
1286: 
1287:     fileNameLabel.setLabelFor(entry);
1288:     fileNameLabel.setHorizontalTextPosition(SwingConstants.LEFT);
1289:     fileTypesLabel.setLabelFor(filters);
1290:     fileTypesLabel.setHorizontalTextPosition(SwingConstants.LEFT);
1291: 
1292:     closePanel = new JPanel();
1293:     accept = getApproveButton(filechooser);
1294:     cancel = new JButton(cancelButtonText);
1295:     cancel.setMnemonic(cancelButtonMnemonic);
1296:     cancel.setToolTipText(cancelButtonToolTipText);
1297:     closePanel.add(accept);
1298:     closePanel.add(cancel);
1299: 
1300:     c.anchor = GridBagConstraints.WEST;
1301:     c.weighty = 0;
1302:     c.weightx = 0;
1303:     c.gridx = 0;
1304: 
1305:     bottomPanel = new JPanel();
1306:     bottomPanel.setLayout(new GridBagLayout());
1307:     bottomPanel.add(fileNameLabel, c);
1308: 
1309:     c.gridy = 1;
1310:     bottomPanel.add(fileTypesLabel, c);
1311:     c.gridx = 1;
1312:     c.gridy = 0;
1313:     c.weightx = 1;
1314:     c.weighty = 1;
1315:     bottomPanel.add(entry, c);
1316: 
1317:     c.gridy = 1;
1318:     bottomPanel.add(filters, c);
1319: 
1320:     c.fill = GridBagConstraints.NONE;
1321:     c.gridy = 2;
1322:     c.anchor = GridBagConstraints.EAST;
1323:     bottomPanel.add(closePanel, c);
1324: 
1325:     filechooser.setLayout(new BorderLayout());
1326:     filechooser.add(topPanel, BorderLayout.NORTH);
1327:     filechooser.add(centrePanel, BorderLayout.CENTER);
1328:     filechooser.add(bottomPanel, BorderLayout.SOUTH);
1329:   }
1330: 
1331:   /**
1332:    * Uninstalls the components from the file chooser.
1333:    *
1334:    * @param fc  the file chooser.
1335:    */
1336:   public void uninstallComponents(JFileChooser fc)
1337:   {
1338:     parents = null;
1339: 
1340:     accept = null;
1341:     cancel = null;
1342:     upFolderButton = null;
1343:     homeFolderButton = null;
1344:     newFolderButton = null;
1345: 
1346:     filelist = null;
1347:   }
1348: 
1349:   /**
1350:    * Installs the listeners required by this UI delegate.
1351:    *
1352:    * @param fc  the file chooser.
1353:    */
1354:   protected void installListeners(JFileChooser fc)
1355:   {
1356:     propertyChangeListener = createPropertyChangeListener(filechooser);
1357:     filechooser.addPropertyChangeListener(propertyChangeListener);
1358: 
1359:     //parents.addItemListener(createBoxListener());
1360:     accept.addActionListener(getApproveSelectionAction());
1361:     cancel.addActionListener(getCancelSelectionAction());
1362:     upFolderButton.addActionListener(getChangeToParentDirectoryAction());
1363:     homeFolderButton.addActionListener(getGoHomeAction());
1364:     newFolderButton.addActionListener(getNewFolderAction());
1365:     filters.addItemListener(createFilterListener());
1366: 
1367:     filelist.addMouseListener(createDoubleClickListener(filechooser, filelist));
1368:     filelist.addListSelectionListener(createListSelectionListener(filechooser));
1369:   }
1370: 
1371:   /**
1372:    * Uninstalls the listeners previously installed by this UI delegate.
1373:    *
1374:    * @param fc  the file chooser.
1375:    */
1376:   protected void uninstallListeners(JFileChooser fc)
1377:   {
1378:     filechooser.removePropertyChangeListener(propertyChangeListener);
1379:     propertyChangeListener = null;
1380:   }
1381: 
1382:   /**
1383:    * Installs the defaults for this UI delegate.
1384:    *
1385:    * @param fc  the file chooser.
1386:    */
1387:   protected void installDefaults(JFileChooser fc)
1388:   {
1389:     installIcons(fc);
1390:     installStrings(fc);
1391:   }
1392: 
1393:   /**
1394:    * Uninstalls the defaults previously added by this UI delegate.
1395:    *
1396:    * @param fc  the file chooser.
1397:    */
1398:   protected void uninstallDefaults(JFileChooser fc)
1399:   {
1400:     uninstallStrings(fc);
1401:     uninstallIcons(fc);
1402:   }
1403: 
1404:   /**
1405:    * Installs the icons for this UI delegate (NOT YET IMPLEMENTED).
1406:    *
1407:    * @param fc  the file chooser.
1408:    */
1409:   protected void installIcons(JFileChooser fc)
1410:   {
1411:     // FIXME: Implement.
1412:   }
1413: 
1414:   /**
1415:    * Uninstalls the icons previously added by this UI delegate (NOT YET
1416:    * IMPLEMENTED).
1417:    *
1418:    * @param fc  the file chooser.
1419:    */
1420:   protected void uninstallIcons(JFileChooser fc)
1421:   {
1422:     // FIXME: Implement.
1423:   }
1424: 
1425:   /**
1426:    * Installs the strings used by this UI delegate.
1427:    *
1428:    * @param fc  the file chooser.
1429:    */
1430:   protected void installStrings(JFileChooser fc)
1431:   {
1432:     UIDefaults defaults = UIManager.getLookAndFeelDefaults();
1433: 
1434:     acceptAllFileFilterText = defaults.getString("FileChooser.acceptAllFileFilterText");
1435:     cancelButtonMnemonic = defaults.getInt("FileChooser.cancelButtonMnemonic");
1436:     cancelButtonText = defaults.getString("FileChooser.cancelButtonText");
1437:     cancelButtonToolTipText = defaults.getString("FileChooser.cancelButtonToolTipText");
1438: 
1439:     dirDescText = defaults.getString("FileChooser.directoryDescriptionText");
1440:     fileDescText = defaults.getString("FileChooser.fileDescriptionText");
1441: 
1442:     helpButtonMnemonic = defaults.getInt("FileChooser.helpButtonMnemonic");
1443:     helpButtonText = defaults.getString("FileChooser.helpButtonText");
1444:     helpButtonToolTipText = defaults.getString("FileChooser.helpButtonToolTipText");
1445: 
1446:     openButtonMnemonic = defaults.getInt("FileChooser.openButtonMnemonic");
1447:     openButtonText = defaults.getString("FileChooser.openButtonText");
1448:     openButtonToolTipText = defaults.getString("FileChooser.openButtonToolTipText");
1449: 
1450:     saveButtonMnemonic = defaults.getInt("FileChooser.saveButtonMnemonic");
1451:     saveButtonText = defaults.getString("FileChooser.saveButtonText");
1452:     saveButtonToolTipText = defaults.getString("FileChooser.saveButtonToolTipText");
1453:   }
1454: 
1455:   /**
1456:    * Uninstalls the strings previously added by this UI delegate.
1457:    *
1458:    * @param fc  the file chooser.
1459:    */
1460:   protected void uninstallStrings(JFileChooser fc)
1461:   {
1462:     acceptAllFileFilterText = null;
1463:     cancelButtonMnemonic = 0;
1464:     cancelButtonText = null;
1465:     cancelButtonToolTipText = null;
1466: 
1467:     dirDescText = null;
1468:     fileDescText = null;
1469: 
1470:     helpButtonMnemonic = 0;
1471:     helpButtonText = null;
1472:     helpButtonToolTipText = null;
1473: 
1474:     openButtonMnemonic = 0;
1475:     openButtonText = null;
1476:     openButtonToolTipText = null;
1477: 
1478:     saveButtonMnemonic = 0;
1479:     saveButtonText = null;
1480:     saveButtonToolTipText = null;
1481:   }
1482: 
1483:   /**
1484:    * Creates a new directory model.
1485:    */
1486:   protected void createModel()
1487:   {
1488:     model = new BasicDirectoryModel(filechooser);
1489:   }
1490: 
1491:   /**
1492:    * Returns the directory model.
1493:    *
1494:    * @return The directory model.
1495:    */
1496:   public BasicDirectoryModel getModel()
1497:   {
1498:     return model;
1499:   }
1500: 
1501:   /**
1502:    * Creates a listener to handle changes to the properties of the given
1503:    * file chooser component.
1504:    * 
1505:    * @param fc  the file chooser component.
1506:    * 
1507:    * @return A new listener.
1508:    */
1509:   public PropertyChangeListener createPropertyChangeListener(JFileChooser fc)
1510:   {
1511:     return new PropertyChangeListener()
1512:     {
1513:       public void propertyChange(PropertyChangeEvent e)
1514:       {
1515:         // FIXME: Multiple file selection waiting on JList multiple selection
1516:         // bug.
1517:         if (e.getPropertyName().equals(
1518:                                        JFileChooser.SELECTED_FILE_CHANGED_PROPERTY))
1519:           {
1520:             if (filechooser.getSelectedFile() == null)
1521:               setFileName(null);
1522:             else
1523:               setFileName(filechooser.getSelectedFile().toString());
1524:             int index = -1;
1525:             File file = filechooser.getSelectedFile();
1526:             for (index = 0; index < model.getSize(); index++)
1527:               if (((File) model.getElementAt(index)).equals(file))
1528:                 break;
1529:             if (index == -1)
1530:               return;
1531:             filelist.setSelectedIndex(index);
1532:             filelist.ensureIndexIsVisible(index);
1533:             filelist.revalidate();
1534:             filelist.repaint();
1535:           }
1536:         else if (e.getPropertyName().equals(
1537:                                             JFileChooser.DIRECTORY_CHANGED_PROPERTY))
1538:           {
1539:             filelist.clearSelection();
1540:             filelist.revalidate();
1541:             filelist.repaint();
1542:             setDirectorySelected(false);
1543:             setDirectory(filechooser.getCurrentDirectory());
1544:             boxEntries();
1545:           }
1546:         else if (e.getPropertyName().equals(
1547:                                             JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY)
1548:                  || e.getPropertyName().equals(
1549:                                                JFileChooser.FILE_FILTER_CHANGED_PROPERTY))
1550:           filterEntries();
1551:         else if (e.getPropertyName().equals(
1552:                                             JFileChooser.DIALOG_TYPE_CHANGED_PROPERTY)
1553:                  || e.getPropertyName().equals(
1554:                                                JFileChooser.DIALOG_TITLE_CHANGED_PROPERTY))
1555:           {
1556:             Window owner = SwingUtilities.windowForComponent(filechooser);
1557:             if (owner instanceof JDialog)
1558:               ((JDialog) owner).setTitle(getDialogTitle(filechooser));
1559:             accept.setText(getApproveButtonText(filechooser));
1560:             accept.setToolTipText(getApproveButtonToolTipText(filechooser));
1561:             accept.setMnemonic(getApproveButtonMnemonic(filechooser));
1562:           }
1563:         else if (e.getPropertyName().equals(
1564:                                             JFileChooser.APPROVE_BUTTON_TEXT_CHANGED_PROPERTY))
1565:           accept.setText(getApproveButtonText(filechooser));
1566:         else if (e.getPropertyName().equals(
1567:                                             JFileChooser.APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY))
1568:           accept.setToolTipText(getApproveButtonToolTipText(filechooser));
1569:         else if (e.getPropertyName().equals(
1570:                                             JFileChooser.APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY))
1571:           accept.setMnemonic(getApproveButtonMnemonic(filechooser));
1572:         else if (e.getPropertyName().equals(
1573:                                             JFileChooser.CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY))
1574:           {
1575:             if (filechooser.getControlButtonsAreShown())
1576:               {
1577:                 GridBagConstraints c = new GridBagConstraints();
1578:                 c.gridy = 1;
1579:                 bottomPanel.add(filters, c);
1580: 
1581:                 c.fill = GridBagConstraints.BOTH;
1582:                 c.gridy = 2;
1583:                 c.anchor = GridBagConstraints.EAST;
1584:                 bottomPanel.add(closePanel, c);
1585:                 bottomPanel.revalidate();
1586:                 bottomPanel.repaint();
1587:                 bottomPanel.doLayout();
1588:               }
1589:             else
1590:               bottomPanel.remove(closePanel);
1591:           }
1592:         else if (e.getPropertyName().equals(
1593:                                             JFileChooser.ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY))
1594:           {
1595:             if (filechooser.isAcceptAllFileFilterUsed())
1596:               filechooser.addChoosableFileFilter(getAcceptAllFileFilter(filechooser));
1597:             else
1598:               filechooser.removeChoosableFileFilter(getAcceptAllFileFilter(filechooser));
1599:           }
1600:         else if (e.getPropertyName().equals(
1601:                                             JFileChooser.ACCESSORY_CHANGED_PROPERTY))
1602:           {
1603:             JComponent old = (JComponent) e.getOldValue();
1604:             if (old != null)
1605:               getAccessoryPanel().remove(old);
1606:             JComponent newval = (JComponent) e.getNewValue();
1607:             if (newval != null)
1608:               getAccessoryPanel().add(newval);
1609:           }
1610:         if (e.getPropertyName().equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)
1611:             || e.getPropertyName().equals(
1612:                                           JFileChooser.FILE_FILTER_CHANGED_PROPERTY)
1613:             || e.getPropertyName().equals(
1614:                                           JFileChooser.FILE_HIDING_CHANGED_PROPERTY))
1615:           rescanCurrentDirectory(filechooser);
1616: 
1617:         filechooser.revalidate();
1618:         filechooser.repaint();
1619:       }
1620:     };
1621:   }
1622: 
1623:   /**
1624:    * Returns the current file name.
1625:    * 
1626:    * @return The current file name.
1627:    */
1628:   public String getFileName()
1629:   {
1630:     return filename;
1631:   }
1632: 
1633:   /**
1634:    * Returns the current directory name.
1635:    *
1636:    * @return The directory name.
1637:    * 
1638:    * @see #setDirectoryName(String)
1639:    */
1640:   public String getDirectoryName()
1641:   {
1642:     // XXX: I don't see a case where the thing returns something non-null..
1643:     return null;
1644:   }
1645: 
1646:   /**
1647:    * Sets the file name.
1648:    *
1649:    * @param filename  the file name.
1650:    * 
1651:    * @see #getFileName()
1652:    */
1653:   public void setFileName(String filename)
1654:   {
1655:     this.filename = filename;
1656:   }
1657: 
1658:   /**
1659:    * Sets the directory name (NOT IMPLEMENTED).
1660:    *
1661:    * @param dirname  the directory name.
1662:    * 
1663:    * @see #getDirectoryName()
1664:    */
1665:   public void setDirectoryName(String dirname)
1666:   {
1667:     // FIXME: Implement
1668:   }
1669: 
1670:   /**
1671:    * Rescans the current directory.
1672:    *
1673:    * @param fc  the file chooser.
1674:    */
1675:   public void rescanCurrentDirectory(JFileChooser fc)
1676:   {
1677:     getModel().validateFileCache();
1678:     filelist.revalidate();
1679:   }
1680: 
1681:   /**
1682:    * NOT YET IMPLEMENTED.
1683:    *
1684:    * @param fc  the file chooser.
1685:    * @param f  the file.
1686:    */
1687:   public void ensureFileIsVisible(JFileChooser fc, File f)
1688:   {
1689:     // XXX: Not sure what this does.
1690:   }
1691: 
1692:   /**
1693:    * Returns the {@link JFileChooser} component that this UI delegate 
1694:    * represents.
1695:    *
1696:    * @return The component represented by this UI delegate.
1697:    */
1698:   public JFileChooser getFileChooser()
1699:   {
1700:     return filechooser;
1701:   }
1702: 
1703:   /**
1704:    * Returns the optional accessory panel.
1705:    *
1706:    * @return The optional accessory panel.
1707:    */
1708:   public JPanel getAccessoryPanel()
1709:   {
1710:     return accessoryPanel;
1711:   }
1712: 
1713:   /**
1714:    * Creates and returns an approve (open or save) button for the dialog.
1715:    *
1716:    * @param fc  the file chooser.
1717:    *
1718:    * @return The button.
1719:    */
1720:   public JButton getApproveButton(JFileChooser fc)
1721:   {
1722:     accept = new JButton(getApproveButtonText(fc));
1723:     accept.setMnemonic(getApproveButtonMnemonic(fc));
1724:     accept.setToolTipText(getApproveButtonToolTipText(fc));
1725:     return accept;
1726:   }
1727: 
1728:   /**
1729:    * Returns the tool tip text for the approve (open/save) button.  This first
1730:    * checks the file chooser to see if a value has been explicitly set - if
1731:    * not, a default value appropriate for the type of file chooser is 
1732:    * returned.
1733:    *
1734:    * @param fc  the file chooser.
1735:    *
1736:    * @return The tool tip text.
1737:    */
1738:   public String getApproveButtonToolTipText(JFileChooser fc)
1739:   {
1740:     if (fc.getApproveButtonToolTipText() != null)
1741:       return fc.getApproveButtonToolTipText();
1742:     else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG)
1743:       return saveButtonToolTipText;
1744:     else
1745:       return openButtonToolTipText;
1746:   }
1747: 
1748:   /**
1749:    * Clears the icon cache.
1750:    */
1751:   public void clearIconCache()
1752:   {
1753:     if (fv instanceof BasicFileView)
1754:       ((BasicFileView) fv).clearIconCache();
1755:   }
1756: 
1757:   /**
1758:    * Creates a new listener to handle selections in the file list.
1759:    *
1760:    * @param fc  the file chooser component.
1761:    *
1762:    * @return A new instance of {@link SelectionListener}.
1763:    */
1764:   public ListSelectionListener createListSelectionListener(JFileChooser fc)
1765:   {
1766:     return new SelectionListener();
1767:   }
1768: 
1769:   /**
1770:    * Creates a new listener to handle double-click events.
1771:    *
1772:    * @param fc  the file chooser component.
1773:    * @param list  the list.
1774:    *
1775:    * @return A new instance of {@link DoubleClickListener}.
1776:    */
1777:   protected MouseListener createDoubleClickListener(JFileChooser fc, JList list)
1778:   {
1779:     return new DoubleClickListener(list);
1780:   }
1781: 
1782:   /**
1783:    * Returns <code>true</code> if a directory is selected, and 
1784:    * <code>false</code> otherwise.
1785:    *
1786:    * @return A boolean.
1787:    */
1788:   protected boolean isDirectorySelected()
1789:   {
1790:     return dirSelected;
1791:   }
1792: 
1793:   /**
1794:    * Sets the flag that indicates whether the current directory is selected.
1795:    *
1796:    * @param selected  the new flag value.
1797:    */
1798:   protected void setDirectorySelected(boolean selected)
1799:   {
1800:     dirSelected = selected;
1801:   }
1802: 
1803:   /**
1804:    * Returns the current directory.
1805:    *
1806:    * @return The current directory.
1807:    */
1808:   protected File getDirectory()
1809:   {
1810:     return currDir;
1811:   }
1812: 
1813:   /**
1814:    * Sets the current directory.
1815:    *
1816:    * @param f  the directory.
1817:    */
1818:   protected void setDirectory(File f)
1819:   {
1820:     currDir = f;
1821:   }
1822: 
1823:   /**
1824:    * Returns the "accept all" file filter.
1825:    *
1826:    * @param fc  the file chooser component.
1827:    *
1828:    * @return The "accept all" file filter.
1829:    */
1830:   public FileFilter getAcceptAllFileFilter(JFileChooser fc)
1831:   {
1832:     return acceptAll;
1833:   }
1834: 
1835:   /**
1836:    * Returns the file view for the file chooser.  This returns either the
1837:    * file view that has been explicitly set for the {@link JFileChooser}, or
1838:    * a default file view.
1839:    *
1840:    * @param fc  the file chooser component.
1841:    *
1842:    * @return The file view.
1843:    * 
1844:    * @see JFileChooser#getFileView()
1845:    */
1846:   public FileView getFileView(JFileChooser fc)
1847:   {
1848:     return fv;
1849:   }
1850: 
1851:   /**
1852:    * Returns the dialog title.
1853:    *
1854:    * @param fc  the file chooser (<code>null</code> not permitted).
1855:    *
1856:    * @return The dialog title.
1857:    * 
1858:    * @see JFileChooser#getDialogTitle()
1859:    */
1860:   public String getDialogTitle(JFileChooser fc)
1861:   {
1862:     String ret = fc.getDialogTitle();
1863:     if (ret != null)
1864:       return ret;
1865:     switch (fc.getDialogType())
1866:       {
1867:       case JFileChooser.OPEN_DIALOG:
1868:     ret = openButtonText;
1869:     break;
1870:       case JFileChooser.SAVE_DIALOG:
1871:     ret = saveButtonText;
1872:     break;
1873:       default:
1874:     ret = fc.getApproveButtonText();
1875:     break;
1876:       }
1877:     if (ret == null)
1878:       ret = openButtonText;
1879:     return ret;
1880:   }
1881: 
1882:   /**
1883:    * Returns the approve button mnemonic.
1884:    *
1885:    * @param fc  the file chooser (<code>null</code> not permitted).
1886:    *
1887:    * @return The approve button mnemonic.
1888:    * 
1889:    * @see JFileChooser#getApproveButtonMnemonic()
1890:    */
1891:   public int getApproveButtonMnemonic(JFileChooser fc)
1892:   {
1893:     if (fc.getApproveButtonMnemonic() != 0)
1894:       return fc.getApproveButtonMnemonic();
1895:     else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG)
1896:       return saveButtonMnemonic;
1897:     else
1898:       return openButtonMnemonic;
1899:   }
1900: 
1901:   /**
1902:    * Returns the approve button text.
1903:    *
1904:    * @param fc  the file chooser (<code>null</code> not permitted).
1905:    *
1906:    * @return The approve button text.
1907:    * 
1908:    * @see JFileChooser#getApproveButtonText()
1909:    */
1910:   public String getApproveButtonText(JFileChooser fc)
1911:   {
1912:     if (fc.getApproveButtonText() != null)
1913:       return fc.getApproveButtonText();
1914:     else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG)
1915:       return saveButtonText;
1916:     else
1917:       return openButtonText;
1918:   }
1919: 
1920:   /**
1921:    * Creates and returns a new action that will be used with the "new folder" 
1922:    * button.
1923:    *
1924:    * @return A new instance of {@link GoHomeAction}.
1925:    */
1926:   public Action getNewFolderAction()
1927:   {
1928:     return new NewFolderAction();
1929:   }
1930: 
1931:   /**
1932:    * Creates and returns a new action that will be used with the "home folder" 
1933:    * button.
1934:    *
1935:    * @return A new instance of {@link GoHomeAction}.
1936:    */
1937:   public Action getGoHomeAction()
1938:   {
1939:     return new GoHomeAction();
1940:   }
1941: 
1942:   /**
1943:    * Creates and returns a new action that will be used with the "up folder" 
1944:    * button.
1945:    *
1946:    * @return A new instance of {@link ChangeToParentDirectoryAction}.
1947:    */
1948:   public Action getChangeToParentDirectoryAction()
1949:   {
1950:     return new ChangeToParentDirectoryAction();
1951:   }
1952: 
1953:   /**
1954:    * Creates and returns a new action that will be used with the "approve" 
1955:    * button.
1956:    *
1957:    * @return A new instance of {@link ApproveSelectionAction}.
1958:    */
1959:   public Action getApproveSelectionAction()
1960:   {
1961:     return new ApproveSelectionAction();
1962:   }
1963: 
1964:   /**
1965:    * Creates and returns a new action that will be used with the "cancel" 
1966:    * button.
1967:    *
1968:    * @return A new instance of {@link CancelSelectionAction}.
1969:    */
1970:   public Action getCancelSelectionAction()
1971:   {
1972:     return new CancelSelectionAction();
1973:   }
1974: 
1975:   /**
1976:    * Creates and returns a new instance of {@link UpdateAction}.
1977:    *
1978:    * @return An action. 
1979:    */
1980:   public Action getUpdateAction()
1981:   {
1982:     return new UpdateAction();
1983:   }
1984: }