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