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