BasicFileChooserUI.java 35.7 KB
Newer Older
Tom Tromey committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
/* BasicFileChooserUI.java --
   Copyright (C) 2005  Free Software Foundation, Inc.

This file is part of GNU Classpath.

GNU Classpath is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GNU Classpath is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING.  If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA.

Linking this library statically or dynamically with other modules is
making a combined work based on this library.  Thus, the terms and
conditions of the GNU General Public License cover the whole
combination.

As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent
modules, and to copy and distribute the resulting executable under
terms of your choice, provided that you also meet, for each linked
independent module, the terms and conditions of the license of that
module.  An independent module is a module which is not derived from
or based on this library.  If you modify this library, you may extend
this exception to your version of the library, but you are not
obligated to do so.  If you do not wish to do so, delete this
exception statement from your version. */

package javax.swing.plaf.basic;

import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
50

Tom Tromey committed
51 52 53 54 55 56 57 58 59 60 61
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
62
import javax.swing.UIDefaults;
Tom Tromey committed
63 64 65 66 67 68 69 70
import javax.swing.UIManager;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileSystemView;
import javax.swing.filechooser.FileView;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.FileChooserUI;
71
import javax.swing.plaf.metal.MetalIconFactory;
Tom Tromey committed
72 73 74


/**
75 76
 * A UI delegate for the {@link JFileChooser} component under the 
 * {@link BasicLookAndFeel}.
Tom Tromey committed
77 78 79 80
 */
public class BasicFileChooserUI extends FileChooserUI
{
  /**
81
   * A file filter that accepts all files.
Tom Tromey committed
82 83 84
   */
  protected class AcceptAllFileFilter extends FileFilter
  {
85 86 87
    /**
     * Creates a new instance.
     */
Tom Tromey committed
88 89
    public AcceptAllFileFilter()
    {
90
      // Nothing to do here.
Tom Tromey committed
91 92 93
    }
    
    /**
94 95
     * Returns <code>true</code> always, as all files are accepted by this
     * filter.
Tom Tromey committed
96
     *
97
     * @param f  the file.
Tom Tromey committed
98
     *
99
     * @return Always <code>true</code>.
Tom Tromey committed
100 101 102 103 104 105 106
     */
    public boolean accept(File f)
    {
      return true;
    }

    /**
107
     * Returns a description for this filter.
Tom Tromey committed
108
     *
109
     * @return A description for the file filter.
Tom Tromey committed
110 111 112 113 114 115 116 117
     */
    public String getDescription()
    {
      return acceptAllFileFilterText;
    }
  }

  /**
118 119 120
   * Handles a user action to approve the dialog selection.
   * 
   * @see BasicFileChooserUI#getApproveSelectionAction()
Tom Tromey committed
121 122 123 124 125 126 127 128
   */
  protected class ApproveSelectionAction extends AbstractAction
  {
    /**
     * Creates a new ApproveSelectionAction object.
     */
    protected ApproveSelectionAction()
    {
129
      super("approveSelection");
Tom Tromey committed
130 131 132
    }

    /**
133 134 135
     * Sets the current selection and closes the dialog.
     * 
     * @param e  the action event.
Tom Tromey committed
136 137 138
     */
    public void actionPerformed(ActionEvent e)
    {
139 140 141 142 143
      Object obj = null;
      if (parentPath != null)
        obj = new String(parentPath + getFileName());
      else
        obj = filechooser.getSelectedFile();
Tom Tromey committed
144 145
      if (obj != null)
        {
146 147 148 149 150 151 152
          File f = filechooser.getFileSystemView().createFileObject(obj.toString());
          File currSelected = filechooser.getSelectedFile();
          if (filechooser.isTraversable(f))
            {
              filechooser.setCurrentDirectory(currSelected);
              filechooser.rescanCurrentDirectory();
            }
153 154 155 156 157
          else
            {
              filechooser.approveSelection();
              closeDialog();
            }
Tom Tromey committed
158
        }
159 160 161
      else
        {
          File f = new File(filechooser.getCurrentDirectory(), getFileName());
162 163
	  if ( selectedDir != null )
	    f = selectedDir;
164 165 166 167 168 169 170 171 172 173 174 175
          if (filechooser.isTraversable(f))
            {
              filechooser.setCurrentDirectory(f);
              filechooser.rescanCurrentDirectory();
            }
          else
            {
              filechooser.setSelectedFile(f);
              filechooser.approveSelection();
              closeDialog();
            }
        }
Tom Tromey committed
176 177 178 179
    }
  }

  /**
180
   * Provides presentation information about files and directories.
Tom Tromey committed
181 182 183
   */
  protected class BasicFileView extends FileView
  {
184
    /** Storage for cached icons. */
185
    protected Hashtable<File, Icon> iconCache = new Hashtable<File, Icon>();
Tom Tromey committed
186

187 188 189
    /**
     * Creates a new instance.
     */
Tom Tromey committed
190 191
    public BasicFileView()
    {
192
      // Nothing to do here.
Tom Tromey committed
193 194 195
    }

    /**
196
     * Adds an icon to the cache, associating it with the given file/directory.
Tom Tromey committed
197
     *
198 199
     * @param f  the file/directory.
     * @param i  the icon.
Tom Tromey committed
200 201 202 203 204 205 206
     */
    public void cacheIcon(File f, Icon i)
    {
      iconCache.put(f, i);
    }

    /**
207
     * Clears the icon cache.
Tom Tromey committed
208 209 210 211 212 213 214
     */
    public void clearIconCache()
    {
      iconCache.clear();
    }

    /**
215 216
     * Retrieves the icon associated with the specified file/directory, if 
     * there is one.
Tom Tromey committed
217
     *
218
     * @param f  the file/directory.
Tom Tromey committed
219
     *
220
     * @return The cached icon (or <code>null</code>).
Tom Tromey committed
221 222 223 224 225 226 227
     */
    public Icon getCachedIcon(File f)
    {
      return (Icon) iconCache.get(f);
    }

