       1 /*
       2  * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
       3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       4  *
       5  * This code is free software; you can redistribute it and/or modify it
       6  * under the terms of the GNU General Public License version 2 only, as
       7  * published by the Free Software Foundation.  Oracle designates this
       8  * particular file as subject to the "Classpath" exception as provided
       9  * by Oracle in the LICENSE file that accompanied this code.
      10  *
      11  * This code is distributed in the hope that it will be useful, but WITHOUT
      12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14  * version 2 for more details (a copy is included in the LICENSE file that
      15  * accompanied this code).
      16  *
      17  * You should have received a copy of the GNU General Public License version
      18  * 2 along with this work; if not, write to the Free Software Foundation,
      19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
      20  *
      21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
      22  * or visit www.oracle.com if you need additional information or have any
      23  * questions.
      24  */
      25
      26 package com.sun.java.swing.plaf.windows;
      27
      28 import javax.swing.*;
      29 import javax.swing.border.*;
      30 import javax.swing.filechooser.*;
      31 import javax.swing.event.*;
      32 import javax.swing.plaf.*;
      33 import javax.swing.plaf.basic.*;
      34 import java.awt.*;
      35 import java.awt.event.*;
      36 import java.awt.image.BufferedImage;
      37 import java.beans.*;
      38 import java.io.File;
      39 import java.io.FileNotFoundException;
      40 import java.io.IOException;
      41 import java.util.*;
      42 import java.security.AccessController;
      43 import java.security.PrivilegedAction;
      44
      45 import sun.awt.shell.ShellFolder;
      46 import sun.swing.*;
      47
      48 import javax.accessibility.*;
      49
      50 /**
      51  * Windows {@literal L&F} implementation of a FileChooser.
      52  *
      53  * @author Jeff Dinkins
      54  */
      55 public class WindowsFileChooserUI extends BasicFileChooserUI {
      56
      57     // The following are private because the implementation of the
      58     // Windows FileChooser L&F is not complete yet.
      59
      60     private JPanel centerPanel;
      61
      62     private JLabel lookInLabel;
      63     private JComboBox<File> directoryComboBox;
      64     private DirectoryComboBoxModel directoryComboBoxModel;
      65     private ActionListener directoryComboBoxAction = new DirectoryComboBoxAction();
      66
      67     private FilterComboBoxModel filterComboBoxModel;
      68
      69     private JTextField filenameTextField;
      70     private FilePane filePane;
      71     private WindowsPlacesBar placesBar;
      72
      73     private JButton approveButton;
      74     private JButton cancelButton;
      75
      76     private JPanel buttonPanel;
      77     private JPanel bottomPanel;
      78
      79     private JComboBox<FileFilter> filterComboBox;
      80
      81     private static final Dimension hstrut10 = new Dimension(10, 1);
      82
      83     private static final Dimension vstrut4  = new Dimension(1, 4);
      84     private static final Dimension vstrut6  = new Dimension(1, 6);
      85     private static final Dimension vstrut8  = new Dimension(1, 8);
      86
      87     private static final Insets shrinkwrap = new Insets(0,0,0,0);
      88
      89     // Preferred and Minimum sizes for the dialog box
      90     private static int PREF_WIDTH = 425;
      91     private static int PREF_HEIGHT = 245;
      92     private static Dimension PREF_SIZE = new Dimension(PREF_WIDTH, PREF_HEIGHT);
      93
      94     private static int MIN_WIDTH = 425;
      95     private static int MIN_HEIGHT = 245;
      96
      97     private static int LIST_PREF_WIDTH = 444;
      98     private static int LIST_PREF_HEIGHT = 138;
      99     private static Dimension LIST_PREF_SIZE = new Dimension(LIST_PREF_WIDTH, LIST_PREF_HEIGHT);
     100
     101     // Labels, mnemonics, and tooltips (oh my!)
     102     private int    lookInLabelMnemonic = 0;
     103     private String lookInLabelText = null;
     104     private String saveInLabelText = null;
     105
     106     private int    fileNameLabelMnemonic = 0;
     107     private String fileNameLabelText = null;
     108     private int    folderNameLabelMnemonic = 0;
     109     private String folderNameLabelText = null;
     110
     111     private int    filesOfTypeLabelMnemonic = 0;
     112     private String filesOfTypeLabelText = null;
     113
     114     private String upFolderToolTipText = null;
     115     private String upFolderAccessibleName = null;
     116
     117     private String newFolderToolTipText = null;
     118     private String newFolderAccessibleName = null;
     119
     120     private String viewMenuButtonToolTipText = null;
     121     private String viewMenuButtonAccessibleName = null;
     122
     123     private BasicFileView fileView = new WindowsFileView();
     124
     125     private JLabel fileNameLabel;
     126
     127     private void populateFileNameLabel() {
     128         if (getFileChooser().getFileSelectionMode() == JFileChooser.DIRECTORIES_ONLY) {
     129             fileNameLabel.setText(folderNameLabelText);
     130             fileNameLabel.setDisplayedMnemonic(folderNameLabelMnemonic);
     131         } else {
     132             fileNameLabel.setText(fileNameLabelText);
     133             fileNameLabel.setDisplayedMnemonic(fileNameLabelMnemonic);
     134         }
     135     }
     136
     137     //
     138     // ComponentUI Interface Implementation methods
     139     //
     140     public static ComponentUI createUI(JComponent c) {
     141         return new WindowsFileChooserUI((JFileChooser) c);
     142     }
     143
     144     public WindowsFileChooserUI(JFileChooser filechooser) {
     145         super(filechooser);
     146     }
     147
     148     public void installUI(JComponent c) {
     149         super.installUI(c);
     150     }
     151
     152     public void uninstallComponents(JFileChooser fc) {
     153         fc.removeAll();
     154     }
     155
     156     private class WindowsFileChooserUIAccessor implements FilePane.FileChooserUIAccessor {
     157         public JFileChooser getFileChooser() {
     158             return WindowsFileChooserUI.this.getFileChooser();
     159         }
     160
     161         public BasicDirectoryModel getModel() {
     162             return WindowsFileChooserUI.this.getModel();
     163         }
     164
     165         public JPanel createList() {
     166             return WindowsFileChooserUI.this.createList(getFileChooser());
     167         }
     168
     169         public JPanel createDetailsView() {
     170             return WindowsFileChooserUI.this.createDetailsView(getFileChooser());
     171         }
     172
     173         public boolean isDirectorySelected() {
     174             return WindowsFileChooserUI.this.isDirectorySelected();
     175         }
     176
     177         public File getDirectory() {
     178             return WindowsFileChooserUI.this.getDirectory();
     179         }
     180
     181         public Action getChangeToParentDirectoryAction() {
     182             return WindowsFileChooserUI.this.getChangeToParentDirectoryAction();
     183         }
     184
     185         public Action getApproveSelectionAction() {
     186             return WindowsFileChooserUI.this.getApproveSelectionAction();
     187         }
     188
     189         public Action getNewFolderAction() {
     190             return WindowsFileChooserUI.this.getNewFolderAction();
     191         }
     192
     193         public MouseListener createDoubleClickListener(JList<?> list) {
     194             return WindowsFileChooserUI.this.createDoubleClickListener(getFileChooser(),
     195                                                                        list);
     196         }
     197
     198         public ListSelectionListener createListSelectionListener() {
     199             return WindowsFileChooserUI.this.createListSelectionListener(getFileChooser());
     200         }
     201     }
     202
     203     public void installComponents(JFileChooser fc) {
     204         filePane = new FilePane(new WindowsFileChooserUIAccessor());
     205         fc.addPropertyChangeListener(filePane);
     206
     207         FileSystemView fsv = fc.getFileSystemView();
     208
     209         fc.setBorder(new EmptyBorder(4, 10, 10, 10));
     210         fc.setLayout(new BorderLayout(8, 8));
     211
     212         updateUseShellFolder();
     213
     214         // ********************************* //
     215         // **** Construct the top panel **** //
     216         // ********************************* //
     217
     218         // Directory manipulation buttons
     219         JToolBar topPanel = new JToolBar();
     220         topPanel.setFloatable(false);
     221         topPanel.putClientProperty("JToolBar.isRollover", Boolean.TRUE);
     222
     223         // Add the top panel to the fileChooser
     224         fc.add(topPanel, BorderLayout.NORTH);
     225
     226         // ComboBox Label
     227         @SuppressWarnings("serial") // anonymous class
     228         JLabel tmp1 = new JLabel(lookInLabelText, JLabel.TRAILING) {
     229             public Dimension getPreferredSize() {
     230                 return getMinimumSize();
     231             }
     232
     233             public Dimension getMinimumSize() {
     234                 Dimension d = super.getPreferredSize();
     235                 if (placesBar != null) {
     236                     d.width = Math.max(d.width, placesBar.getWidth());
     237                 }
     238                 return d;
     239             }
     240         };
     241         lookInLabel = tmp1;
     242         lookInLabel.setDisplayedMnemonic(lookInLabelMnemonic);
     243         lookInLabel.setAlignmentX(JComponent.LEFT_ALIGNMENT);
     244         lookInLabel.setAlignmentY(JComponent.CENTER_ALIGNMENT);
     245         topPanel.add(lookInLabel);
     246         topPanel.add(Box.createRigidArea(new Dimension(8,0)));
     247
     248         // CurrentDir ComboBox
     249         @SuppressWarnings("serial") // anonymous class
     250         JComboBox<File> tmp2 = new JComboBox<File>() {
     251             public Dimension getMinimumSize() {
     252                 Dimension d = super.getMinimumSize();
     253                 d.width = 60;
     254                 return d;
     255             }
     256
     257             public Dimension getPreferredSize() {
     258                 Dimension d = super.getPreferredSize();
     259                 // Must be small enough to not affect total width.
     260                 d.width = 150;
     261                 return d;
     262             }
     263         };
     264         directoryComboBox = tmp2;
     265         directoryComboBox.putClientProperty( "JComboBox.lightweightKeyboardNavigation", "Lightweight" );
     266         lookInLabel.setLabelFor(directoryComboBox);
     267         directoryComboBoxModel = createDirectoryComboBoxModel(fc);
     268         directoryComboBox.setModel(directoryComboBoxModel);
     269         directoryComboBox.addActionListener(directoryComboBoxAction);
     270         directoryComboBox.setRenderer(createDirectoryComboBoxRenderer(fc));
     271         directoryComboBox.setAlignmentX(JComponent.LEFT_ALIGNMENT);
     272         directoryComboBox.setAlignmentY(JComponent.CENTER_ALIGNMENT);
     273         directoryComboBox.setMaximumRowCount(8);
     274
     275         topPanel.add(directoryComboBox);
     276         topPanel.add(Box.createRigidArea(hstrut10));
     277
     278         // Up Button
     279         JButton upFolderButton = createToolButton(getChangeToParentDirectoryAction(), upFolderIcon,
     280             upFolderToolTipText, upFolderAccessibleName);
     281         topPanel.add(upFolderButton);
     282
     283         // New Directory Button
     284         if (!UIManager.getBoolean("FileChooser.readOnly")) {
     285             JButton newFolderButton = createToolButton(filePane.getNewFolderAction(), newFolderIcon,
     286                 newFolderToolTipText, newFolderAccessibleName);
     287             topPanel.add(newFolderButton);
     288         }
     289
     290         // View button group
     291         ButtonGroup viewButtonGroup = new ButtonGroup();
     292
     293         // Popup Menu
     294         final JPopupMenu viewTypePopupMenu = new JPopupMenu();
     295
     296         final JRadioButtonMenuItem listViewMenuItem = new JRadioButtonMenuItem(
     297                 filePane.getViewTypeAction(FilePane.VIEWTYPE_LIST));
     298         listViewMenuItem.setSelected(filePane.getViewType() == FilePane.VIEWTYPE_LIST);
     299         viewTypePopupMenu.add(listViewMenuItem);
     300         viewButtonGroup.add(listViewMenuItem);
     301
     302         final JRadioButtonMenuItem detailsViewMenuItem = new JRadioButtonMenuItem(
     303                 filePane.getViewTypeAction(FilePane.VIEWTYPE_DETAILS));
     304         detailsViewMenuItem.setSelected(filePane.getViewType() == FilePane.VIEWTYPE_DETAILS);
     305         viewTypePopupMenu.add(detailsViewMenuItem);
     306         viewButtonGroup.add(detailsViewMenuItem);
     307
     308         // Create icon for viewMenuButton
     309         BufferedImage image = new BufferedImage(viewMenuIcon.getIconWidth() + 7, viewMenuIcon.getIconHeight(),
     310                 BufferedImage.TYPE_INT_ARGB);
     311         Graphics graphics = image.getGraphics();
     312         viewMenuIcon.paintIcon(filePane, graphics, 0, 0);
     313         int x = image.getWidth() - 5;
     314         int y = image.getHeight() / 2 - 1;
     315         graphics.setColor(Color.BLACK);
     316         graphics.fillPolygon(new int[]{x, x + 5, x + 2}, new int[]{y, y, y + 3}, 3);
     317
     318         // Details Button
     319         final JButton viewMenuButton = createToolButton(null, new ImageIcon(image), viewMenuButtonToolTipText,
     320                 viewMenuButtonAccessibleName);
     321
     322         viewMenuButton.addMouseListener(new MouseAdapter() {
     323             public void mousePressed(MouseEvent e) {
     324                 if (SwingUtilities.isLeftMouseButton(e) && !viewMenuButton.isSelected()) {
     325                     viewMenuButton.setSelected(true);
     326
     327                     viewTypePopupMenu.show(viewMenuButton, 0, viewMenuButton.getHeight());
     328                 }
     329             }
     330         });
     331         viewMenuButton.addKeyListener(new KeyAdapter() {
     332             public void keyPressed(KeyEvent e) {
     333                 // Forbid keyboard actions if the button is not in rollover state
     334                 if (e.getKeyCode() == KeyEvent.VK_SPACE && viewMenuButton.getModel().isRollover()) {
     335                     viewMenuButton.setSelected(true);
     336
     337                     viewTypePopupMenu.show(viewMenuButton, 0, viewMenuButton.getHeight());
     338                 }
     339             }
     340         });
     341         viewTypePopupMenu.addPopupMenuListener(new PopupMenuListener() {
     342             public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
     343             }
     344
     345             public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
     346                 SwingUtilities.invokeLater(new Runnable() {
     347                     public void run() {
     348                         viewMenuButton.setSelected(false);
     349                     }
     350                 });
     351             }
     352
     353             public void popupMenuCanceled(PopupMenuEvent e) {
     354             }
     355         });
     356
     357         topPanel.add(viewMenuButton);
     358
     359         topPanel.add(Box.createRigidArea(new Dimension(80, 0)));
     360
     361         filePane.addPropertyChangeListener(new PropertyChangeListener() {
     362             public void propertyChange(PropertyChangeEvent e) {
     363                 if ("viewType".equals(e.getPropertyName())) {
     364                     switch (filePane.getViewType()) {
     365                         case FilePane.VIEWTYPE_LIST:
     366                             listViewMenuItem.setSelected(true);
     367                             break;
     368
     369                         case FilePane.VIEWTYPE_DETAILS:
     370                             detailsViewMenuItem.setSelected(true);
     371                             break;
     372                     }
     373                 }
     374             }
     375         });
     376
     377         // ************************************** //
     378         // ******* Add the directory pane ******* //
     379         // ************************************** //
     380         centerPanel = new JPanel(new BorderLayout());
     381         centerPanel.add(getAccessoryPanel(), BorderLayout.AFTER_LINE_ENDS);
     382         JComponent accessory = fc.getAccessory();
     383         if(accessory != null) {
     384             getAccessoryPanel().add(accessory);
     385         }
     386         filePane.setPreferredSize(LIST_PREF_SIZE);
     387         centerPanel.add(filePane, BorderLayout.CENTER);
     388         fc.add(centerPanel, BorderLayout.CENTER);
     389
     390         // ********************************** //
     391         // **** Construct the bottom panel ** //
     392         // ********************************** //
     393         getBottomPanel().setLayout(new BoxLayout(getBottomPanel(), BoxLayout.LINE_AXIS));
     394
     395         // Add the bottom panel to file chooser
     396         centerPanel.add(getBottomPanel(), BorderLayout.SOUTH);
     397
     398         // labels
     399         JPanel labelPanel = new JPanel();
     400         labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.PAGE_AXIS));
     401         labelPanel.add(Box.createRigidArea(vstrut4));
     402
     403         fileNameLabel = new JLabel();
     404         populateFileNameLabel();
     405         fileNameLabel.setAlignmentY(0);
     406         labelPanel.add(fileNameLabel);
     407
     408         labelPanel.add(Box.createRigidArea(new Dimension(1,12)));
     409
     410         JLabel ftl = new JLabel(filesOfTypeLabelText);
     411         ftl.setDisplayedMnemonic(filesOfTypeLabelMnemonic);
     412         labelPanel.add(ftl);
     413
     414         getBottomPanel().add(labelPanel);
     415         getBottomPanel().add(Box.createRigidArea(new Dimension(15, 0)));
     416
     417         // file entry and filters
     418         JPanel fileAndFilterPanel = new JPanel();
     419         fileAndFilterPanel.add(Box.createRigidArea(vstrut8));
     420         fileAndFilterPanel.setLayout(new BoxLayout(fileAndFilterPanel, BoxLayout.Y_AXIS));
     421
     422         @SuppressWarnings("serial") // anonymous class
     423         JTextField tmp3 = new JTextField(35) {
     424             public Dimension getMaximumSize() {
     425                 return new Dimension(Short.MAX_VALUE, super.getPreferredSize().height);
     426             }
     427         };
     428         filenameTextField = tmp3;
     429
     430         fileNameLabel.setLabelFor(filenameTextField);
     431         filenameTextField.addFocusListener(
     432             new FocusAdapter() {
     433                 public void focusGained(FocusEvent e) {
     434                     if (!getFileChooser().isMultiSelectionEnabled()) {
     435                         filePane.clearSelection();
     436                     }
     437                 }
     438             }
     439         );
     440
     441         if (fc.isMultiSelectionEnabled()) {
     442             setFileName(fileNameString(fc.getSelectedFiles()));
     443         } else {
     444             setFileName(fileNameString(fc.getSelectedFile()));
     445         }
     446
     447         fileAndFilterPanel.add(filenameTextField);
     448         fileAndFilterPanel.add(Box.createRigidArea(vstrut8));
     449
     450         filterComboBoxModel = createFilterComboBoxModel();
     451         fc.addPropertyChangeListener(filterComboBoxModel);
     452         filterComboBox = new JComboBox<FileFilter>(filterComboBoxModel);
     453         ftl.setLabelFor(filterComboBox);
     454         filterComboBox.setRenderer(createFilterComboBoxRenderer());
     455         fileAndFilterPanel.add(filterComboBox);
     456
     457         getBottomPanel().add(fileAndFilterPanel);
     458         getBottomPanel().add(Box.createRigidArea(new Dimension(30, 0)));
     459
     460         // buttons
     461         getButtonPanel().setLayout(new BoxLayout(getButtonPanel(), BoxLayout.Y_AXIS));
     462
     463         @SuppressWarnings("serial") // anonymous class
     464         JButton tmp4 = new JButton(getApproveButtonText(fc)) {
     465             public Dimension getMaximumSize() {
     466                 return approveButton.getPreferredSize().width > cancelButton.getPreferredSize().width ?
     467                        approveButton.getPreferredSize() : cancelButton.getPreferredSize();
     468             }
     469         };
     470         approveButton = tmp4;
     471         Insets buttonMargin = approveButton.getMargin();
     472         buttonMargin = new InsetsUIResource(buttonMargin.top,    buttonMargin.left  + 5,
     473                                             buttonMargin.bottom, buttonMargin.right + 5);
     474         approveButton.setMargin(buttonMargin);
     475         approveButton.setMnemonic(getApproveButtonMnemonic(fc));
     476         approveButton.addActionListener(getApproveSelectionAction());
     477         approveButton.setToolTipText(getApproveButtonToolTipText(fc));
     478         getButtonPanel().add(Box.createRigidArea(vstrut6));
     479         getButtonPanel().add(approveButton);
     480         getButtonPanel().add(Box.createRigidArea(vstrut4));
     481
     482         @SuppressWarnings("serial") // anonymous class
     483         JButton tmp5 = new JButton(cancelButtonText) {
     484             public Dimension getMaximumSize() {
     485                 return approveButton.getPreferredSize().width > cancelButton.getPreferredSize().width ?
     486                        approveButton.getPreferredSize() : cancelButton.getPreferredSize();
     487             }
     488         };
     489         cancelButton = tmp5;
     490         cancelButton.setMargin(buttonMargin);
     491         cancelButton.setToolTipText(cancelButtonToolTipText);
     492         cancelButton.addActionListener(getCancelSelectionAction());
     493         getButtonPanel().add(cancelButton);
     494
     495         if(fc.getControlButtonsAreShown()) {
     496             addControlButtons();
     497         }
     498     }
     499
     500     private void updateUseShellFolder() {
     501         // Decide whether to use the ShellFolder class to populate shortcut
     502         // panel and combobox.
     503         JFileChooser fc = getFileChooser();
     504
     505         if (FilePane.usesShellFolder(fc)) {
     506             if (placesBar == null && !UIManager.getBoolean("FileChooser.noPlacesBar")) {
     507                 placesBar = new WindowsPlacesBar(fc, XPStyle.getXP() != null);
     508                 fc.add(placesBar, BorderLayout.BEFORE_LINE_BEGINS);
     509                 fc.addPropertyChangeListener(placesBar);
     510             }
     511         } else {
     512             if (placesBar != null) {
     513                 fc.remove(placesBar);
     514                 fc.removePropertyChangeListener(placesBar);
     515                 placesBar = null;
     516             }
     517         }
     518     }
     519
     520     protected JPanel getButtonPanel() {
     521         if(buttonPanel == null) {
     522             buttonPanel = new JPanel();
     523         }
     524         return buttonPanel;
     525     }
     526
     527     protected JPanel getBottomPanel() {
     528         if(bottomPanel == null) {
     529             bottomPanel = new JPanel();
     530         }
     531         return bottomPanel;
     532     }
     533
     534     protected void installStrings(JFileChooser fc) {
     535         super.installStrings(fc);
     536
     537         Locale l = fc.getLocale();
     538
     539         lookInLabelMnemonic = getMnemonic("FileChooser.lookInLabelMnemonic", l);
     540         lookInLabelText = UIManager.getString("FileChooser.lookInLabelText",l);
     541         saveInLabelText = UIManager.getString("FileChooser.saveInLabelText",l);
     542
     543         fileNameLabelMnemonic = getMnemonic("FileChooser.fileNameLabelMnemonic", l);
     544         fileNameLabelText = UIManager.getString("FileChooser.fileNameLabelText",l);
     545         folderNameLabelMnemonic = getMnemonic("FileChooser.folderNameLabelMnemonic", l);
     546         folderNameLabelText = UIManager.getString("FileChooser.folderNameLabelText",l);
     547
     548         filesOfTypeLabelMnemonic = getMnemonic("FileChooser.filesOfTypeLabelMnemonic", l);
     549         filesOfTypeLabelText = UIManager.getString("FileChooser.filesOfTypeLabelText",l);
     550
     551         upFolderToolTipText =  UIManager.getString("FileChooser.upFolderToolTipText",l);
     552         upFolderAccessibleName = UIManager.getString("FileChooser.upFolderAccessibleName",l);
     553
     554         newFolderToolTipText = UIManager.getString("FileChooser.newFolderToolTipText",l);
     555         newFolderAccessibleName = UIManager.getString("FileChooser.newFolderAccessibleName",l);
     556
     557         viewMenuButtonToolTipText = UIManager.getString("FileChooser.viewMenuButtonToolTipText",l);
     558         viewMenuButtonAccessibleName = UIManager.getString("FileChooser.viewMenuButtonAccessibleName",l);
     559     }
     560
     561     private Integer getMnemonic(String key, Locale l) {
     562         return SwingUtilities2.getUIDefaultsInt(key, l);
     563     }
     564
     565     protected void installListeners(JFileChooser fc) {
     566         super.installListeners(fc);
     567         ActionMap actionMap = getActionMap();
     568         SwingUtilities.replaceUIActionMap(fc, actionMap);
     569     }
     570
     571     protected ActionMap getActionMap() {
     572         return createActionMap();
     573     }
     574
     575     protected ActionMap createActionMap() {
     576         ActionMap map = new ActionMapUIResource();
     577         FilePane.addActionsToMap(map, filePane.getActions());
     578         return map;
     579     }
     580
     581     protected JPanel createList(JFileChooser fc) {
     582         return filePane.createList();
     583     }
     584
     585     protected JPanel createDetailsView(JFileChooser fc) {
     586         return filePane.createDetailsView();
     587     }
     588
     589     /**
     590      * Creates a selection listener for the list of files and directories.
     591      *
     592      * @param fc a <code>JFileChooser</code>
     593      * @return a <code>ListSelectionListener</code>
     594      */
     595     public ListSelectionListener createListSelectionListener(JFileChooser fc) {
     596         return super.createListSelectionListener(fc);
     597     }
     598
     599     // Obsolete class, not used in this version.
     600     @SuppressWarnings("serial")
     601     protected class WindowsNewFolderAction extends NewFolderAction {
     602     }
     603
     604     // Obsolete class, not used in this version.
     605     protected class SingleClickListener extends MouseAdapter {
     606     }
     607
     608     // Obsolete class, not used in this version.
     609     @SuppressWarnings("serial") // Superclass is not serializable across versions
     610     protected class FileRenderer extends DefaultListCellRenderer  {
     611     }
     612
     613     public void uninstallUI(JComponent c) {
     614         // Remove listeners
     615         c.removePropertyChangeListener(filterComboBoxModel);
     616         c.removePropertyChangeListener(filePane);
     617         if (placesBar != null) {
     618             c.removePropertyChangeListener(placesBar);
     619         }
     620         cancelButton.removeActionListener(getCancelSelectionAction());
     621         approveButton.removeActionListener(getApproveSelectionAction());
     622         filenameTextField.removeActionListener(getApproveSelectionAction());
     623
     624         if (filePane != null) {
     625             filePane.uninstallUI();
     626             filePane = null;
     627         }
     628
     629         super.uninstallUI(c);
     630     }
     631
     632     /**
     633      * Returns the preferred size of the specified
     634      * <code>JFileChooser</code>.
     635      * The preferred size is at least as large,
     636      * in both height and width,
     637      * as the preferred size recommended
     638      * by the file chooser's layout manager.
     639      *
     640      * @param c  a <code>JFileChooser</code>
     641      * @return   a <code>Dimension</code> specifying the preferred
     642      *           width and height of the file chooser
     643      */
     644     @Override
     645     public Dimension getPreferredSize(JComponent c) {
     646         int prefWidth = PREF_SIZE.width;
     647         Dimension d = c.getLayout().preferredLayoutSize(c);
     648         if (d != null) {
     649             return new Dimension(d.width < prefWidth ? prefWidth : d.width,
     650                                  d.height < PREF_SIZE.height ? PREF_SIZE.height : d.height);
     651         } else {
     652             return new Dimension(prefWidth, PREF_SIZE.height);
     653         }
     654     }
     655
     656     /**
     657      * Returns the minimum size of the <code>JFileChooser</code>.
     658      *
     659      * @param c  a <code>JFileChooser</code>
     660      * @return   a <code>Dimension</code> specifying the minimum
     661      *           width and height of the file chooser
     662      */
     663     @Override
     664     public Dimension getMinimumSize(JComponent c) {
     665         return new Dimension(MIN_WIDTH, MIN_HEIGHT);
     666     }
     667
     668     /**
     669      * Returns the maximum size of the <code>JFileChooser</code>.
     670      *
     671      * @param c  a <code>JFileChooser</code>
     672      * @return   a <code>Dimension</code> specifying the maximum
     673      *           width and height of the file chooser
     674      */
     675     @Override
     676     public Dimension getMaximumSize(JComponent c) {
     677         return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
     678     }
     679
     680     private String fileNameString(File file) {
     681         if (file == null) {
     682             return null;
     683         } else {
     684             JFileChooser fc = getFileChooser();
     685             if ((fc.isDirectorySelectionEnabled() && !fc.isFileSelectionEnabled()) ||
     686                 (fc.isDirectorySelectionEnabled() && fc.isFileSelectionEnabled() && fc.getFileSystemView().isFileSystemRoot(file))){
     687                 return file.getPath();
     688             } else {
     689                 return file.getName();
     690             }
     691         }
     692     }
     693
     694     private String fileNameString(File[] files) {
     695         StringBuilder buf = new StringBuilder();
     696         for (int i = 0; files != null && i < files.length; i++) {
     697             if (i > 0) {
     698                 buf.append(" ");
     699             }
     700             if (files.length > 1) {
     701                 buf.append("\"");
     702             }
     703             buf.append(fileNameString(files[i]));
     704             if (files.length > 1) {
     705                 buf.append("\"");
     706             }
     707         }
     708         return buf.toString();
     709     }
     710
     711     /* The following methods are used by the PropertyChange Listener */
     712
     713     private void doSelectedFileChanged(PropertyChangeEvent e) {
     714         File f = (File) e.getNewValue();
     715         JFileChooser fc = getFileChooser();
     716         if (f != null
     717             && ((fc.isFileSelectionEnabled() && !f.isDirectory())
     718                 || (f.isDirectory() && fc.isDirectorySelectionEnabled()))) {
     719
     720             setFileName(fileNameString(f));
     721         }
     722     }
     723
     724     private void doSelectedFilesChanged(PropertyChangeEvent e) {
     725         File[] files = (File[]) e.getNewValue();
     726         JFileChooser fc = getFileChooser();
     727         if (files != null
     728             && files.length > 0
     729             && (files.length > 1 || fc.isDirectorySelectionEnabled() || !files[0].isDirectory())) {
     730             setFileName(fileNameString(files));
     731         }
     732     }
     733
     734     private void doDirectoryChanged(PropertyChangeEvent e) {
     735         JFileChooser fc = getFileChooser();
     736         FileSystemView fsv = fc.getFileSystemView();
     737
     738         clearIconCache();
     739         File currentDirectory = fc.getCurrentDirectory();
     740         if(currentDirectory != null) {
     741             directoryComboBoxModel.addItem(currentDirectory);
     742
     743             if (fc.isDirectorySelectionEnabled() && !fc.isFileSelectionEnabled()) {
     744                 if (fsv.isFileSystem(currentDirectory)) {
     745                     setFileName(currentDirectory.getPath());
     746                 } else {
     747                     setFileName(null);
     748                 }
     749             }
     750         }
     751     }
     752
     753     private void doFilterChanged(PropertyChangeEvent e) {
     754         clearIconCache();
     755     }
     756
     757     private void doFileSelectionModeChanged(PropertyChangeEvent e) {
     758         if (fileNameLabel != null) {
     759             populateFileNameLabel();
     760         }
     761         clearIconCache();
     762
     763         JFileChooser fc = getFileChooser();
     764         File currentDirectory = fc.getCurrentDirectory();
     765         if (currentDirectory != null
     766             && fc.isDirectorySelectionEnabled()
     767             && !fc.isFileSelectionEnabled()
     768             && fc.getFileSystemView().isFileSystem(currentDirectory)) {
     769
     770             setFileName(currentDirectory.getPath());
     771         } else {
     772             setFileName(null);
     773         }
     774     }
     775
     776     private void doAccessoryChanged(PropertyChangeEvent e) {
     777         if(getAccessoryPanel() != null) {
     778             if(e.getOldValue() != null) {
     779                 getAccessoryPanel().remove((JComponent) e.getOldValue());
     780             }
     781             JComponent accessory = (JComponent) e.getNewValue();
     782             if(accessory != null) {
     783                 getAccessoryPanel().add(accessory, BorderLayout.CENTER);
     784             }
     785         }
     786     }
     787
     788     private void doApproveButtonTextChanged(PropertyChangeEvent e) {
     789         JFileChooser chooser = getFileChooser();
     790         approveButton.setText(getApproveButtonText(chooser));
     791         approveButton.setToolTipText(getApproveButtonToolTipText(chooser));
     792         approveButton.setMnemonic(getApproveButtonMnemonic(chooser));
     793     }
     794
     795     private void doDialogTypeChanged(PropertyChangeEvent e) {
     796         JFileChooser chooser = getFileChooser();
     797         approveButton.setText(getApproveButtonText(chooser));
     798         approveButton.setToolTipText(getApproveButtonToolTipText(chooser));
     799         approveButton.setMnemonic(getApproveButtonMnemonic(chooser));
     800         if (chooser.getDialogType() == JFileChooser.SAVE_DIALOG) {
     801             lookInLabel.setText(saveInLabelText);
     802         } else {
     803             lookInLabel.setText(lookInLabelText);
     804         }
     805     }
     806
     807     private void doApproveButtonMnemonicChanged(PropertyChangeEvent e) {
     808         approveButton.setMnemonic(getApproveButtonMnemonic(getFileChooser()));
     809     }
     810
     811     private void doControlButtonsChanged(PropertyChangeEvent e) {
     812         if(getFileChooser().getControlButtonsAreShown()) {
     813             addControlButtons();
     814         } else {
     815             removeControlButtons();
     816         }
     817     }
     818
     819     /*
     820      * Listen for filechooser property changes, such as
     821      * the selected file changing, or the type of the dialog changing.
     822      */
     823     public PropertyChangeListener createPropertyChangeListener(JFileChooser fc) {
     824         return new PropertyChangeListener() {
     825             public void propertyChange(PropertyChangeEvent e) {
     826                 String s = e.getPropertyName();
     827                 if(s.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) {
     828                     doSelectedFileChanged(e);
     829                 } else if (s.equals(JFileChooser.SELECTED_FILES_CHANGED_PROPERTY)) {
     830                     doSelectedFilesChanged(e);
     831                 } else if(s.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)) {
     832                     doDirectoryChanged(e);
     833                 } else if(s.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)) {
     834                     doFilterChanged(e);
     835                 } else if(s.equals(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY)) {
     836                     doFileSelectionModeChanged(e);
     837                 } else if(s.equals(JFileChooser.ACCESSORY_CHANGED_PROPERTY)) {
     838                     doAccessoryChanged(e);
     839                 } else if (s.equals(JFileChooser.APPROVE_BUTTON_TEXT_CHANGED_PROPERTY) ||
     840                            s.equals(JFileChooser.APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY)) {
     841                     doApproveButtonTextChanged(e);
     842                 } else if(s.equals(JFileChooser.DIALOG_TYPE_CHANGED_PROPERTY)) {
     843                     doDialogTypeChanged(e);
     844                 } else if(s.equals(JFileChooser.APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY)) {
     845                     doApproveButtonMnemonicChanged(e);
     846                 } else if(s.equals(JFileChooser.CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY)) {
     847                     doControlButtonsChanged(e);
     848                 } else if (s == "FileChooser.useShellFolder") {
     849                     updateUseShellFolder();
     850                     doDirectoryChanged(e);
     851                 } else if (s.equals("componentOrientation")) {
     852                     ComponentOrientation o = (ComponentOrientation)e.getNewValue();
     853                     JFileChooser cc = (JFileChooser)e.getSource();
     854                     if (o != e.getOldValue()) {
     855                         cc.applyComponentOrientation(o);
     856                     }
     857                 } else if (s.equals("ancestor")) {
     858                     if (e.getOldValue() == null && e.getNewValue() != null) {
     859                         // Ancestor was added, set initial focus
     860                         filenameTextField.selectAll();
     861                         filenameTextField.requestFocus();
     862                     }
     863                 }
     864             }
     865         };
     866     }
     867
     868
     869     protected void removeControlButtons() {
     870         getBottomPanel().remove(getButtonPanel());
     871     }
     872
     873     protected void addControlButtons() {
     874         getBottomPanel().add(getButtonPanel());
     875     }
     876
     877     public void ensureFileIsVisible(JFileChooser fc, File f) {
     878         filePane.ensureFileIsVisible(fc, f);
     879     }
     880
     881     public void rescanCurrentDirectory(JFileChooser fc) {
     882         filePane.rescanCurrentDirectory();
     883     }
     884
     885     public String getFileName() {
     886         if(filenameTextField != null) {
     887             return filenameTextField.getText();
     888         } else {
     889             return null;
     890         }
     891     }
     892
     893     public void setFileName(String filename) {
     894         if(filenameTextField != null) {
     895             filenameTextField.setText(filename);
     896         }
     897     }
     898
     899     /**
     900      * Property to remember whether a directory is currently selected in the UI.
     901      * This is normally called by the UI on a selection event.
     902      *
     903      * @param directorySelected if a directory is currently selected.
     904      * @since 1.4
     905      */
     906     protected void setDirectorySelected(boolean directorySelected) {
     907         super.setDirectorySelected(directorySelected);
     908         JFileChooser chooser = getFileChooser();
     909         if(directorySelected) {
     910             approveButton.setText(directoryOpenButtonText);
     911             approveButton.setToolTipText(directoryOpenButtonToolTipText);
     912             approveButton.setMnemonic(directoryOpenButtonMnemonic);
     913         } else {
     914             approveButton.setText(getApproveButtonText(chooser));
     915             approveButton.setToolTipText(getApproveButtonToolTipText(chooser));
     916             approveButton.setMnemonic(getApproveButtonMnemonic(chooser));
     917         }
     918     }
     919
     920     public String getDirectoryName() {
     921         // PENDING(jeff) - get the name from the directory combobox
     922         return null;
     923     }
     924
     925     public void setDirectoryName(String dirname) {
     926         // PENDING(jeff) - set the name in the directory combobox
     927     }
     928
     929     protected DirectoryComboBoxRenderer createDirectoryComboBoxRenderer(JFileChooser fc) {
     930         return new DirectoryComboBoxRenderer();
     931     }
     932
     933     @SuppressWarnings("serial") // anonymous class
     934     private static JButton createToolButton(Action a, Icon defaultIcon, String toolTipText, String accessibleName) {
     935         final JButton result = new JButton(a);
     936
     937         result.setText(null);
     938         result.setIcon(defaultIcon);
     939         result.setToolTipText(toolTipText);
     940         result.setRequestFocusEnabled(false);
     941         result.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, accessibleName);
     942         result.putClientProperty(WindowsLookAndFeel.HI_RES_DISABLED_ICON_CLIENT_KEY, Boolean.TRUE);
     943         result.setAlignmentX(JComponent.LEFT_ALIGNMENT);
     944         result.setAlignmentY(JComponent.CENTER_ALIGNMENT);
     945         result.setMargin(shrinkwrap);
     946         result.setFocusPainted(false);
     947
     948         result.setModel(new DefaultButtonModel() {
     949             public void setPressed(boolean b) {
     950                 // Forbid keyboard actions if the button is not in rollover state
     951                 if (!b || isRollover()) {
     952                     super.setPressed(b);
     953                 }
     954             }
     955
     956             public void setRollover(boolean b) {
     957                 if (b && !isRollover()) {
     958                     // Reset other buttons
     959                     for (Component component : result.getParent().getComponents()) {
     960                         if (component instanceof JButton && component != result) {
     961                             ((JButton) component).getModel().setRollover(false);
     962                         }
     963                     }
     964                 }
     965
     966                 super.setRollover(b);
     967             }
     968
     969             public void setSelected(boolean b) {
     970                 super.setSelected(b);
     971
     972                 if (b) {
     973                     stateMask |= PRESSED | ARMED;
     974                 } else {
     975                     stateMask &= ~(PRESSED | ARMED);
     976                 }
     977             }
     978         });
     979
     980         result.addFocusListener(new FocusAdapter() {
     981             public void focusGained(FocusEvent e) {
     982                 result.getModel().setRollover(true);
     983             }
     984
     985             public void focusLost(FocusEvent e) {
     986                 result.getModel().setRollover(false);
     987             }
     988         });
     989
     990         return result;
     991     }
     992
     993     //
     994     // Renderer for DirectoryComboBox
     995     //
     996     @SuppressWarnings("serial") // Superclass is not serializable across versions
     997     class DirectoryComboBoxRenderer extends DefaultListCellRenderer  {
     998         IndentIcon ii = new IndentIcon();
     999         public Component getListCellRendererComponent(JList<?> list, Object value,
    1000                                                       int index, boolean isSelected,
    1001                                                       boolean cellHasFocus) {
    1002
    1003             super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
    1004
    1005             if (value == null) {
    1006                 setText("");
    1007                 return this;
    1008             }
    1009             File directory = (File)value;
    1010             setText(getFileChooser().getName(directory));
    1011             Icon icon = getFileChooser().getIcon(directory);
    1012             ii.icon = icon;
    1013             ii.depth = directoryComboBoxModel.getDepth(index);
    1014             setIcon(ii);
    1015
    1016             return this;
    1017         }
    1018     }
    1019
    1020     static final int space = 10;
    1021     class IndentIcon implements Icon {
    1022
    1023         Icon icon = null;
    1024         int depth = 0;
    1025
    1026         public void paintIcon(Component c, Graphics g, int x, int y) {
    1027             if (c.getComponentOrientation().isLeftToRight()) {
    1028                 icon.paintIcon(c, g, x+depth*space, y);
    1029             } else {
    1030                 icon.paintIcon(c, g, x, y);
    1031             }
    1032         }
    1033
    1034         public int getIconWidth() {
    1035             return icon.getIconWidth() + depth*space;
    1036         }
    1037
    1038         public int getIconHeight() {
    1039             return icon.getIconHeight();
    1040         }
    1041
    1042     }
    1043
    1044     //
    1045     // DataModel for DirectoryComboxbox
    1046     //
    1047     protected DirectoryComboBoxModel createDirectoryComboBoxModel(JFileChooser fc) {
    1048         return new DirectoryComboBoxModel();
    1049     }
    1050
    1051     /**
    1052      * Data model for a type-face selection combo-box.
    1053      */
    1054     @SuppressWarnings("serial") // Superclass is not serializable across versions
    1055     protected class DirectoryComboBoxModel extends AbstractListModel<File> implements ComboBoxModel<File> {
    1056         Vector<File> directories = new Vector<File>();
    1057         int[] depths = null;
    1058         File selectedDirectory = null;
    1059         JFileChooser chooser = getFileChooser();
    1060         FileSystemView fsv = chooser.getFileSystemView();
    1061
    1062         public DirectoryComboBoxModel() {
    1063             // Add the current directory to the model, and make it the
    1064             // selectedDirectory
    1065             File dir = getFileChooser().getCurrentDirectory();
    1066             if(dir != null) {
    1067                 addItem(dir);
    1068             }
    1069         }
    1070
    1071         /**
    1072          * Adds the directory to the model and sets it to be selected,
    1073          * additionally clears out the previous selected directory and
    1074          * the paths leading up to it, if any.
    1075          */
    1076         private void addItem(File directory) {
    1077
    1078             if(directory == null) {
    1079                 return;
    1080             }
    1081
    1082             boolean useShellFolder = FilePane.usesShellFolder(chooser);
    1083
    1084             directories.clear();
    1085
    1086             File[] baseFolders = (useShellFolder)
    1087                     ? (File[]) ShellFolder.get("fileChooserComboBoxFolders")
    1088                     : fsv.getRoots();
    1089             directories.addAll(Arrays.asList(baseFolders));
    1090
    1091             // Get the canonical (full) path. This has the side
    1092             // benefit of removing extraneous chars from the path,
    1093             // for example /foo/bar/ becomes /foo/bar
    1094             File canonical;
    1095             try {
    1096                 canonical = directory.getCanonicalFile();
    1097             } catch (IOException e) {
    1098                 // Maybe drive is not ready. Can't abort here.
    1099                 canonical = directory;
    1100             }
    1101
    1102             // create File instances of each directory leading up to the top
    1103             try {
    1104                 File sf = useShellFolder ? ShellFolder.getShellFolder(canonical)
    1105                                          : canonical;
    1106                 File f = sf;
    1107                 Vector<File> path = new Vector<File>(10);
    1108                 do {
    1109                     path.addElement(f);
    1110                 } while ((f = f.getParentFile()) != null);
    1111
    1112                 int pathCount = path.size();
    1113                 // Insert chain at appropriate place in vector
    1114                 for (int i = 0; i < pathCount; i++) {
    1115                     f = path.get(i);
    1116                     if (directories.contains(f)) {
    1117                         int topIndex = directories.indexOf(f);
    1118                         for (int j = i-1; j >= 0; j--) {
    1119                             directories.insertElementAt(path.get(j), topIndex+i-j);
    1120                         }
    1121                         break;
    1122                     }
    1123                 }
    1124                 calculateDepths();
    1125                 setSelectedItem(sf);
    1126             } catch (FileNotFoundException ex) {
    1127                 calculateDepths();
    1128             }
    1129         }
    1130
    1131         private void calculateDepths() {
    1132             depths = new int[directories.size()];
    1133             for (int i = 0; i < depths.length; i++) {
    1134                 File dir = directories.get(i);
    1135                 File parent = dir.getParentFile();
    1136                 depths[i] = 0;
    1137                 if (parent != null) {
    1138                     for (int j = i-1; j >= 0; j--) {
    1139                         if (parent.equals(directories.get(j))) {
    1140                             depths[i] = depths[j] + 1;
    1141                             break;
    1142                         }
    1143                     }
    1144                 }
    1145             }
    1146         }
    1147
    1148         public int getDepth(int i) {
    1149             return (depths != null && i >= 0 && i < depths.length) ? depths[i] : 0;
    1150         }
    1151
    1152         public void setSelectedItem(File selectedDirectory) {
    1153             this.selectedDirectory = selectedDirectory;
    1154             fireContentsChanged(this, -1, -1);
    1155         }
    1156
    1157         public File getSelectedItem() {
    1158             return selectedDirectory;
    1159         }
    1160
    1161         public int getSize() {
    1162             return directories.size();
    1163         }
    1164
    1165         public File getElementAt(int index) {
    1166             return directories.elementAt(index);
    1167         }
    1168     }
    1169
    1170     //
    1171     // Renderer for Types ComboBox
    1172     //
    1173     protected FilterComboBoxRenderer createFilterComboBoxRenderer() {
    1174         return new FilterComboBoxRenderer();
    1175     }
    1176
    1177     /**
    1178      * Render different type sizes and styles.
    1179      */
    1180     @SuppressWarnings("serial") // Superclass is not serializable across versions
    1181     public class FilterComboBoxRenderer extends DefaultListCellRenderer {
    1182         public Component getListCellRendererComponent(JList<?> list,
    1183             Object value, int index, boolean isSelected,
    1184             boolean cellHasFocus) {
    1185
    1186             super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
    1187
    1188             if (value != null && value instanceof FileFilter) {
    1189                 setText(((FileFilter)value).getDescription());
    1190             }
    1191
    1192             return this;
    1193         }
    1194     }
    1195
    1196     //
    1197     // DataModel for Types Comboxbox
    1198     //
    1199     protected FilterComboBoxModel createFilterComboBoxModel() {
    1200         return new FilterComboBoxModel();
    1201     }
    1202
    1203     /**
    1204      * Data model for a type-face selection combo-box.
    1205      */
    1206     @SuppressWarnings("serial") // Superclass is not serializable across versions
    1207     protected class FilterComboBoxModel extends AbstractListModel<FileFilter> implements ComboBoxModel<FileFilter>,
    1208             PropertyChangeListener {
    1209         protected FileFilter[] filters;
    1210         protected FilterComboBoxModel() {
    1211             super();
    1212             filters = getFileChooser().getChoosableFileFilters();
    1213         }
    1214
    1215         public void propertyChange(PropertyChangeEvent e) {
    1216             String prop = e.getPropertyName();
    1217             if(prop == JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY) {
    1218                 filters = (FileFilter[]) e.getNewValue();
    1219                 fireContentsChanged(this, -1, -1);
    1220             } else if (prop == JFileChooser.FILE_FILTER_CHANGED_PROPERTY) {
    1221                 fireContentsChanged(this, -1, -1);
    1222             }
    1223         }
    1224
    1225         public void setSelectedItem(FileFilter filter) {
    1226             if(filter != null) {
    1227                 getFileChooser().setFileFilter(filter);
    1228                 fireContentsChanged(this, -1, -1);
    1229             }
    1230         }
    1231
    1232         public FileFilter getSelectedItem() {
    1233             // Ensure that the current filter is in the list.
    1234             // NOTE: we shouldnt' have to do this, since JFileChooser adds
    1235             // the filter to the choosable filters list when the filter
    1236             // is set. Lets be paranoid just in case someone overrides
    1237             // setFileFilter in JFileChooser.
    1238             FileFilter currentFilter = getFileChooser().getFileFilter();
    1239             boolean found = false;
    1240             if(currentFilter != null) {
    1241                 for (FileFilter filter : filters) {
    1242                     if (filter == currentFilter) {
    1243                         found = true;
    1244                     }
    1245                 }
    1246                 if(found == false) {
    1247                     getFileChooser().addChoosableFileFilter(currentFilter);
    1248                 }
    1249             }
    1250             return getFileChooser().getFileFilter();
    1251         }
    1252
    1253         public int getSize() {
    1254             if(filters != null) {
    1255                 return filters.length;
    1256             } else {
    1257                 return 0;
    1258             }
    1259         }
    1260
    1261         public FileFilter getElementAt(int index) {
    1262             if(index > getSize() - 1) {
    1263                 // This shouldn't happen. Try to recover gracefully.
    1264                 return getFileChooser().getFileFilter();
    1265             }
    1266             if(filters != null) {
    1267                 return filters[index];
    1268             } else {
    1269                 return null;
    1270             }
    1271         }
    1272     }
    1273
    1274     public void valueChanged(ListSelectionEvent e) {
    1275         JFileChooser fc = getFileChooser();
    1276         File f = fc.getSelectedFile();
    1277         if (!e.getValueIsAdjusting() && f != null && !getFileChooser().isTraversable(f)) {
    1278             setFileName(fileNameString(f));
    1279         }
    1280     }
    1281
    1282     /**
    1283      * Acts when DirectoryComboBox has changed the selected item.
    1284      */
    1285     protected class DirectoryComboBoxAction implements ActionListener {
    1286
    1287
    1288
    1289
    1290         public void actionPerformed(ActionEvent e) {
    1291             File f = directoryComboBox.getSelectedItem();
    1292             getFileChooser().setCurrentDirectory(f);
    1293         }
    1294     }
    1295
    1296     protected JButton getApproveButton(JFileChooser fc) {
    1297         return approveButton;
    1298     }
    1299
    1300     public FileView getFileView(JFileChooser fc) {
    1301         return fileView;
    1302     }
    1303
    1304     // ***********************
    1305     // * FileView operations *
    1306     // ***********************
    1307     protected class WindowsFileView extends BasicFileView {
    1308         /* FileView type descriptions */
    1309
    1310         public Icon getIcon(File f) {
    1311             Icon icon = getCachedIcon(f);
    1312             if (icon != null) {
    1313                 return icon;
    1314             }
    1315             if (f != null) {
    1316                 icon = getFileChooser().getFileSystemView().getSystemIcon(f);
    1317             }
    1318             if (icon == null) {
    1319                 icon = super.getIcon(f);
    1320             }
    1321             cacheIcon(f, icon);
    1322             return icon;
    1323         }
    1324     }
    1325 }