    rev 48858 : Work in progress for JDK-6303622
    Use generic in Swing components like JComboBox
    1. Added generic return type and parameter type for JComboBox.
    2. Modified JList related classes as well.
    3. Reverted the changes made to "getSelectedValues" as suggested by Joe.
    4. Modified files that were failing on Linux and Mac as well.

       1 /*
       2  * Copyright (c) 2003, 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 package sun.swing.plaf.synth;
      26
      27 import java.awt.*;
      28 import java.awt.event.*;
      29 import java.beans.*;
      30 import java.io.*;
      31 import java.util.*;
      32 import java.security.AccessController;
      33 import java.security.PrivilegedAction;
      34
      35 import javax.swing.*;
      36 import javax.swing.event.*;
      37 import javax.swing.filechooser.*;
      38 import javax.swing.filechooser.FileFilter;
      39 import javax.swing.plaf.basic.*;
      40 import javax.swing.plaf.synth.*;
      41 import javax.swing.plaf.ActionMapUIResource;
      42
      43 import sun.awt.shell.ShellFolder;
      44 import sun.swing.*;
      45
      46 /**
      47  * Synth FileChooserUI implementation.
      48  * <p>
      49  * Note that the classes in the com.sun.java.swing.plaf.synth
      50  * package are not
      51  * part of the core Java APIs. They are a part of Sun's JDK and JRE
      52  * distributions. Although other licensees may choose to distribute
      53  * these classes, developers cannot depend on their availability in
      54  * non-Sun implementations. Additionally this API may change in
      55  * incompatible ways between releases. While this class is public, it
      56  * shoud be considered an implementation detail, and subject to change.
      57  *
      58  * @author Leif Samuelsson
      59  * @author Jeff Dinkins
      60  */
      61 public class SynthFileChooserUIImpl extends SynthFileChooserUI {
      62     private JLabel lookInLabel;
      63     private JComboBox<File> directoryComboBox;
      64     private DirectoryComboBoxModel directoryComboBoxModel;
      65     private Action directoryComboBoxAction = new DirectoryComboBoxAction();
      66
      67     private FilterComboBoxModel filterComboBoxModel;
      68
      69     private JTextField fileNameTextField;
      70
      71     private FilePane filePane;
      72     private JToggleButton listViewButton;
      73     private JToggleButton detailsViewButton;
      74
      75     private boolean readOnly;
      76
      77     private JPanel buttonPanel;
      78     private JPanel bottomPanel;
      79
      80     private JComboBox<FileFilter> filterComboBox;
      81
      82     private static final Dimension hstrut5 = new Dimension(5, 1);
      83
      84     private static final Insets shrinkwrap = new Insets(0,0,0,0);
      85
      86     // Preferred and Minimum sizes for the dialog box
      87     private static Dimension LIST_PREF_SIZE = new Dimension(405, 135);
      88
      89     // Labels, mnemonics, and tooltips (oh my!)
      90     private int    lookInLabelMnemonic = 0;
      91     private String lookInLabelText = null;
      92     private String saveInLabelText = null;
      93
      94     private int    fileNameLabelMnemonic = 0;
      95     private String fileNameLabelText = null;
      96     private int    folderNameLabelMnemonic = 0;
      97     private String folderNameLabelText = null;
      98
      99     private int    filesOfTypeLabelMnemonic = 0;
     100     private String filesOfTypeLabelText = null;
     101
     102     private String upFolderToolTipText = null;
     103     private String upFolderAccessibleName = null;
     104
     105     private String homeFolderToolTipText = null;
     106     private String homeFolderAccessibleName = null;
     107
     108     private String newFolderToolTipText = null;
     109     private String newFolderAccessibleName = null;
     110
     111     private String listViewButtonToolTipText = null;
     112     private String listViewButtonAccessibleName = null;
     113
     114     private String detailsViewButtonToolTipText = null;
     115     private String detailsViewButtonAccessibleName = null;
     116
     117     private AlignedLabel fileNameLabel;
     118     private final PropertyChangeListener modeListener = new PropertyChangeListener() {
     119         public void propertyChange(PropertyChangeEvent event) {
     120             if (fileNameLabel != null) {
     121                 populateFileNameLabel();
     122             }
     123         }
     124     };
     125
     126     private void populateFileNameLabel() {
     127         if (getFileChooser().getFileSelectionMode() == JFileChooser.DIRECTORIES_ONLY) {
     128             fileNameLabel.setText(folderNameLabelText);
     129             fileNameLabel.setDisplayedMnemonic(folderNameLabelMnemonic);
     130         } else {
     131             fileNameLabel.setText(fileNameLabelText);
     132             fileNameLabel.setDisplayedMnemonic(fileNameLabelMnemonic);
     133         }
     134     }
     135
     136     public SynthFileChooserUIImpl(JFileChooser b) {
     137         super(b);
     138     }
     139
     140
     141     private class SynthFileChooserUIAccessor implements FilePane.FileChooserUIAccessor {
     142         public JFileChooser getFileChooser() {
     143             return SynthFileChooserUIImpl.this.getFileChooser();
     144         }
     145
     146         public BasicDirectoryModel getModel() {
     147             return SynthFileChooserUIImpl.this.getModel();
     148         }
     149
     150         public JPanel createList() {
     151             return null;
     152         }
     153
     154         public JPanel createDetailsView() {
     155             return null;
     156         }
     157
     158         public boolean isDirectorySelected() {
     159             return SynthFileChooserUIImpl.this.isDirectorySelected();
     160         }
     161
     162         public File getDirectory() {
     163             return SynthFileChooserUIImpl.this.getDirectory();
     164         }
     165
     166         public Action getChangeToParentDirectoryAction() {
     167             return SynthFileChooserUIImpl.this.getChangeToParentDirectoryAction();
     168         }
     169
     170         public Action getApproveSelectionAction() {
     171             return SynthFileChooserUIImpl.this.getApproveSelectionAction();
     172         }
     173
     174         public Action getNewFolderAction() {
     175             return SynthFileChooserUIImpl.this.getNewFolderAction();
     176         }
     177
     178         public MouseListener createDoubleClickListener(JList<?> list) {
     179             return SynthFileChooserUIImpl.this.createDoubleClickListener(getFileChooser(),
     180                                                                      list);
     181         }
     182
     183         public ListSelectionListener createListSelectionListener() {
     184             return SynthFileChooserUIImpl.this.createListSelectionListener(getFileChooser());
     185         }
     186     }
     187
     188     protected void installDefaults(JFileChooser fc) {
     189         super.installDefaults(fc);
     190         readOnly = UIManager.getBoolean("FileChooser.readOnly");
     191     }
     192
     193     @SuppressWarnings("serial") // anonymous classes inside
     194     public void installComponents(JFileChooser fc) {
     195         super.installComponents(fc);
     196
     197         SynthContext context = getContext(fc, ENABLED);
     198
     199         fc.setLayout(new BorderLayout(0, 11));
     200
     201         // ********************************* //
     202         // **** Construct the top panel **** //
     203         // ********************************* //
     204
     205         // Directory manipulation buttons
     206         JPanel topPanel = new JPanel(new BorderLayout(11, 0));
     207     JPanel topButtonPanel = new JPanel();
     208     topButtonPanel.setLayout(new BoxLayout(topButtonPanel, BoxLayout.LINE_AXIS));
     209     topPanel.add(topButtonPanel, BorderLayout.AFTER_LINE_ENDS);
     210
     211         // Add the top panel to the fileChooser
     212         fc.add(topPanel, BorderLayout.NORTH);
     213
     214         // ComboBox Label
     215         lookInLabel = new JLabel(lookInLabelText);
     216         lookInLabel.setDisplayedMnemonic(lookInLabelMnemonic);
     217         topPanel.add(lookInLabel, BorderLayout.BEFORE_LINE_BEGINS);
     218
     219         // CurrentDir ComboBox
     220         directoryComboBox = new JComboBox<File>();
     221         directoryComboBox.getAccessibleContext().setAccessibleDescription(lookInLabelText);
     222         directoryComboBox.putClientProperty( "JComboBox.isTableCellEditor", Boolean.TRUE );
     223         lookInLabel.setLabelFor(directoryComboBox);
     224         directoryComboBoxModel = createDirectoryComboBoxModel(fc);
     225         directoryComboBox.setModel(directoryComboBoxModel);
     226         directoryComboBox.addActionListener(directoryComboBoxAction);
     227         directoryComboBox.setRenderer(createDirectoryComboBoxRenderer(fc));
     228         directoryComboBox.setAlignmentX(JComponent.LEFT_ALIGNMENT);
     229         directoryComboBox.setAlignmentY(JComponent.TOP_ALIGNMENT);
     230         directoryComboBox.setMaximumRowCount(8);
     231         topPanel.add(directoryComboBox, BorderLayout.CENTER);
     232
     233         filePane = new FilePane(new SynthFileChooserUIAccessor());
     234         fc.addPropertyChangeListener(filePane);
     235
     236         // Add 'Go Up' to context menu, plus 'Go Home' if on Unix
     237         JPopupMenu contextMenu = filePane.getComponentPopupMenu();
     238         if (contextMenu != null) {
     239             contextMenu.insert(getChangeToParentDirectoryAction(), 0);
     240             if (File.separatorChar == '/') {
     241                 contextMenu.insert(getGoHomeAction(), 1);
     242             }
     243         }
     244
     245     FileSystemView fsv = fc.getFileSystemView();
     246
     247     // Up Button
     248     JButton upFolderButton = new JButton(getChangeToParentDirectoryAction());
     249     upFolderButton.setText(null);
     250     upFolderButton.setIcon(upFolderIcon);
     251     upFolderButton.setToolTipText(upFolderToolTipText);
     252     upFolderButton.getAccessibleContext().setAccessibleName(upFolderAccessibleName);
     253     upFolderButton.setAlignmentX(JComponent.LEFT_ALIGNMENT);
     254     upFolderButton.setAlignmentY(JComponent.CENTER_ALIGNMENT);
     255     upFolderButton.setMargin(shrinkwrap);
     256
     257     topButtonPanel.add(upFolderButton);
     258     topButtonPanel.add(Box.createRigidArea(hstrut5));
     259
     260     // Home Button
     261     File homeDir = fsv.getHomeDirectory();
     262     String toolTipText = homeFolderToolTipText;
     263
     264     JButton b = new JButton(homeFolderIcon);
     265     b.setToolTipText(toolTipText);
     266     b.getAccessibleContext().setAccessibleName(homeFolderAccessibleName);
     267     b.setAlignmentX(JComponent.LEFT_ALIGNMENT);
     268     b.setAlignmentY(JComponent.CENTER_ALIGNMENT);
     269     b.setMargin(shrinkwrap);
     270
     271     b.addActionListener(getGoHomeAction());
     272     topButtonPanel.add(b);
     273     topButtonPanel.add(Box.createRigidArea(hstrut5));
     274
     275     // New Directory Button
     276     if (!readOnly) {
     277         b = new JButton(filePane.getNewFolderAction());
     278         b.setText(null);
     279         b.setIcon(newFolderIcon);
     280         b.setToolTipText(newFolderToolTipText);
     281         b.getAccessibleContext().setAccessibleName(newFolderAccessibleName);
     282         b.setAlignmentX(JComponent.LEFT_ALIGNMENT);
     283         b.setAlignmentY(JComponent.CENTER_ALIGNMENT);
     284         b.setMargin(shrinkwrap);
     285         topButtonPanel.add(b);
     286         topButtonPanel.add(Box.createRigidArea(hstrut5));
     287     }
     288
     289     // View button group
     290     ButtonGroup viewButtonGroup = new ButtonGroup();
     291
     292     // List Button
     293     listViewButton = new JToggleButton(listViewIcon);
     294     listViewButton.setToolTipText(listViewButtonToolTipText);
     295     listViewButton.getAccessibleContext().setAccessibleName(listViewButtonAccessibleName);
     296     listViewButton.setSelected(true);
     297     listViewButton.setAlignmentX(JComponent.LEFT_ALIGNMENT);
     298     listViewButton.setAlignmentY(JComponent.CENTER_ALIGNMENT);
     299     listViewButton.setMargin(shrinkwrap);
     300     listViewButton.addActionListener(filePane.getViewTypeAction(FilePane.VIEWTYPE_LIST));
     301     topButtonPanel.add(listViewButton);
     302     viewButtonGroup.add(listViewButton);
     303
     304     // Details Button
     305     detailsViewButton = new JToggleButton(detailsViewIcon);
     306     detailsViewButton.setToolTipText(detailsViewButtonToolTipText);
     307     detailsViewButton.getAccessibleContext().setAccessibleName(detailsViewButtonAccessibleName);
     308     detailsViewButton.setAlignmentX(JComponent.LEFT_ALIGNMENT);
     309     detailsViewButton.setAlignmentY(JComponent.CENTER_ALIGNMENT);
     310     detailsViewButton.setMargin(shrinkwrap);
     311     detailsViewButton.addActionListener(filePane.getViewTypeAction(FilePane.VIEWTYPE_DETAILS));
     312     topButtonPanel.add(detailsViewButton);
     313     viewButtonGroup.add(detailsViewButton);
     314
     315     filePane.addPropertyChangeListener(new PropertyChangeListener() {
     316         public void propertyChange(PropertyChangeEvent e) {
     317             if ("viewType".equals(e.getPropertyName())) {
     318                 int viewType = filePane.getViewType();
     319                 switch (viewType) {
     320                     case FilePane.VIEWTYPE_LIST:
     321                         listViewButton.setSelected(true);
     322                         break;
     323                     case FilePane.VIEWTYPE_DETAILS:
     324                         detailsViewButton.setSelected(true);
     325                         break;
     326                 }
     327             }
     328         }
     329     });
     330
     331         // ************************************** //
     332         // ******* Add the directory pane ******* //
     333         // ************************************** //
     334         fc.add(getAccessoryPanel(), BorderLayout.AFTER_LINE_ENDS);
     335         JComponent accessory = fc.getAccessory();
     336         if (accessory != null) {
     337             getAccessoryPanel().add(accessory);
     338         }
     339         filePane.setPreferredSize(LIST_PREF_SIZE);
     340         fc.add(filePane, BorderLayout.CENTER);
     341
     342
     343         // ********************************** //
     344         // **** Construct the bottom panel ** //
     345         // ********************************** //
     346         bottomPanel = new JPanel();
     347         bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.Y_AXIS));
     348         fc.add(bottomPanel, BorderLayout.SOUTH);
     349
     350         // FileName label and textfield
     351         JPanel fileNamePanel = new JPanel();
     352         fileNamePanel.setLayout(new BoxLayout(fileNamePanel, BoxLayout.LINE_AXIS));
     353         bottomPanel.add(fileNamePanel);
     354         bottomPanel.add(Box.createRigidArea(new Dimension(1, 5)));
     355
     356         fileNameLabel = new AlignedLabel();
     357         populateFileNameLabel();
     358         fileNamePanel.add(fileNameLabel);
     359
     360         fileNameTextField = new JTextField(35) {
     361             public Dimension getMaximumSize() {
     362                 return new Dimension(Short.MAX_VALUE, super.getPreferredSize().height);
     363             }
     364         };
     365         fileNamePanel.add(fileNameTextField);
     366         fileNameLabel.setLabelFor(fileNameTextField);
     367         fileNameTextField.addFocusListener(
     368             new FocusAdapter() {
     369                 public void focusGained(FocusEvent e) {
     370                     if (!getFileChooser().isMultiSelectionEnabled()) {
     371                         filePane.clearSelection();
     372                     }
     373                 }
     374             }
     375         );
     376         if (fc.isMultiSelectionEnabled()) {
     377             setFileName(fileNameString(fc.getSelectedFiles()));
     378         } else {
     379             setFileName(fileNameString(fc.getSelectedFile()));
     380         }
     381
     382
     383         // Filetype label and combobox
     384         JPanel filesOfTypePanel = new JPanel();
     385         filesOfTypePanel.setLayout(new BoxLayout(filesOfTypePanel, BoxLayout.LINE_AXIS));
     386         bottomPanel.add(filesOfTypePanel);
     387
     388         AlignedLabel filesOfTypeLabel = new AlignedLabel(filesOfTypeLabelText);
     389         filesOfTypeLabel.setDisplayedMnemonic(filesOfTypeLabelMnemonic);
     390         filesOfTypePanel.add(filesOfTypeLabel);
     391
     392         filterComboBoxModel = createFilterComboBoxModel();
     393         fc.addPropertyChangeListener(filterComboBoxModel);
     394         filterComboBox = new JComboBox<FileFilter>(filterComboBoxModel);
     395         filterComboBox.getAccessibleContext().setAccessibleDescription(filesOfTypeLabelText);
     396         filesOfTypeLabel.setLabelFor(filterComboBox);
     397         filterComboBox.setRenderer(createFilterComboBoxRenderer());
     398         filesOfTypePanel.add(filterComboBox);
     399
     400
     401         // buttons
     402         buttonPanel = new JPanel();
     403         buttonPanel.setLayout(new ButtonAreaLayout());
     404
     405         buttonPanel.add(getApproveButton(fc));
     406         buttonPanel.add(getCancelButton(fc));
     407
     408         if (fc.getControlButtonsAreShown()) {
     409             addControlButtons();
     410         }
     411
     412         groupLabels(new AlignedLabel[] { fileNameLabel, filesOfTypeLabel });
     413     }
     414
     415     protected void installListeners(JFileChooser fc) {
     416         super.installListeners(fc);
     417         fc.addPropertyChangeListener(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY, modeListener);
     418     }
     419
     420     protected void uninstallListeners(JFileChooser fc) {
     421         fc.removePropertyChangeListener(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY, modeListener);
     422         super.uninstallListeners(fc);
     423     }
     424
     425     private String fileNameString(File file) {
     426         if (file == null) {
     427             return null;
     428         } else {
     429             JFileChooser fc = getFileChooser();
     430             if (fc.isDirectorySelectionEnabled() && !fc.isFileSelectionEnabled()) {
     431                 return file.getPath();
     432             } else {
     433                 return file.getName();
     434             }
     435         }
     436     }
     437
     438     private String fileNameString(File[] files) {
     439         StringBuilder sb = new StringBuilder();
     440         for (int i = 0; files != null && i < files.length; i++) {
     441             if (i > 0) {
     442                 sb.append(" ");
     443             }
     444             if (files.length > 1) {
     445                 sb.append("\"");
     446             }
     447             sb.append(fileNameString(files[i]));
     448             if (files.length > 1) {
     449                 sb.append("\"");
     450             }
     451         }
     452         return sb.toString();
     453     }
     454
     455     public void uninstallUI(JComponent c) {
     456         // Remove listeners
     457         c.removePropertyChangeListener(filterComboBoxModel);
     458         c.removePropertyChangeListener(filePane);
     459
     460         if (filePane != null) {
     461             filePane.uninstallUI();
     462             filePane = null;
     463         }
     464
     465         super.uninstallUI(c);
     466     }
     467
     468     protected void installStrings(JFileChooser fc) {
     469         super.installStrings(fc);
     470
     471         Locale l = fc.getLocale();
     472
     473         lookInLabelMnemonic = getMnemonic("FileChooser.lookInLabelMnemonic", l);
     474         lookInLabelText = UIManager.getString("FileChooser.lookInLabelText", l);
     475         saveInLabelText = UIManager.getString("FileChooser.saveInLabelText", l);
     476
     477         fileNameLabelMnemonic = getMnemonic("FileChooser.fileNameLabelMnemonic", l);
     478         fileNameLabelText = UIManager.getString("FileChooser.fileNameLabelText", l);
     479         folderNameLabelMnemonic = getMnemonic("FileChooser.folderNameLabelMnemonic", l);
     480         folderNameLabelText = UIManager.getString("FileChooser.folderNameLabelText", l);
     481
     482         filesOfTypeLabelMnemonic = getMnemonic("FileChooser.filesOfTypeLabelMnemonic", l);
     483         filesOfTypeLabelText = UIManager.getString("FileChooser.filesOfTypeLabelText", l);
     484
     485     upFolderToolTipText =  UIManager.getString("FileChooser.upFolderToolTipText",l);
     486     upFolderAccessibleName = UIManager.getString("FileChooser.upFolderAccessibleName",l);
     487
     488     homeFolderToolTipText =  UIManager.getString("FileChooser.homeFolderToolTipText",l);
     489     homeFolderAccessibleName = UIManager.getString("FileChooser.homeFolderAccessibleName",l);
     490
     491     newFolderToolTipText = UIManager.getString("FileChooser.newFolderToolTipText",l);
     492     newFolderAccessibleName = UIManager.getString("FileChooser.newFolderAccessibleName",l);
     493
     494     listViewButtonToolTipText = UIManager.getString("FileChooser.listViewButtonToolTipText",l);
     495     listViewButtonAccessibleName = UIManager.getString("FileChooser.listViewButtonAccessibleName",l);
     496
     497     detailsViewButtonToolTipText = UIManager.getString("FileChooser.detailsViewButtonToolTipText",l);
     498     detailsViewButtonAccessibleName = UIManager.getString("FileChooser.detailsViewButtonAccessibleName",l);
     499     }
     500
     501     private int getMnemonic(String key, Locale l) {
     502         return SwingUtilities2.getUIDefaultsInt(key, l);
     503     }
     504
     505
     506     public String getFileName() {
     507         if (fileNameTextField != null) {
     508             return fileNameTextField.getText();
     509         } else {
     510             return null;
     511         }
     512     }
     513
     514     public void setFileName(String fileName) {
     515         if (fileNameTextField != null) {
     516             fileNameTextField.setText(fileName);
     517         }
     518     }
     519
     520     @Override public void rescanCurrentDirectory(JFileChooser fc) {
     521         filePane.rescanCurrentDirectory();
     522     }
     523
     524     protected void doSelectedFileChanged(PropertyChangeEvent e) {
     525         super.doSelectedFileChanged(e);
     526
     527         File f = (File) e.getNewValue();
     528         JFileChooser fc = getFileChooser();
     529         if (f != null
     530             && ((fc.isFileSelectionEnabled() && !f.isDirectory())
     531                 || (f.isDirectory() && fc.isDirectorySelectionEnabled()))) {
     532
     533             setFileName(fileNameString(f));
     534         }
     535     }
     536
     537     protected void doSelectedFilesChanged(PropertyChangeEvent e) {
     538         super.doSelectedFilesChanged(e);
     539
     540         File[] files = (File[]) e.getNewValue();
     541         JFileChooser fc = getFileChooser();
     542         if (files != null
     543             && files.length > 0
     544             && (files.length > 1 || fc.isDirectorySelectionEnabled() || !files[0].isDirectory())) {
     545             setFileName(fileNameString(files));
     546         }
     547     }
     548
     549     protected void doDirectoryChanged(PropertyChangeEvent e) {
     550         super.doDirectoryChanged(e);
     551
     552         JFileChooser fc = getFileChooser();
     553         FileSystemView fsv = fc.getFileSystemView();
     554         File currentDirectory = fc.getCurrentDirectory();
     555
     556         if (!readOnly && currentDirectory != null) {
     557             getNewFolderAction().setEnabled(filePane.canWrite(currentDirectory));
     558         }
     559
     560         if (currentDirectory != null) {
     561             JComponent cb = getDirectoryComboBox();
     562             if (cb instanceof JComboBox) {
     563                 ComboBoxModel<?> model = ((JComboBox)cb).getModel();
     564                 if (model instanceof DirectoryComboBoxModel) {
     565                     ((DirectoryComboBoxModel)model).addItem(currentDirectory);
     566                 }
     567             }
     568
     569             if (fc.isDirectorySelectionEnabled() && !fc.isFileSelectionEnabled()) {
     570                 if (fsv.isFileSystem(currentDirectory)) {
     571                     setFileName(currentDirectory.getPath());
     572                 } else {
     573                     setFileName(null);
     574                 }
     575             }
     576         }
     577     }
     578
     579
     580     protected void doFileSelectionModeChanged(PropertyChangeEvent e) {
     581         super.doFileSelectionModeChanged(e);
     582
     583         JFileChooser fc = getFileChooser();
     584         File currentDirectory = fc.getCurrentDirectory();
     585         if (currentDirectory != null
     586             && fc.isDirectorySelectionEnabled()
     587             && !fc.isFileSelectionEnabled()
     588             && fc.getFileSystemView().isFileSystem(currentDirectory)) {
     589
     590             setFileName(currentDirectory.getPath());
     591         } else {
     592             setFileName(null);
     593         }
     594     }
     595
     596     protected void doAccessoryChanged(PropertyChangeEvent e) {
     597         if (getAccessoryPanel() != null) {
     598             if (e.getOldValue() != null) {
     599                 getAccessoryPanel().remove((JComponent)e.getOldValue());
     600             }
     601             JComponent accessory = (JComponent)e.getNewValue();
     602             if (accessory != null) {
     603                 getAccessoryPanel().add(accessory, BorderLayout.CENTER);
     604             }
     605         }
     606     }
     607
     608     protected void doControlButtonsChanged(PropertyChangeEvent e) {
     609         super.doControlButtonsChanged(e);
     610
     611         if (getFileChooser().getControlButtonsAreShown()) {
     612             addControlButtons();
     613         } else {
     614             removeControlButtons();
     615         }
     616     }
     617
     618     protected void addControlButtons() {
     619         if (bottomPanel != null) {
     620             bottomPanel.add(buttonPanel);
     621         }
     622     }
     623
     624     protected void removeControlButtons() {
     625         if (bottomPanel != null) {
     626             bottomPanel.remove(buttonPanel);
     627         }
     628     }
     629
     630
     631
     632
     633     // *******************************************************
     634     // ************ FileChooser UI PLAF methods **************
     635     // *******************************************************
     636
     637     protected ActionMap createActionMap() {
     638         ActionMap map = new ActionMapUIResource();
     639         // add standard actions
     640         FilePane.addActionsToMap(map, filePane.getActions());
     641         // add synth only actions
     642         map.put("fileNameCompletion", getFileNameCompletionAction());
     643         return map;
     644     }
     645
     646     // *****************************
     647     // ***** Directory Actions *****
     648     // *****************************
     649
     650     protected JComponent getDirectoryComboBox() {
     651         return directoryComboBox;
     652     }
     653
     654     protected Action getDirectoryComboBoxAction() {
     655         return directoryComboBoxAction;
     656     }
     657
     658     protected DirectoryComboBoxRenderer createDirectoryComboBoxRenderer(JFileChooser fc) {
     659         return new DirectoryComboBoxRenderer(directoryComboBox.getRenderer());
     660     }
     661
     662     //
     663     // Renderer for DirectoryComboBox
     664     //
     665     // Synth has some odd behavior with regards to renderers. Renderers are styled
     666     // in a specific manner by the SynthComboBoxUI. If we extend DefaultListCellRenderer
     667     // here, then we get none of those benefits or behaviors, leading to poor
     668     // looking combo boxes.
     669     // So what we do here is delegate most jobs to the "real" or original renderer,
     670     // and simply monkey with the icon and text of the renderer.
     671     private class DirectoryComboBoxRenderer implements ListCellRenderer<File> {
     672         private ListCellRenderer<? super File> delegate;
     673         IndentIcon ii = new IndentIcon();
     674
     675         private DirectoryComboBoxRenderer(ListCellRenderer<? super File> delegate) {
     676             this.delegate = delegate;
     677         }
     678
     679         @Override
     680         public Component getListCellRendererComponent(JList<? extends File> list, File value, int index, boolean isSelected, boolean cellHasFocus) {
     681             Component c = delegate.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
     682
     683             assert c instanceof JLabel;
     684             JLabel label = (JLabel)c;
     685             if (value == null) {
     686                 label.setText("");
     687                 return label;
     688             }
     689             label.setText(getFileChooser().getName(value));
     690             Icon icon = getFileChooser().getIcon(value);
     691             ii.icon = icon;
     692             ii.depth = directoryComboBoxModel.getDepth(index);
     693             label.setIcon(ii);
     694
     695             return label;
     696         }
     697     }
     698
     699     static final int space = 10;
     700     class IndentIcon implements Icon {
     701
     702         Icon icon = null;
     703         int depth = 0;
     704
     705         public void paintIcon(Component c, Graphics g, int x, int y) {
     706             if (icon != null) {
     707                 if (c.getComponentOrientation().isLeftToRight()) {
     708                     icon.paintIcon(c, g, x+depth*space, y);
     709                 } else {
     710                     icon.paintIcon(c, g, x, y);
     711                 }
     712             }
     713         }
     714
     715         public int getIconWidth() {
     716             return ((icon != null) ? icon.getIconWidth() : 0) + depth*space;
     717         }
     718
     719         public int getIconHeight() {
     720             return (icon != null) ? icon.getIconHeight() : 0;
     721         }
     722
     723     }
     724
     725     //
     726     // DataModel for DirectoryComboxbox
     727     //
     728     protected DirectoryComboBoxModel createDirectoryComboBoxModel(JFileChooser fc) {
     729         return new DirectoryComboBoxModel();
     730     }
     731
     732     /**
     733      * Data model for a type-face selection combo-box.
     734      */
     735     @SuppressWarnings("serial") // JDK-implementation class
     736     protected class DirectoryComboBoxModel extends AbstractListModel<File> implements ComboBoxModel<File> {
     737         Vector<File> directories = new Vector<File>();
     738         int[] depths = null;
     739         File selectedDirectory = null;
     740         JFileChooser chooser = getFileChooser();
     741         FileSystemView fsv = chooser.getFileSystemView();
     742
     743         public DirectoryComboBoxModel() {
     744             // Add the current directory to the model, and make it the
     745             // selectedDirectory
     746             File dir = getFileChooser().getCurrentDirectory();
     747             if (dir != null) {
     748                 addItem(dir);
     749             }
     750         }
     751
     752         /**
     753          * Adds the directory to the model and sets it to be selected,
     754          * additionally clears out the previous selected directory and
     755          * the paths leading up to it, if any.
     756          */
     757         public void addItem(File directory) {
     758
     759             if (directory == null) {
     760                 return;
     761             }
     762
     763             boolean useShellFolder = FilePane.usesShellFolder(chooser);
     764
     765             int oldSize = directories.size();
     766             directories.clear();
     767             if (oldSize > 0) {
     768                 fireIntervalRemoved(this, 0, oldSize);
     769             }
     770
     771             File[] baseFolders = (useShellFolder)
     772                     ? (File[]) ShellFolder.get("fileChooserComboBoxFolders")
     773                     : fsv.getRoots();
     774             directories.addAll(Arrays.asList(baseFolders));
     775
     776             // Get the canonical (full) path. This has the side
     777             // benefit of removing extraneous chars from the path,
     778             // for example /foo/bar/ becomes /foo/bar
     779             File canonical;
     780             try {
     781                 canonical = ShellFolder.getNormalizedFile(directory);
     782             } catch (IOException e) {
     783                 // Maybe drive is not ready. Can't abort here.
     784                 canonical = directory;
     785             }
     786
     787             // create File instances of each directory leading up to the top
     788             try {
     789                 File sf = useShellFolder ? ShellFolder.getShellFolder(canonical)
     790                                          : canonical;
     791                 File f = sf;
     792                 Vector<File> path = new Vector<File>(10);
     793                 do {
     794                     path.addElement(f);
     795                 } while ((f = f.getParentFile()) != null);
     796
     797                 int pathCount = path.size();
     798                 // Insert chain at appropriate place in vector
     799                 for (int i = 0; i < pathCount; i++) {
     800                     f = path.get(i);
     801                     if (directories.contains(f)) {
     802                         int topIndex = directories.indexOf(f);
     803                         for (int j = i-1; j >= 0; j--) {
     804                             directories.insertElementAt(path.get(j), topIndex+i-j);
     805                         }
     806                         break;
     807                     }
     808                 }
     809                 calculateDepths();
     810                 setSelectedItem(sf);
     811             } catch (FileNotFoundException ex) {
     812                 calculateDepths();
     813             }
     814         }
     815
     816         private void calculateDepths() {
     817             depths = new int[directories.size()];
     818             for (int i = 0; i < depths.length; i++) {
     819                 File dir = directories.get(i);
     820                 File parent = dir.getParentFile();
     821                 depths[i] = 0;
     822                 if (parent != null) {
     823                     for (int j = i-1; j >= 0; j--) {
     824                         if (parent.equals(directories.get(j))) {
     825                             depths[i] = depths[j] + 1;
     826                             break;
     827                         }
     828                     }
     829                 }
     830             }
     831         }
     832
     833         public int getDepth(int i) {
     834             return (depths != null && i >= 0 && i < depths.length) ? depths[i] : 0;
     835         }
     836
     837         @Override
     838         public void setSelectedItem(File selectedDirectory) {
     839             this.selectedDirectory = selectedDirectory;
     840             fireContentsChanged(this, -1, -1);
     841         }
     842
     843         @Override
     844         public File getSelectedItem() {
     845             return selectedDirectory;
     846         }
     847
     848         public int getSize() {
     849             return directories.size();
     850         }
     851
     852         public File getElementAt(int index) {
     853             return directories.elementAt(index);
     854         }
     855     }
     856
     857     /**
     858      * Acts when DirectoryComboBox has changed the selected item.
     859      */
     860     @SuppressWarnings("serial") // JDK-implementation class
     861     protected class DirectoryComboBoxAction extends AbstractAction {
     862         protected DirectoryComboBoxAction() {
     863             super("DirectoryComboBoxAction");
     864         }
     865
     866         public void actionPerformed(ActionEvent e) {
     867             directoryComboBox.hidePopup();
     868             JComponent cb = getDirectoryComboBox();
     869             if (cb instanceof JComboBox) {
     870                 File f = (File)((JComboBox)cb).getSelectedItem();
     871                 getFileChooser().setCurrentDirectory(f);
     872             }
     873         }
     874     }
     875
     876     //
     877     // Renderer for Types ComboBox
     878     //
     879     protected FilterComboBoxRenderer createFilterComboBoxRenderer() {
     880         return new FilterComboBoxRenderer(filterComboBox.getRenderer());
     881     }
     882
     883     /**
     884      * Render different type sizes and styles.
     885      */
     886     public class FilterComboBoxRenderer implements ListCellRenderer<FileFilter> {
     887         private ListCellRenderer<? super FileFilter> delegate;
     888         private FilterComboBoxRenderer(ListCellRenderer<? super FileFilter> delegate) {
     889             this.delegate = delegate;
     890         }
     891
     892         public Component getListCellRendererComponent(JList<? extends FileFilter> list, FileFilter value, int index,
     893                                                       boolean isSelected, boolean cellHasFocus) {
     894             Component c = delegate.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
     895
     896             String text = null;
     897             if (value != null) {
     898                 text = value.getDescription();
     899             }
     900
     901             //this should always be true, since SynthComboBoxUI's SynthComboBoxRenderer
     902             //extends JLabel
     903             assert c instanceof JLabel;
     904             if (text != null) {
     905                 ((JLabel)c).setText(text);
     906             }
     907             return c;
     908         }
     909     }
     910
     911     //
     912     // DataModel for Types Comboxbox
     913     //
     914     protected FilterComboBoxModel createFilterComboBoxModel() {
     915         return new FilterComboBoxModel();
     916     }
     917
     918     /**
     919      * Data model for a type-face selection combo-box.
     920      */
     921     @SuppressWarnings("serial") // JDK-implementation class
     922     protected class FilterComboBoxModel extends AbstractListModel<FileFilter> implements ComboBoxModel<FileFilter>,
     923             PropertyChangeListener {
     924         protected FileFilter[] filters;
     925         protected FilterComboBoxModel() {
     926             super();
     927             filters = getFileChooser().getChoosableFileFilters();
     928         }
     929
     930         public void propertyChange(PropertyChangeEvent e) {
     931             String prop = e.getPropertyName();
     932             if(prop == JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY) {
     933                 filters = (FileFilter[]) e.getNewValue();
     934                 fireContentsChanged(this, -1, -1);
     935             } else if (prop == JFileChooser.FILE_FILTER_CHANGED_PROPERTY) {
     936                 fireContentsChanged(this, -1, -1);
     937             }
     938         }
     939
     940         public void setSelectedItem(FileFilter filter) {
     941             if(filter != null) {
     942                 getFileChooser().setFileFilter(filter);
     943                 fireContentsChanged(this, -1, -1);
     944             }
     945         }
     946
     947         public FileFilter getSelectedItem() {
     948             // Ensure that the current filter is in the list.
     949             // NOTE: we shouldnt' have to do this, since JFileChooser adds
     950             // the filter to the choosable filters list when the filter
     951             // is set. Lets be paranoid just in case someone overrides
     952             // setFileFilter in JFileChooser.
     953             FileFilter currentFilter = getFileChooser().getFileFilter();
     954             boolean found = false;
     955             if(currentFilter != null) {
     956                 for (FileFilter filter : filters) {
     957                     if (filter == currentFilter) {
     958                         found = true;
     959                     }
     960                 }
     961                 if(found == false) {
     962                     getFileChooser().addChoosableFileFilter(currentFilter);
     963                 }
     964             }
     965             return getFileChooser().getFileFilter();
     966         }
     967
     968         public int getSize() {
     969             if(filters != null) {
     970                 return filters.length;
     971             } else {
     972                 return 0;
     973             }
     974         }
     975
     976         public FileFilter getElementAt(int index) {
     977             if(index > getSize() - 1) {
     978                 // This shouldn't happen. Try to recover gracefully.
     979                 return getFileChooser().getFileFilter();
     980             }
     981             if(filters != null) {
     982                 return filters[index];
     983             } else {
     984                 return null;
     985             }
     986         }
     987     }
     988
     989
     990
     991     /**
     992      * <code>ButtonAreaLayout</code> behaves in a similar manner to
     993      * <code>FlowLayout</code>. It lays out all components from left to
     994      * right, flushed right. The widths of all components will be set
     995      * to the largest preferred size width.
     996      */
     997     private static class ButtonAreaLayout implements LayoutManager {
     998         private int hGap = 5;
     999         private int topMargin = 17;
    1000
    1001         public void addLayoutComponent(String string, Component comp) {
    1002         }
    1003
    1004         public void layoutContainer(Container container) {
    1005             Component[] children = container.getComponents();
    1006
    1007             if (children != null && children.length > 0) {
    1008                 int         numChildren = children.length;
    1009                 Dimension[] sizes = new Dimension[numChildren];
    1010                 Insets      insets = container.getInsets();
    1011                 int         yLocation = insets.top + topMargin;
    1012                 int         maxWidth = 0;
    1013
    1014                 for (int counter = 0; counter < numChildren; counter++) {
    1015                     sizes[counter] = children[counter].getPreferredSize();
    1016                     maxWidth = Math.max(maxWidth, sizes[counter].width);
    1017                 }
    1018                 int xLocation, xOffset;
    1019                 if (container.getComponentOrientation().isLeftToRight()) {
    1020                     xLocation = container.getSize().width - insets.left - maxWidth;
    1021                     xOffset = hGap + maxWidth;
    1022                 } else {
    1023                     xLocation = insets.left;
    1024                     xOffset = -(hGap + maxWidth);
    1025                 }
    1026                 for (int counter = numChildren - 1; counter >= 0; counter--) {
    1027                     children[counter].setBounds(xLocation, yLocation,
    1028                                                 maxWidth, sizes[counter].height);
    1029                     xLocation -= xOffset;
    1030                 }
    1031             }
    1032         }
    1033
    1034         public Dimension minimumLayoutSize(Container c) {
    1035             if (c != null) {
    1036                 Component[] children = c.getComponents();
    1037
    1038                 if (children != null && children.length > 0) {
    1039                     int       numChildren = children.length;
    1040                     int       height = 0;
    1041                     Insets    cInsets = c.getInsets();
    1042                     int       extraHeight = topMargin + cInsets.top + cInsets.bottom;
    1043                     int       extraWidth = cInsets.left + cInsets.right;
    1044                     int       maxWidth = 0;
    1045
    1046                     for (int counter = 0; counter < numChildren; counter++) {
    1047                         Dimension aSize = children[counter].getPreferredSize();
    1048                         height = Math.max(height, aSize.height);
    1049                         maxWidth = Math.max(maxWidth, aSize.width);
    1050                     }
    1051                     return new Dimension(extraWidth + numChildren * maxWidth +
    1052                                          (numChildren - 1) * hGap,
    1053                                          extraHeight + height);
    1054                 }
    1055             }
    1056             return new Dimension(0, 0);
    1057         }
    1058
    1059         public Dimension preferredLayoutSize(Container c) {
    1060             return minimumLayoutSize(c);
    1061         }
    1062
    1063         public void removeLayoutComponent(Component c) { }
    1064     }
    1065
    1066     private static void groupLabels(AlignedLabel[] group) {
    1067         for (int i = 0; i < group.length; i++) {
    1068             group[i].group = group;
    1069         }
    1070     }
    1071
    1072     @SuppressWarnings("serial") // JDK-implementation class
    1073     private class AlignedLabel extends JLabel {
    1074         private AlignedLabel[] group;
    1075         private int maxWidth = 0;
    1076
    1077         AlignedLabel() {
    1078             super();
    1079             setAlignmentX(JComponent.LEFT_ALIGNMENT);
    1080         }
    1081
    1082         AlignedLabel(String text) {
    1083             super(text);
    1084             setAlignmentX(JComponent.LEFT_ALIGNMENT);
    1085         }
    1086
    1087         public Dimension getPreferredSize() {
    1088             Dimension d = super.getPreferredSize();
    1089             // Align the width with all other labels in group.
    1090             return new Dimension(getMaxWidth() + 11, d.height);
    1091         }
    1092
    1093         private int getMaxWidth() {
    1094             if (maxWidth == 0 && group != null) {
    1095                 int max = 0;
    1096                 for (int i = 0; i < group.length; i++) {
    1097                     max = Math.max(group[i].getSuperPreferredWidth(), max);
    1098                 }
    1099                 for (int i = 0; i < group.length; i++) {
    1100                     group[i].maxWidth = max;
    1101                 }
    1102             }
    1103             return maxWidth;
    1104         }
    1105
    1106         private int getSuperPreferredWidth() {
    1107             return super.getPreferredSize().width;
    1108         }
    1109     }
    1110 }
    --- EOF ---