    /**
228 229 230
     * Returns a description of the given file/directory.  In this 
     * implementation, the description is the same as the name returned by 
     * {@link #getName(File)}.
Tom Tromey committed
231
     *
232
     * @param f  the file/directory.
Tom Tromey committed
233
     *
234
     * @return A description of the given file/directory.
Tom Tromey committed
235 236 237 238 239 240 241
     */
    public String getDescription(File f)
    {
      return getName(f);
    }

    /**
242
     * Returns an icon appropriate for the given file or directory.
Tom Tromey committed
243
     *
244
     * @param f  the file/directory.
Tom Tromey committed
245
     *
246
     * @return An icon.
Tom Tromey committed
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
     */
    public Icon getIcon(File f)
    {
      Icon val = getCachedIcon(f);
      if (val != null)
	return val;
      if (filechooser.isTraversable(f))
	val = directoryIcon;
      else
	val = fileIcon;
      cacheIcon(f, val);
      return val;
    }

    /**
262
     * Returns the name for the given file/directory.
Tom Tromey committed
263
     *
264
     * @param f  the file/directory.
Tom Tromey committed
265
     *
266
     * @return The name of the file/directory.
Tom Tromey committed
267 268 269
     */
    public String getName(File f)
    {
270 271 272 273 274 275 276 277
      String name = null;
      if (f != null)
        {
          JFileChooser c = getFileChooser();
          FileSystemView v = c.getFileSystemView();
          name = v.getSystemDisplayName(f);
        }
      return name;
Tom Tromey committed
278 279 280
    }

    /**
281
     * Returns a localised description for the type of file/directory.
Tom Tromey committed
282
     *
283
     * @param f  the file/directory.
Tom Tromey committed
284
     *
285
     * @return A type description for the given file/directory.
Tom Tromey committed
286 287 288 289 290 291 292 293 294 295
     */
    public String getTypeDescription(File f)
    {
      if (filechooser.isTraversable(f))
	return dirDescText;
      else
	return fileDescText;
    }

    /**
296 297
     * Returns {@link Boolean#TRUE} if the given file/directory is hidden,
     * and {@link Boolean#FALSE} otherwise.
Tom Tromey committed
298
     *
299
     * @param f  the file/directory.
Tom Tromey committed
300
     *
301
     * @return {@link Boolean#TRUE} or {@link Boolean#FALSE}.
Tom Tromey committed
302 303 304
     */
    public Boolean isHidden(File f)
    {
305
      return Boolean.valueOf(filechooser.getFileSystemView().isHiddenFile(f));
Tom Tromey committed
306 307 308 309
    }
  }

  /**
310 311 312
   * Handles an action to cancel the file chooser.
   * 
   * @see BasicFileChooserUI#getCancelSelectionAction()
Tom Tromey committed
313 314 315 316
   */
  protected class CancelSelectionAction extends AbstractAction
  {
    /**
317
     * Creates a new <code>CancelSelectionAction</code> object.
Tom Tromey committed
318 319 320
     */
    protected CancelSelectionAction()
    {
321
      super(null);
Tom Tromey committed
322 323 324
    }

    /**
325
     * Cancels the selection and closes the dialog.
Tom Tromey committed
326
     *
327
     * @param e  the action event (ignored).
Tom Tromey committed
328 329 330
     */
    public void actionPerformed(ActionEvent e)
    {
331 332
      filechooser.setSelectedFile(null);
      filechooser.setSelectedFiles(null);
Tom Tromey committed
333 334 335 336 337 338
      filechooser.cancelSelection();
      closeDialog();
    }
  }

  /**
339 340 341 342
   * An action to handle changes to the parent directory (for example, via
   * a click on the "up folder" button).
   * 
   * @see BasicFileChooserUI#getChangeToParentDirectoryAction()
Tom Tromey committed
343 344 345 346
   */
  protected class ChangeToParentDirectoryAction extends AbstractAction
  {
    /**
347
     * Creates a new <code>ChangeToParentDirectoryAction</code> object.
Tom Tromey committed
348 349 350
     */
    protected ChangeToParentDirectoryAction()
    {
351
      super("Go Up");
Tom Tromey committed
352 353 354
    }

    /**
355
     * Handles the action event.
Tom Tromey committed
356
     *
357
     * @param e  the action event.
Tom Tromey committed
358 359 360 361 362 363 364 365 366 367
     */
    public void actionPerformed(ActionEvent e)
    {
      filechooser.changeToParentDirectory();
      filechooser.revalidate();
      filechooser.repaint();
    }
  }

  /**
368 369 370
   * A mouse listener that handles double-click events.
   * 
   * @see BasicFileChooserUI#createDoubleClickListener(JFileChooser, JList)
Tom Tromey committed
371 372 373 374 375
   */
  protected class DoubleClickListener extends MouseAdapter
  {

    /** DOCUMENT ME! */
376
    private Object lastSelected;
Tom Tromey committed
377 378

    /** DOCUMENT ME! */
379
    private JList list;
Tom Tromey committed
380 381 382 383 384 385 386 387 388 389 390 391 392 393

    /**
     * Creates a new DoubleClickListener object.
     *
     * @param list DOCUMENT ME!
     */
    public DoubleClickListener(JList list)
    {
      this.list = list;
      lastSelected = list.getSelectedValue();
      setDirectorySelected(false);
    }

