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