    /**
394 395 396
     * Handles a mouse click event.
     * 
     * @param e  the event.
Tom Tromey committed
397 398 399
     */
    public void mouseClicked(MouseEvent e)
    {
400 401
      Object p = list.getSelectedValue();
      if (p == null)
402
        return;
Tom Tromey committed
403
      FileSystemView fsv = filechooser.getFileSystemView();
404 405
      if (e.getClickCount() >= 2 && lastSelected != null &&
          p.toString().equals(lastSelected.toString()))
Tom Tromey committed
406
        {
407 408 409 410 411 412 413 414 415 416 417 418
          File f = fsv.createFileObject(lastSelected.toString());
          if (filechooser.isTraversable(f))
            {
              filechooser.setCurrentDirectory(f);
              filechooser.rescanCurrentDirectory();
            }
          else
            {
              filechooser.setSelectedFile(f);
              filechooser.approveSelection();
              closeDialog();
            }
Tom Tromey committed
419
        }
420
      else // single click
Tom Tromey committed
421
        {
422
          String path = p.toString();
423
          File f = fsv.createFileObject(path);
424 425 426 427 428 429 430 431 432 433 434
          filechooser.setSelectedFile(f);
          
          if (filechooser.isMultiSelectionEnabled())
            {
              int[] inds = list.getSelectedIndices();
              File[] allFiles = new File[inds.length];
              for (int i = 0; i < inds.length; i++)
                allFiles[i] = (File) list.getModel().getElementAt(inds[i]);
              filechooser.setSelectedFiles(allFiles);
            }
          
435 436 437 438 439 440 441 442 443 444 445
          if (filechooser.isTraversable(f))
            {
              setDirectorySelected(true);
              setDirectory(f);
            }
          else
            {
              setDirectorySelected(false);
              setDirectory(null);
            }
          lastSelected = path;
446
          parentPath = f.getParent();
447
	    
448
          if (f.isFile())
449
            setFileName(f.getName());
450 451
          else if (filechooser.getFileSelectionMode() != 
		   JFileChooser.FILES_ONLY)
452
            setFileName(path);
Tom Tromey committed
453 454 455 456
        }
    }

    /**
457 458 459
     * Handles a mouse entered event (NOT IMPLEMENTED).
     * 
     * @param e  the mouse event.
Tom Tromey committed
460 461 462 463 464 465 466 467
     */
    public void mouseEntered(MouseEvent e)
    {
      // FIXME: Implement
    }
  }

  /**
468 469 470 471
   * An action that changes the file chooser to display the user's home 
   * directory. 
   * 
   * @see BasicFileChooserUI#getGoHomeAction()
Tom Tromey committed
472 473 474 475
   */
  protected class GoHomeAction extends AbstractAction
  {
    /**
476
     * Creates a new <code>GoHomeAction</code> object.
Tom Tromey committed
477 478 479
     */
    protected GoHomeAction()
    {
480
      super("Go Home");
Tom Tromey committed
481 482 483
    }

    /**
484 485
     * Sets the directory to the user's home directory, and repaints the
     * file chooser component.
Tom Tromey committed
486
     *
487
     * @param e  the action event (ignored).
Tom Tromey committed
488 489 490 491 492 493 494 495 496 497 498
     */
    public void actionPerformed(ActionEvent e)
    {
      filechooser.setCurrentDirectory(filechooser.getFileSystemView()
                                                 .getHomeDirectory());
      filechooser.revalidate();
      filechooser.repaint();
    }
  }

  /**
499 500 501
   * An action that handles the creation of a new folder/directory.
   * 
   * @see BasicFileChooserUI#getNewFolderAction()
Tom Tromey committed
502 503 504 505
   */
  protected class NewFolderAction extends AbstractAction
  {
    /**
506
     * Creates a new <code>NewFolderAction</code> object.
Tom Tromey committed
507 508 509
     */
    protected NewFolderAction()
    {
510
      super("New Folder");
Tom Tromey committed
511 512 513
    }

    /**
514
     * Handles the event by creating a new folder.
Tom Tromey committed
515
     *
516
     * @param e  the action event (ignored).
Tom Tromey committed
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534
     */
    public void actionPerformed(ActionEvent e)
    {
      try
        {
	  filechooser.getFileSystemView().createNewFolder(filechooser
	                                                  .getCurrentDirectory());
        }
      catch (IOException ioe)
        {
	  return;
        }
      filechooser.rescanCurrentDirectory();
      filechooser.repaint();
    }
  }

  /**
535 536 537
   * A listener for selection events in the file list.
   * 
   * @see BasicFileChooserUI#createListSelectionListener(JFileChooser)
Tom Tromey committed
538 539 540 541
   */
  protected class SelectionListener implements ListSelectionListener
  {
    /**
542
     * Creates a new <code>SelectionListener</code> object.
Tom Tromey committed
543 544 545
     */
    protected SelectionListener()
    {
546
      // Nothing to do here.
Tom Tromey committed
547 548 549
    }

    /**
550
     * Sets the JFileChooser to the selected file on an update
Tom Tromey committed
551 552 553 554 555
     *
     * @param e DOCUMENT ME!
     */
    public void valueChanged(ListSelectionEvent e)
    {
556 557
      JList list = (JList) e.getSource();
      Object f = list.getSelectedValue();
Tom Tromey committed
558 559 560 561
      if (f == null)
	return;
      File file = filechooser.getFileSystemView().createFileObject(f.toString());
      if (! filechooser.isTraversable(file))
562 563 564 565
	{
	  selectedDir = null;
	  filechooser.setSelectedFile(file);
	}
Tom Tromey committed
566
      else
567 568 569 570
	{
	  selectedDir = file;
	  filechooser.setSelectedFile(null);
	}
Tom Tromey committed
571 572 573 574 575
    }
  }

  /**
   * DOCUMENT ME!
576 577
   * 
   * @see BasicFileChooserUI#getUpdateAction()
Tom Tromey committed
578 579 580 581 582 583 584 585
   */
  protected class UpdateAction extends AbstractAction
  {
    /**
     * Creates a new UpdateAction object.
     */
    protected UpdateAction()
    {
586
      super(null);
Tom Tromey committed
587 588 589
    }

    /**
590
     * NOT YET IMPLEMENTED.
Tom Tromey committed
591
     *
592
     * @param e  the action event.
Tom Tromey committed
593 594 595
     */
    public void actionPerformed(ActionEvent e)
    {
596
      // FIXME: implement this
Tom Tromey committed
597 598 599
    }
  }

600
  /** The localised mnemonic for the cancel button. */
Tom Tromey committed
601 602
  protected int cancelButtonMnemonic;

603
  /** The localised text for the cancel button. */
Tom Tromey committed
604 605
  protected String cancelButtonText;

606
  /** The localised tool tip text for the cancel button. */
Tom Tromey committed
607 608
  protected String cancelButtonToolTipText;

609
  /** An icon representing a computer. */
610
  protected Icon computerIcon;
Tom Tromey committed
611

612
  /** An icon for the "details view" button. */
613
  protected Icon detailsViewIcon;
Tom Tromey committed
614

615
  /** An icon representing a directory. */
616
  protected Icon directoryIcon;
Tom Tromey committed
617

618
  /** The localised Mnemonic for the open button. */
Tom Tromey committed
619 620
  protected int directoryOpenButtonMnemonic;

621
  /** The localised text for the open button. */
Tom Tromey committed
622 623
  protected String directoryOpenButtonText;

624
  /** The localised tool tip text for the open button. */
Tom Tromey committed
625 626
  protected String directoryOpenButtonToolTipText;

627
  /** An icon representing a file. */
628
  protected Icon fileIcon;
Tom Tromey committed
629

630
  /** An icon representing a floppy drive. */
631
  protected Icon floppyDriveIcon;
Tom Tromey committed
632

633
  /** An icon representing a hard drive. */
634
  protected Icon hardDriveIcon;
Tom Tromey committed
635

636
  /** The localised mnemonic for the "help" button. */
Tom Tromey committed
637 638
  protected int helpButtonMnemonic;

639
  /** The localised text for the "help" button. */
Tom Tromey committed
640 641
  protected String helpButtonText;

642
  /** The localised tool tip text for the help button. */
Tom Tromey committed
643 644
  protected String helpButtonToolTipText;

645
  /** An icon representing the user's home folder. */
646
  protected Icon homeFolderIcon;
Tom Tromey committed
647

648
  /** An icon for the "list view" button. */
649
  protected Icon listViewIcon;
Tom Tromey committed
650

651
  /** An icon for the "new folder" button. */
Tom Tromey committed
652 653
  protected Icon newFolderIcon = directoryIcon;

654
  /** The localised mnemonic for the "open" button. */
Tom Tromey committed
655 656
  protected int openButtonMnemonic;

657
  /** The localised text for the "open" button. */
Tom Tromey committed
658 659
  protected String openButtonText;

660
  /** The localised tool tip text for the "open" button. */
Tom Tromey committed
661 662
  protected String openButtonToolTipText;

663
  /** The localised mnemonic for the "save" button. */
Tom Tromey committed
664 665
  protected int saveButtonMnemonic;

666
  /** The localised text for the "save" button. */
Tom Tromey committed
667 668
  protected String saveButtonText;

669
  /** The localised tool tip text for the save button. */
Tom Tromey committed
670 671
  protected String saveButtonToolTipText;

672
  /** The localised mnemonic for the "update" button. */
Tom Tromey committed
673 674
  protected int updateButtonMnemonic;

675
  /** The localised text for the "update" button. */
Tom Tromey committed
676 677
  protected String updateButtonText;

678
  /** The localised tool tip text for the "update" button. */
Tom Tromey committed
679 680
  protected String updateButtonToolTipText;

681
  /** An icon for the "up folder" button. */
682
  protected Icon upFolderIcon;
Tom Tromey committed
683 684 685

  // -- begin private, but package local since used in inner classes --

686
  /** The file chooser component represented by this UI delegate. */
Tom Tromey committed
687 688
  JFileChooser filechooser;

689
  /** The model for the directory list. */
Tom Tromey committed
690 691
  BasicDirectoryModel model;

692
  /** The file filter for all files. */
Tom Tromey committed
693 694
  FileFilter acceptAll = new AcceptAllFileFilter();

695
  /** The default file view. */
Tom Tromey committed
696 697
  FileView fv = new BasicFileView();

698
  /** The accept (open/save) button. */
Tom Tromey committed
699 700
  JButton accept;

701
  /** An optional accessory panel. */
702
  JPanel accessoryPanel = new JPanel();
Tom Tromey committed
703

704
  /** A property change listener. */
Tom Tromey committed
705 706
  PropertyChangeListener propertyChangeListener;

707
  /** The text describing the filter for "all files". */
Tom Tromey committed
708 709
  String acceptAllFileFilterText;

710
  /** The text describing a directory type. */
Tom Tromey committed
711 712
  String dirDescText;

713
  /** The text describing a file type. */
Tom Tromey committed
714 715
  String fileDescText;

716
  /** Is a directory selected? */
717
  boolean dirSelected;
Tom Tromey committed
718

719
  /** The current directory. */
720
  File currDir;
Tom Tromey committed
721

722 723
  // FIXME: describe what is contained in the bottom panel
  /** The bottom panel. */
Tom Tromey committed
724
  JPanel bottomPanel;
725 726
  
  /** The close panel. */
Tom Tromey committed
727 728
  JPanel closePanel;

729 730 731 732 733 734
  /** Text box that displays file name */
  JTextField entry;
    
  /** Current parent path */
  String parentPath;
  
735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769
  /**
   * The action for the 'approve' button.
   * @see #getApproveSelectionAction()
   */
  private ApproveSelectionAction approveSelectionAction;
  
  /**
   * The action for the 'cancel' button.
   * @see #getCancelSelectionAction()
   */
  private CancelSelectionAction cancelSelectionAction;
  
  /**
   * The action for the 'go home' control button.
   * @see #getGoHomeAction()
   */
  private GoHomeAction goHomeAction;
  
  /**
   * The action for the 'up folder' control button.
   * @see #getChangeToParentDirectoryAction()
   */
  private ChangeToParentDirectoryAction changeToParentDirectoryAction;
  
  /**
   * The action for the 'new folder' control button.
   * @see #getNewFolderAction()
   */
  private NewFolderAction newFolderAction;
  
  /**
   * The action for ???.  // FIXME: what is this?
   * @see #getUpdateAction()
   */
  private UpdateAction updateAction;
770 771 772 773 774 775 776

  /**
   * When in FILES_ONLY, mode a directory cannot be selected, so
   * we save a reference to any it here. This is used to enter
   * the directory on "Open" when in that mode.
   */
  private File selectedDir;
777
  
Tom Tromey committed
778 779 780
  // -- end private --

  /**
781
   * Closes the dialog.
Tom Tromey committed
782 783 784 785 786 787 788 789 790
   */
  void closeDialog()
  {
    Window owner = SwingUtilities.windowForComponent(filechooser);
    if (owner instanceof JDialog)
      ((JDialog) owner).dispose();
  }

  /**
791
   * Creates a new <code>BasicFileChooserUI</code> object.
Tom Tromey committed
792
   *
793
   * @param b  the file chooser component.
Tom Tromey committed
794 795 796 797 798 799
   */
  public BasicFileChooserUI(JFileChooser b)
  {
  }

  /**
800
   * Returns a UI delegate for the given component.
Tom Tromey committed
801
   *
802
   * @param c  the component (should be a {@link JFileChooser}).
Tom Tromey committed
803
   *
804
   * @return A new UI delegate.
Tom Tromey committed
805 806 807 808 809 810 811
   */
  public static ComponentUI createUI(JComponent c)
  {
    return new BasicFileChooserUI((JFileChooser) c);
  }

  /**
812 813 814
   * Installs the UI for the specified component.
   * 
   * @param c  the component (should be a {@link JFileChooser}).
Tom Tromey committed
815 816 817 818 819
   */
  public void installUI(JComponent c)
  {
    if (c instanceof JFileChooser)
      {
820
        JFileChooser fc = (JFileChooser) c;
821
        this.filechooser = fc;
822 823 824 825 826 827 828
        fc.resetChoosableFileFilters();
        createModel();
        clearIconCache();
        installDefaults(fc);
        installComponents(fc);
        installListeners(fc);
        
829
        File path = filechooser.getCurrentDirectory();
830
        if (path != null)
831
          parentPath = path.getParent();
Tom Tromey committed
832 833 834 835
      }
  }

  /**
836 837 838
   * Uninstalls this UI from the given component.
   * 
   * @param c  the component (should be a {@link JFileChooser}).
Tom Tromey committed
839 840 841 842 843 844 845 846 847 848 849
   */
  public void uninstallUI(JComponent c)
  {
    model = null;
    uninstallListeners(filechooser);
    uninstallComponents(filechooser);
    uninstallDefaults(filechooser);
    filechooser = null;
  }

  // FIXME: Indent the entries in the combobox
Tom Tromey committed
850 851 852
  // Made this method package private to access it from within inner classes
  // with better performance
  void boxEntries()
Tom Tromey committed
853 854 855 856 857 858 859
  {
    ArrayList parentFiles = new ArrayList();
    File parent = filechooser.getCurrentDirectory();
    if (parent == null)
      parent = filechooser.getFileSystemView().getDefaultDirectory();
    while (parent != null)
      {
Tom Tromey committed
860 861 862
        String name = parent.getName();
        if (name.equals(""))
          name = parent.getAbsolutePath();
Tom Tromey committed
863

Tom Tromey committed
864 865
        parentFiles.add(parentFiles.size(), name);
        parent = parent.getParentFile();
Tom Tromey committed
866 867 868 869 870
      }

    if (parentFiles.size() == 0)
      return;

871
  }  
Tom Tromey committed
872 873

  /**
874
   * Creates and install the subcomponents for the file chooser.
Tom Tromey committed
875
   *
876
   * @param fc  the file chooser.
Tom Tromey committed
877 878 879 880 881 882
   */
  public void installComponents(JFileChooser fc)
  {
  }

  /**
883
   * Uninstalls the components from the file chooser.
Tom Tromey committed
884
   *
885
   * @param fc  the file chooser.
Tom Tromey committed
886 887 888 889 890 891
   */
  public void uninstallComponents(JFileChooser fc)
  {
  }

  /**
892
   * Installs the listeners required by this UI delegate.
Tom Tromey committed
893
   *
894
   * @param fc  the file chooser.
Tom Tromey committed
895 896 897 898
   */
  protected void installListeners(JFileChooser fc)
  {
    propertyChangeListener = createPropertyChangeListener(filechooser);
899 900 901
    if (propertyChangeListener != null)
      filechooser.addPropertyChangeListener(propertyChangeListener);
    fc.addPropertyChangeListener(getModel());
Tom Tromey committed
902 903 904
  }

  /**
905
   * Uninstalls the listeners previously installed by this UI delegate.
Tom Tromey committed
906
   *
907
   * @param fc  the file chooser.
Tom Tromey committed
908 909 910
   */
  protected void uninstallListeners(JFileChooser fc)
  {
911 912 913 914 915 916
    if (propertyChangeListener != null)
      {
        filechooser.removePropertyChangeListener(propertyChangeListener);
        propertyChangeListener = null;
      }
    fc.removePropertyChangeListener(getModel());
Tom Tromey committed
917 918 919
  }

  /**
920
   * Installs the defaults for this UI delegate.
Tom Tromey committed
921
   *
922
   * @param fc  the file chooser.
Tom Tromey committed
923 924 925 926 927 928 929 930
   */
  protected void installDefaults(JFileChooser fc)
  {
    installIcons(fc);
    installStrings(fc);
  }

  /**
931
   * Uninstalls the defaults previously added by this UI delegate.
Tom Tromey committed
932
   *
933
   * @param fc  the file chooser.
Tom Tromey committed
934 935 936 937 938 939 940 941
   */
  protected void uninstallDefaults(JFileChooser fc)
  {
    uninstallStrings(fc);
    uninstallIcons(fc);
  }

  /**
942
   * Installs the icons for this UI delegate.
Tom Tromey committed
943
   *
944
   * @param fc  the file chooser (ignored).
Tom Tromey committed
945 946 947
   */
  protected void installIcons(JFileChooser fc)
  {
948 949 950 951 952 953 954 955 956 957 958
    UIDefaults defaults = UIManager.getLookAndFeelDefaults();
    computerIcon = MetalIconFactory.getTreeComputerIcon();
    detailsViewIcon = defaults.getIcon("FileChooser.detailsViewIcon");
    directoryIcon = new MetalIconFactory.TreeFolderIcon();
    fileIcon = new MetalIconFactory.TreeLeafIcon();
    floppyDriveIcon = MetalIconFactory.getTreeFloppyDriveIcon();
    hardDriveIcon = MetalIconFactory.getTreeHardDriveIcon();
    homeFolderIcon = defaults.getIcon("FileChooser.homeFolderIcon");
    listViewIcon = defaults.getIcon("FileChooser.listViewIcon");
    newFolderIcon = defaults.getIcon("FileChooser.newFolderIcon");
    upFolderIcon = defaults.getIcon("FileChooser.upFolderIcon");
Tom Tromey committed
959 960 961
  }

  /**
962
   * Uninstalls the icons previously added by this UI delegate.
Tom Tromey committed
963
   *
964
   * @param fc  the file chooser.
Tom Tromey committed
965 966 967
   */
  protected void uninstallIcons(JFileChooser fc)
  {
968 969 970 971 972 973 974 975 976 977
    computerIcon = null;
    detailsViewIcon = null;
    directoryIcon = null;
    fileIcon = null;
    floppyDriveIcon = null;
    hardDriveIcon = null;
    homeFolderIcon = null;
    listViewIcon = null;
    newFolderIcon = null;
    upFolderIcon = null;
Tom Tromey committed
978 979 980
  }

  /**
981
   * Installs the strings used by this UI delegate.
Tom Tromey committed
982
   *
983
   * @param fc  the file chooser.
Tom Tromey committed
984 985 986
   */
  protected void installStrings(JFileChooser fc)
  {
987 988 989 990
    UIDefaults defaults = UIManager.getLookAndFeelDefaults();

    dirDescText = defaults.getString("FileChooser.directoryDescriptionText");
    fileDescText = defaults.getString("FileChooser.fileDescriptionText");
Tom Tromey committed
991

992 993 994 995
    acceptAllFileFilterText = defaults.getString("FileChooser.acceptAllFileFilterText");
    cancelButtonText = "Cancel";
    cancelButtonToolTipText = "Abort file chooser dialog";
    cancelButtonMnemonic = new Integer((String) UIManager.get("FileChooser.cancelButtonMnemonic")).intValue();
Tom Tromey committed
996

997 998 999 1000 1001 1002 1003 1004
    directoryOpenButtonText = "Open";
    directoryOpenButtonToolTipText = "Open selected directory";
    directoryOpenButtonMnemonic 
        = new Integer((String) UIManager.get("FileChooser.directoryOpenButtonMnemonic")).intValue();
    
    helpButtonText = "Help";
    helpButtonToolTipText = "FileChooser help";
    helpButtonMnemonic = new Integer((String) UIManager.get("FileChooser.helpButtonMnemonic")).intValue();
Tom Tromey committed
1005

1006 1007 1008
    openButtonText = "Open";
    openButtonToolTipText = "Open selected file";
    openButtonMnemonic = new Integer((String) UIManager.get("FileChooser.openButtonMnemonic")).intValue();
Tom Tromey committed
1009

1010 1011 1012 1013 1014 1015 1016
    saveButtonText = "Save";
    saveButtonToolTipText = "Save selected file";
    saveButtonMnemonic = new Integer((String) UIManager.get("FileChooser.saveButtonMnemonic")).intValue();
  
    updateButtonText = "Update";
    updateButtonToolTipText = "Update directory listing";
    updateButtonMnemonic = new Integer((String) UIManager.get("FileChooser.updateButtonMnemonic")).intValue();
Tom Tromey committed
1017 1018 1019
  }

  /**
1020
   * Uninstalls the strings previously added by this UI delegate.
Tom Tromey committed
1021
   *
1022
   * @param fc  the file chooser.
Tom Tromey committed
1023 1024 1025 1026
   */
  protected void uninstallStrings(JFileChooser fc)
  {
    acceptAllFileFilterText = null;
1027 1028 1029
    dirDescText = null;
    fileDescText = null;

Tom Tromey committed
1030 1031 1032
    cancelButtonText = null;
    cancelButtonToolTipText = null;

1033 1034
    directoryOpenButtonText = null;
    directoryOpenButtonToolTipText = null;
Tom Tromey committed
1035 1036 1037 1038 1039 1040 1041 1042 1043

    helpButtonText = null;
    helpButtonToolTipText = null;

    openButtonText = null;
    openButtonToolTipText = null;

    saveButtonText = null;
    saveButtonToolTipText = null;
1044 1045 1046
    
    updateButtonText = null;
    updateButtonToolTipText = null;
Tom Tromey committed
1047 1048 1049
  }

  /**
1050
   * Creates a new directory model.
Tom Tromey committed
1051 1052 1053 1054 1055 1056 1057
   */
  protected void createModel()
  {
    model = new BasicDirectoryModel(filechooser);
  }

  /**
1058
   * Returns the directory model.
Tom Tromey committed
1059
   *
1060
   * @return The directory model.
Tom Tromey committed
1061 1062 1063 1064 1065 1066 1067
   */
  public BasicDirectoryModel getModel()
  {
    return model;
  }

  /**
1068 1069 1070 1071 1072 1073
   * Creates a listener to handle changes to the properties of the given
   * file chooser component.
   * 
   * @param fc  the file chooser component.
   * 
   * @return A new listener.
Tom Tromey committed
1074 1075 1076
   */
  public PropertyChangeListener createPropertyChangeListener(JFileChooser fc)
  {
1077 1078
    // The RI returns null here, so do we.
    return null;
Tom Tromey committed
1079 1080 1081
  }

  /**
1082 1083 1084
   * Returns the current file name.
   * 
   * @return The current file name.
Tom Tromey committed
1085 1086 1087
   */
  public String getFileName()
  {
1088
    return entry.getText();
Tom Tromey committed
1089 1090 1091
  }

  /**
1092
   * Returns the current directory name.
Tom Tromey committed
1093
   *
1094 1095 1096
   * @return The directory name.
   * 
   * @see #setDirectoryName(String)
Tom Tromey committed
1097 1098 1099 1100 1101 1102 1103 1104
   */
  public String getDirectoryName()
  {
    // XXX: I don't see a case where the thing returns something non-null..
    return null;
  }

  /**
1105
   * Sets the file name.
Tom Tromey committed
1106
   *
1107 1108 1109
   * @param filename  the file name.
   * 
   * @see #getFileName()
Tom Tromey committed
1110 1111 1112
   */
  public void setFileName(String filename)
  {
1113 1114 1115
    // FIXME:  it might be the case that this method provides an access 
    // point for the JTextField (or whatever) a subclass is using...
    //this.filename = filename;
Tom Tromey committed
1116 1117 1118
  }

  /**
1119
   * Sets the directory name (NOT IMPLEMENTED).
Tom Tromey committed
1120
   *
1121 1122 1123
   * @param dirname  the directory name.
   * 
   * @see #getDirectoryName()
Tom Tromey committed
1124 1125 1126 1127 1128 1129 1130
   */
  public void setDirectoryName(String dirname)
  {
    // FIXME: Implement
  }

  /**
1131
   * Rescans the current directory.
Tom Tromey committed
1132
   *
1133
   * @param fc  the file chooser.
Tom Tromey committed
1134 1135 1136 1137 1138 1139 1140
   */
  public void rescanCurrentDirectory(JFileChooser fc)
  {
    getModel().validateFileCache();
  }

  /**
1141
   * NOT YET IMPLEMENTED.
Tom Tromey committed
1142
   *
1143 1144
   * @param fc  the file chooser.
   * @param f  the file.
Tom Tromey committed
1145 1146 1147 1148 1149 1150 1151
   */
  public void ensureFileIsVisible(JFileChooser fc, File f)
  {
    // XXX: Not sure what this does.
  }

  /**
1152 1153
   * Returns the {@link JFileChooser} component that this UI delegate 
   * represents.
Tom Tromey committed
1154
   *
1155
   * @return The component represented by this UI delegate.
Tom Tromey committed
1156 1157 1158 1159 1160 1161 1162
   */
  public JFileChooser getFileChooser()
  {
    return filechooser;
  }

  /**
1163
   * Returns the optional accessory panel.
Tom Tromey committed
1164
   *
1165
   * @return The optional accessory panel.
Tom Tromey committed
1166 1167 1168 1169 1170 1171 1172
   */
  public JPanel getAccessoryPanel()
  {
    return accessoryPanel;
  }

  /**
1173
   * Returns the approve (open or save) button for the dialog.
Tom Tromey committed
1174
   *
1175
   * @param fc  the file chooser.
Tom Tromey committed
1176
   *
1177
   * @return The button.
Tom Tromey committed
1178
   */
1179
  protected JButton getApproveButton(JFileChooser fc)
Tom Tromey committed
1180 1181 1182 1183 1184
  {
    return accept;
  }

  /**
1185 1186 1187 1188
   * Returns the tool tip text for the approve (open/save) button.  This first
   * checks the file chooser to see if a value has been explicitly set - if
   * not, a default value appropriate for the type of file chooser is 
   * returned.
Tom Tromey committed
1189
   *
1190
   * @param fc  the file chooser.
Tom Tromey committed
1191
   *
1192
   * @return The tool tip text.
Tom Tromey committed
1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204
   */
  public String getApproveButtonToolTipText(JFileChooser fc)
  {
    if (fc.getApproveButtonToolTipText() != null)
      return fc.getApproveButtonToolTipText();
    else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG)
      return saveButtonToolTipText;
    else
      return openButtonToolTipText;
  }

  /**
1205
   * Clears the icon cache.
Tom Tromey committed
1206 1207 1208 1209 1210 1211 1212 1213
   */
  public void clearIconCache()
  {
    if (fv instanceof BasicFileView)
      ((BasicFileView) fv).clearIconCache();
  }

  /**
1214
   * Creates a new listener to handle selections in the file list.
Tom Tromey committed
1215
   *
1216
   * @param fc  the file chooser component.
Tom Tromey committed
1217
   *
1218
   * @return A new instance of {@link SelectionListener}.
Tom Tromey committed
1219 1220 1221 1222 1223 1224 1225
   */
  public ListSelectionListener createListSelectionListener(JFileChooser fc)
  {
    return new SelectionListener();
  }

  /**
1226
   * Creates a new listener to handle double-click events.
Tom Tromey committed
1227
   *
1228 1229
   * @param fc  the file chooser component.
   * @param list  the list.
Tom Tromey committed
1230
   *
1231
   * @return A new instance of {@link DoubleClickListener}.
Tom Tromey committed
1232 1233 1234 1235 1236 1237 1238
   */
  protected MouseListener createDoubleClickListener(JFileChooser fc, JList list)
  {
    return new DoubleClickListener(list);
  }

  /**
1239 1240
   * Returns <code>true</code> if a directory is selected, and 
   * <code>false</code> otherwise.
Tom Tromey committed
1241
   *
1242
   * @return A boolean.
Tom Tromey committed
1243 1244 1245 1246 1247 1248 1249
   */
  protected boolean isDirectorySelected()
  {
    return dirSelected;
  }

  /**
1250
   * Sets the flag that indicates whether the current directory is selected.
Tom Tromey committed
1251
   *
1252
   * @param selected  the new flag value.
Tom Tromey committed
1253 1254 1255 1256 1257 1258 1259
   */
  protected void setDirectorySelected(boolean selected)
  {
    dirSelected = selected;
  }

  /**
1260
   * Returns the current directory.
Tom Tromey committed
1261
   *
1262
   * @return The current directory.
Tom Tromey committed
1263 1264 1265 1266 1267 1268 1269
   */
  protected File getDirectory()
  {
    return currDir;
  }

  /**
1270
   * Sets the current directory.
Tom Tromey committed
1271
   *
1272
   * @param f  the directory.
Tom Tromey committed
1273 1274 1275 1276 1277 1278 1279
   */
  protected void setDirectory(File f)
  {
    currDir = f;
  }

  /**
1280
   * Returns the "accept all" file filter.
Tom Tromey committed
1281
   *
1282
   * @param fc  the file chooser component.
Tom Tromey committed
1283
   *
1284
   * @return The "accept all" file filter.
Tom Tromey committed
1285 1286 1287 1288 1289 1290 1291
   */
  public FileFilter getAcceptAllFileFilter(JFileChooser fc)
  {
    return acceptAll;
  }

  /**
1292 1293
   * Returns the default file view (NOT the file view from the file chooser,
   * if there is one).
Tom Tromey committed
1294
   *
1295
   * @param fc  the file chooser component.
Tom Tromey committed
1296
   *
1297 1298 1299
   * @return The file view.
   * 
   * @see JFileChooser#getFileView()
Tom Tromey committed
1300 1301 1302 1303 1304 1305 1306
   */
  public FileView getFileView(JFileChooser fc)
  {
    return fv;
  }

  /**
1307
   * Returns the dialog title.
Tom Tromey committed
1308
   *
1309
   * @param fc  the file chooser (<code>null</code> not permitted).
Tom Tromey committed
1310
   *
1311 1312 1313
   * @return The dialog title.
   * 
   * @see JFileChooser#getDialogTitle()
Tom Tromey committed
1314 1315 1316
   */
  public String getDialogTitle(JFileChooser fc)
  {
1317 1318 1319 1320
    String result = fc.getDialogTitle();
    if (result == null)
      result = getApproveButtonText(fc);
    return result;
Tom Tromey committed
1321 1322 1323
  }

  /**
1324
   * Returns the approve button mnemonic.
Tom Tromey committed
1325
   *
1326
   * @param fc  the file chooser (<code>null</code> not permitted).
Tom Tromey committed
1327
   *
1328 1329 1330
   * @return The approve button mnemonic.
   * 
   * @see JFileChooser#getApproveButtonMnemonic()
Tom Tromey committed
1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342
   */
  public int getApproveButtonMnemonic(JFileChooser fc)
  {
    if (fc.getApproveButtonMnemonic() != 0)
      return fc.getApproveButtonMnemonic();
    else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG)
      return saveButtonMnemonic;
    else
      return openButtonMnemonic;
  }

  /**
1343
   * Returns the approve button text.
Tom Tromey committed
1344
   *
1345
   * @param fc  the file chooser (<code>null</code> not permitted).
Tom Tromey committed
1346
   *
1347 1348 1349
   * @return The approve button text.
   * 
   * @see JFileChooser#getApproveButtonText()
Tom Tromey committed
1350 1351 1352
   */
  public String getApproveButtonText(JFileChooser fc)
  {
1353 1354 1355 1356 1357 1358 1359 1360 1361
    String result = fc.getApproveButtonText();
    if (result == null)
      {
        if (fc.getDialogType() == JFileChooser.SAVE_DIALOG)
          result = saveButtonText;
        else
          result = openButtonText;
      }
    return result;
Tom Tromey committed
1362 1363 1364
  }

  /**
1365 1366
   * Creates and returns a new action that will be used with the "new folder" 
   * button.
Tom Tromey committed
1367
   *
1368
   * @return A new instance of {@link NewFolderAction}.
Tom Tromey committed
1369 1370 1371
   */
  public Action getNewFolderAction()
  {
1372 1373 1374
    if (newFolderAction == null)
      newFolderAction = new NewFolderAction();
    return newFolderAction;
Tom Tromey committed
1375 1376 1377
  }

  /**
1378 1379
   * Creates and returns a new action that will be used with the "home folder" 
   * button.
Tom Tromey committed
1380
   *
1381
   * @return A new instance of {@link GoHomeAction}.
Tom Tromey committed
1382 1383 1384
   */
  public Action getGoHomeAction()
  {
1385 1386 1387
    if (goHomeAction == null)
      goHomeAction = new GoHomeAction();
    return goHomeAction;
Tom Tromey committed
1388 1389 1390
  }

  /**
1391
   * Returns the action that handles events for the "up folder" control button.
Tom Tromey committed
1392
   *
1393
   * @return An instance of {@link ChangeToParentDirectoryAction}.
Tom Tromey committed
1394 1395 1396
   */
  public Action getChangeToParentDirectoryAction()
  {
1397 1398 1399
    if (changeToParentDirectoryAction == null)
      changeToParentDirectoryAction = new ChangeToParentDirectoryAction();
    return changeToParentDirectoryAction;
Tom Tromey committed
1400 1401 1402
  }

  /**
1403
   * Returns the action that handles events for the "approve" button.
Tom Tromey committed
1404
   *
1405
   * @return An instance of {@link ApproveSelectionAction}.
Tom Tromey committed
1406 1407 1408
   */
  public Action getApproveSelectionAction()
  {
1409 1410 1411
    if (approveSelectionAction == null)
      approveSelectionAction = new ApproveSelectionAction();
    return approveSelectionAction;
Tom Tromey committed
1412 1413 1414
  }

  /**
1415
   * Returns the action that handles events for the "cancel" button.
Tom Tromey committed
1416
   *
1417
   * @return An instance of {@link CancelSelectionAction}.
Tom Tromey committed
1418 1419 1420
   */
  public Action getCancelSelectionAction()
  {
1421 1422 1423
    if (cancelSelectionAction == null)
      cancelSelectionAction = new CancelSelectionAction();
    return cancelSelectionAction;
Tom Tromey committed
1424 1425 1426
  }

  /**
1427
   * Returns the update action (an instance of {@link UpdateAction}).
Tom Tromey committed
1428
   *
1429
   * @return An action. 
Tom Tromey committed
1430 1431 1432
   */
  public Action getUpdateAction()
  {
1433 1434 1435
    if (updateAction == null)
      updateAction = new UpdateAction();
    return updateAction;
Tom Tromey committed
1436 1437
  }
}