| /* | |
| * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. Oracle designates this | |
| * particular file as subject to the "Classpath" exception as provided | |
| * by Oracle in the LICENSE file that accompanied this code. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| package sun.swing.plaf.synth; | |
| import java.awt.*; | |
| import java.awt.event.*; | |
| import java.beans.*; | |
| import java.io.*; | |
| import java.util.*; | |
| import javax.swing.*; | |
| import javax.swing.event.*; | |
| import javax.swing.filechooser.*; | |
| import javax.swing.filechooser.FileFilter; | |
| import javax.swing.plaf.basic.*; | |
| import javax.swing.plaf.synth.*; | |
| import javax.swing.plaf.ActionMapUIResource; | |
| import sun.awt.shell.ShellFolder; | |
| import sun.swing.*; | |
| /** | |
| * Synth FileChooserUI implementation. | |
| * <p> | |
| * Note that the classes in the com.sun.java.swing.plaf.synth | |
| * package are not | |
| * part of the core Java APIs. They are a part of Sun's JDK and JRE | |
| * distributions. Although other licensees may choose to distribute | |
| * these classes, developers cannot depend on their availability in | |
| * non-Sun implementations. Additionally this API may change in | |
| * incompatible ways between releases. While this class is public, it | |
| * should be considered an implementation detail, and subject to change. | |
| * | |
| * @author Leif Samuelsson | |
| * @author Jeff Dinkins | |
| */ | |
| public class SynthFileChooserUIImpl extends SynthFileChooserUI { | |
| private JLabel lookInLabel; | |
| private JComboBox<File> directoryComboBox; | |
| private DirectoryComboBoxModel directoryComboBoxModel; | |
| private Action directoryComboBoxAction = new DirectoryComboBoxAction(); | |
| private FilterComboBoxModel filterComboBoxModel; | |
| private JTextField fileNameTextField; | |
| private FilePane filePane; | |
| private JToggleButton listViewButton; | |
| private JToggleButton detailsViewButton; | |
| private boolean readOnly; | |
| private JPanel buttonPanel; | |
| private JPanel bottomPanel; | |
| private JComboBox<FileFilter> filterComboBox; | |
| private static final Dimension hstrut5 = new Dimension(5, 1); | |
| private static final Insets shrinkwrap = new Insets(0,0,0,0); | |
| // Preferred and Minimum sizes for the dialog box | |
| private static Dimension LIST_PREF_SIZE = new Dimension(405, 135); | |
| // Labels, mnemonics, and tooltips (oh my!) | |
| private int lookInLabelMnemonic = 0; | |
| private String lookInLabelText = null; | |
| private String saveInLabelText = null; | |
| private int fileNameLabelMnemonic = 0; | |
| private String fileNameLabelText = null; | |
| private int folderNameLabelMnemonic = 0; | |
| private String folderNameLabelText = null; | |
| private int filesOfTypeLabelMnemonic = 0; | |
| private String filesOfTypeLabelText = null; | |
| private String upFolderToolTipText = null; | |
| private String upFolderAccessibleName = null; | |
| private String homeFolderToolTipText = null; | |
| private String homeFolderAccessibleName = null; | |
| private String newFolderToolTipText = null; | |
| private String newFolderAccessibleName = null; | |
| private String listViewButtonToolTipText = null; | |
| private String listViewButtonAccessibleName = null; | |
| private String detailsViewButtonToolTipText = null; | |
| private String detailsViewButtonAccessibleName = null; | |
| private AlignedLabel fileNameLabel; | |
| private final PropertyChangeListener modeListener = new PropertyChangeListener() { | |
| public void propertyChange(PropertyChangeEvent event) { | |
| if (fileNameLabel != null) { | |
| populateFileNameLabel(); | |
| } | |
| } | |
| }; | |
| private void populateFileNameLabel() { | |
| if (getFileChooser().getFileSelectionMode() == JFileChooser.DIRECTORIES_ONLY) { | |
| fileNameLabel.setText(folderNameLabelText); | |
| fileNameLabel.setDisplayedMnemonic(folderNameLabelMnemonic); | |
| } else { | |
| fileNameLabel.setText(fileNameLabelText); | |
| fileNameLabel.setDisplayedMnemonic(fileNameLabelMnemonic); | |
| } | |
| } | |
| public SynthFileChooserUIImpl(JFileChooser b) { | |
| super(b); | |
| } | |
| private class SynthFileChooserUIAccessor implements FilePane.FileChooserUIAccessor { | |
| public JFileChooser getFileChooser() { | |
| return SynthFileChooserUIImpl.this.getFileChooser(); | |
| } | |
| public BasicDirectoryModel getModel() { | |
| return SynthFileChooserUIImpl.this.getModel(); | |
| } | |
| public JPanel createList() { | |
| return null; | |
| } | |
| public JPanel createDetailsView() { | |
| return null; | |
| } | |
| public boolean isDirectorySelected() { | |
| return SynthFileChooserUIImpl.this.isDirectorySelected(); | |
| } | |
| public File getDirectory() { | |
| return SynthFileChooserUIImpl.this.getDirectory(); | |
| } | |
| public Action getChangeToParentDirectoryAction() { | |
| return SynthFileChooserUIImpl.this.getChangeToParentDirectoryAction(); | |
| } | |
| public Action getApproveSelectionAction() { | |
| return SynthFileChooserUIImpl.this.getApproveSelectionAction(); | |
| } | |
| public Action getNewFolderAction() { | |
| return SynthFileChooserUIImpl.this.getNewFolderAction(); | |
| } | |
| public MouseListener createDoubleClickListener(JList<?> list) { | |
| return SynthFileChooserUIImpl.this.createDoubleClickListener(getFileChooser(), | |
| list); | |
| } | |
| public ListSelectionListener createListSelectionListener() { | |
| return SynthFileChooserUIImpl.this.createListSelectionListener(getFileChooser()); | |
| } | |
| } | |
| protected void installDefaults(JFileChooser fc) { | |
| super.installDefaults(fc); | |
| readOnly = UIManager.getBoolean("FileChooser.readOnly"); | |
| } | |
| public void installComponents(JFileChooser fc) { | |
| super.installComponents(fc); | |
| SynthContext context = getContext(fc, ENABLED); | |
| fc.setLayout(new BorderLayout(0, 11)); | |
| // ********************************* // | |
| // **** Construct the top panel **** // | |
| // ********************************* // | |
| // Directory manipulation buttons | |
| JPanel topPanel = new JPanel(new BorderLayout(11, 0)); | |
| JPanel topButtonPanel = new JPanel(); | |
| topButtonPanel.setLayout(new BoxLayout(topButtonPanel, BoxLayout.LINE_AXIS)); | |
| topPanel.add(topButtonPanel, BorderLayout.AFTER_LINE_ENDS); | |
| // Add the top panel to the fileChooser | |
| fc.add(topPanel, BorderLayout.NORTH); | |
| // ComboBox Label | |
| lookInLabel = new JLabel(lookInLabelText); | |
| lookInLabel.setDisplayedMnemonic(lookInLabelMnemonic); | |
| topPanel.add(lookInLabel, BorderLayout.BEFORE_LINE_BEGINS); | |
| // CurrentDir ComboBox | |
| directoryComboBox = new JComboBox<File>(); | |
| directoryComboBox.getAccessibleContext().setAccessibleDescription(lookInLabelText); | |
| directoryComboBox.putClientProperty( "JComboBox.isTableCellEditor", Boolean.TRUE ); | |
| lookInLabel.setLabelFor(directoryComboBox); | |
| directoryComboBoxModel = createDirectoryComboBoxModel(fc); | |
| directoryComboBox.setModel(directoryComboBoxModel); | |
| directoryComboBox.addActionListener(directoryComboBoxAction); | |
| directoryComboBox.setRenderer(createDirectoryComboBoxRenderer(fc)); | |
| directoryComboBox.setAlignmentX(JComponent.LEFT_ALIGNMENT); | |
| directoryComboBox.setAlignmentY(JComponent.TOP_ALIGNMENT); | |
| directoryComboBox.setMaximumRowCount(8); | |
| topPanel.add(directoryComboBox, BorderLayout.CENTER); | |
| filePane = new FilePane(new SynthFileChooserUIAccessor()); | |
| fc.addPropertyChangeListener(filePane); | |
| // Add 'Go Up' to context menu, plus 'Go Home' if on Unix | |
| JPopupMenu contextMenu = filePane.getComponentPopupMenu(); | |
| if (contextMenu != null) { | |
| contextMenu.insert(getChangeToParentDirectoryAction(), 0); | |
| if (File.separatorChar == '/') { | |
| contextMenu.insert(getGoHomeAction(), 1); | |
| } | |
| } | |
| FileSystemView fsv = fc.getFileSystemView(); | |
| // Up Button | |
| JButton upFolderButton = new JButton(getChangeToParentDirectoryAction()); | |
| upFolderButton.setText(null); | |
| upFolderButton.setIcon(upFolderIcon); | |
| upFolderButton.setToolTipText(upFolderToolTipText); | |
| upFolderButton.getAccessibleContext().setAccessibleName(upFolderAccessibleName); | |
| upFolderButton.setAlignmentX(JComponent.LEFT_ALIGNMENT); | |
| upFolderButton.setAlignmentY(JComponent.CENTER_ALIGNMENT); | |
| upFolderButton.setMargin(shrinkwrap); | |
| topButtonPanel.add(upFolderButton); | |
| topButtonPanel.add(Box.createRigidArea(hstrut5)); | |
| // Home Button | |
| File homeDir = fsv.getHomeDirectory(); | |
| String toolTipText = homeFolderToolTipText; | |
| JButton b = new JButton(homeFolderIcon); | |
| b.setToolTipText(toolTipText); | |
| b.getAccessibleContext().setAccessibleName(homeFolderAccessibleName); | |
| b.setAlignmentX(JComponent.LEFT_ALIGNMENT); | |
| b.setAlignmentY(JComponent.CENTER_ALIGNMENT); | |
| b.setMargin(shrinkwrap); | |
| b.addActionListener(getGoHomeAction()); | |
| topButtonPanel.add(b); | |
| topButtonPanel.add(Box.createRigidArea(hstrut5)); | |
| // New Directory Button | |
| if (!readOnly) { | |
| b = new JButton(filePane.getNewFolderAction()); | |
| b.setText(null); | |
| b.setIcon(newFolderIcon); | |
| b.setToolTipText(newFolderToolTipText); | |
| b.getAccessibleContext().setAccessibleName(newFolderAccessibleName); | |
| b.setAlignmentX(JComponent.LEFT_ALIGNMENT); | |
| b.setAlignmentY(JComponent.CENTER_ALIGNMENT); | |
| b.setMargin(shrinkwrap); | |
| topButtonPanel.add(b); | |
| topButtonPanel.add(Box.createRigidArea(hstrut5)); | |
| } | |
| // View button group | |
| ButtonGroup viewButtonGroup = new ButtonGroup(); | |
| // List Button | |
| listViewButton = new JToggleButton(listViewIcon); | |
| listViewButton.setToolTipText(listViewButtonToolTipText); | |
| listViewButton.getAccessibleContext().setAccessibleName(listViewButtonAccessibleName); | |
| listViewButton.setSelected(true); | |
| listViewButton.setAlignmentX(JComponent.LEFT_ALIGNMENT); | |
| listViewButton.setAlignmentY(JComponent.CENTER_ALIGNMENT); | |
| listViewButton.setMargin(shrinkwrap); | |
| listViewButton.addActionListener(filePane.getViewTypeAction(FilePane.VIEWTYPE_LIST)); | |
| topButtonPanel.add(listViewButton); | |
| viewButtonGroup.add(listViewButton); | |
| // Details Button | |
| detailsViewButton = new JToggleButton(detailsViewIcon); | |
| detailsViewButton.setToolTipText(detailsViewButtonToolTipText); | |
| detailsViewButton.getAccessibleContext().setAccessibleName(detailsViewButtonAccessibleName); | |
| detailsViewButton.setAlignmentX(JComponent.LEFT_ALIGNMENT); | |
| detailsViewButton.setAlignmentY(JComponent.CENTER_ALIGNMENT); | |
| detailsViewButton.setMargin(shrinkwrap); | |
| detailsViewButton.addActionListener(filePane.getViewTypeAction(FilePane.VIEWTYPE_DETAILS)); | |
| topButtonPanel.add(detailsViewButton); | |
| viewButtonGroup.add(detailsViewButton); | |
| filePane.addPropertyChangeListener(new PropertyChangeListener() { | |
| public void propertyChange(PropertyChangeEvent e) { | |
| if ("viewType".equals(e.getPropertyName())) { | |
| int viewType = filePane.getViewType(); | |
| switch (viewType) { | |
| case FilePane.VIEWTYPE_LIST: | |
| listViewButton.setSelected(true); | |
| break; | |
| case FilePane.VIEWTYPE_DETAILS: | |
| detailsViewButton.setSelected(true); | |
| break; | |
| } | |
| } | |
| } | |
| }); | |
| // ************************************** // | |
| // ******* Add the directory pane ******* // | |
| // ************************************** // | |
| fc.add(getAccessoryPanel(), BorderLayout.AFTER_LINE_ENDS); | |
| JComponent accessory = fc.getAccessory(); | |
| if (accessory != null) { | |
| getAccessoryPanel().add(accessory); | |
| } | |
| filePane.setPreferredSize(LIST_PREF_SIZE); | |
| fc.add(filePane, BorderLayout.CENTER); | |
| // ********************************** // | |
| // **** Construct the bottom panel ** // | |
| // ********************************** // | |
| bottomPanel = new JPanel(); | |
| bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.Y_AXIS)); | |
| fc.add(bottomPanel, BorderLayout.SOUTH); | |
| // FileName label and textfield | |
| JPanel fileNamePanel = new JPanel(); | |
| fileNamePanel.setLayout(new BoxLayout(fileNamePanel, BoxLayout.LINE_AXIS)); | |
| bottomPanel.add(fileNamePanel); | |
| bottomPanel.add(Box.createRigidArea(new Dimension(1, 5))); | |
| fileNameLabel = new AlignedLabel(); | |
| populateFileNameLabel(); | |
| fileNamePanel.add(fileNameLabel); | |
| fileNameTextField = new JTextField(35) { | |
| public Dimension getMaximumSize() { | |
| return new Dimension(Short.MAX_VALUE, super.getPreferredSize().height); | |
| } | |
| }; | |
| fileNamePanel.add(fileNameTextField); | |
| fileNameLabel.setLabelFor(fileNameTextField); | |
| fileNameTextField.addFocusListener( | |
| new FocusAdapter() { | |
| public void focusGained(FocusEvent e) { | |
| if (!getFileChooser().isMultiSelectionEnabled()) { | |
| filePane.clearSelection(); | |
| } | |
| } | |
| } | |
| ); | |
| if (fc.isMultiSelectionEnabled()) { | |
| setFileName(fileNameString(fc.getSelectedFiles())); | |
| } else { | |
| setFileName(fileNameString(fc.getSelectedFile())); | |
| } | |
| // Filetype label and combobox | |
| JPanel filesOfTypePanel = new JPanel(); | |
| filesOfTypePanel.setLayout(new BoxLayout(filesOfTypePanel, BoxLayout.LINE_AXIS)); | |
| bottomPanel.add(filesOfTypePanel); | |
| AlignedLabel filesOfTypeLabel = new AlignedLabel(filesOfTypeLabelText); | |
| filesOfTypeLabel.setDisplayedMnemonic(filesOfTypeLabelMnemonic); | |
| filesOfTypePanel.add(filesOfTypeLabel); | |
| filterComboBoxModel = createFilterComboBoxModel(); | |
| fc.addPropertyChangeListener(filterComboBoxModel); | |
| filterComboBox = new JComboBox<FileFilter>(filterComboBoxModel); | |
| filterComboBox.getAccessibleContext().setAccessibleDescription(filesOfTypeLabelText); | |
| filesOfTypeLabel.setLabelFor(filterComboBox); | |
| filterComboBox.setRenderer(createFilterComboBoxRenderer()); | |
| filesOfTypePanel.add(filterComboBox); | |
| // buttons | |
| buttonPanel = new JPanel(); | |
| buttonPanel.setLayout(new ButtonAreaLayout()); | |
| buttonPanel.add(getApproveButton(fc)); | |
| buttonPanel.add(getCancelButton(fc)); | |
| if (fc.getControlButtonsAreShown()) { | |
| addControlButtons(); | |
| } | |
| groupLabels(new AlignedLabel[] { fileNameLabel, filesOfTypeLabel }); | |
| } | |
| protected void installListeners(JFileChooser fc) { | |
| super.installListeners(fc); | |
| fc.addPropertyChangeListener(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY, modeListener); | |
| } | |
| protected void uninstallListeners(JFileChooser fc) { | |
| fc.removePropertyChangeListener(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY, modeListener); | |
| super.uninstallListeners(fc); | |
| } | |
| private String fileNameString(File file) { | |
| if (file == null) { | |
| return null; | |
| } else { | |
| JFileChooser fc = getFileChooser(); | |
| if (fc.isDirectorySelectionEnabled() && !fc.isFileSelectionEnabled()) { | |
| return file.getPath(); | |
| } else { | |
| return file.getName(); | |
| } | |
| } | |
| } | |
| private String fileNameString(File[] files) { | |
| StringBuilder sb = new StringBuilder(); | |
| for (int i = 0; files != null && i < files.length; i++) { | |
| if (i > 0) { | |
| sb.append(" "); | |
| } | |
| if (files.length > 1) { | |
| sb.append("\""); | |
| } | |
| sb.append(fileNameString(files[i])); | |
| if (files.length > 1) { | |
| sb.append("\""); | |
| } | |
| } | |
| return sb.toString(); | |
| } | |
| public void uninstallUI(JComponent c) { | |
| // Remove listeners | |
| c.removePropertyChangeListener(filterComboBoxModel); | |
| c.removePropertyChangeListener(filePane); | |
| if (filePane != null) { | |
| filePane.uninstallUI(); | |
| filePane = null; | |
| } | |
| super.uninstallUI(c); | |
| } | |
| protected void installStrings(JFileChooser fc) { | |
| super.installStrings(fc); | |
| Locale l = fc.getLocale(); | |
| lookInLabelMnemonic = getMnemonic("FileChooser.lookInLabelMnemonic", l); | |
| lookInLabelText = UIManager.getString("FileChooser.lookInLabelText", l); | |
| saveInLabelText = UIManager.getString("FileChooser.saveInLabelText", l); | |
| fileNameLabelMnemonic = getMnemonic("FileChooser.fileNameLabelMnemonic", l); | |
| fileNameLabelText = UIManager.getString("FileChooser.fileNameLabelText", l); | |
| folderNameLabelMnemonic = getMnemonic("FileChooser.folderNameLabelMnemonic", l); | |
| folderNameLabelText = UIManager.getString("FileChooser.folderNameLabelText", l); | |
| filesOfTypeLabelMnemonic = getMnemonic("FileChooser.filesOfTypeLabelMnemonic", l); | |
| filesOfTypeLabelText = UIManager.getString("FileChooser.filesOfTypeLabelText", l); | |
| upFolderToolTipText = UIManager.getString("FileChooser.upFolderToolTipText",l); | |
| upFolderAccessibleName = UIManager.getString("FileChooser.upFolderAccessibleName",l); | |
| homeFolderToolTipText = UIManager.getString("FileChooser.homeFolderToolTipText",l); | |
| homeFolderAccessibleName = UIManager.getString("FileChooser.homeFolderAccessibleName",l); | |
| newFolderToolTipText = UIManager.getString("FileChooser.newFolderToolTipText",l); | |
| newFolderAccessibleName = UIManager.getString("FileChooser.newFolderAccessibleName",l); | |
| listViewButtonToolTipText = UIManager.getString("FileChooser.listViewButtonToolTipText",l); | |
| listViewButtonAccessibleName = UIManager.getString("FileChooser.listViewButtonAccessibleName",l); | |
| detailsViewButtonToolTipText = UIManager.getString("FileChooser.detailsViewButtonToolTipText",l); | |
| detailsViewButtonAccessibleName = UIManager.getString("FileChooser.detailsViewButtonAccessibleName",l); | |
| } | |
| private int getMnemonic(String key, Locale l) { | |
| return SwingUtilities2.getUIDefaultsInt(key, l); | |
| } | |
| public String getFileName() { | |
| if (fileNameTextField != null) { | |
| return fileNameTextField.getText(); | |
| } else { | |
| return null; | |
| } | |
| } | |
| public void setFileName(String fileName) { | |
| if (fileNameTextField != null) { | |
| fileNameTextField.setText(fileName); | |
| } | |
| } | |
| @Override public void rescanCurrentDirectory(JFileChooser fc) { | |
| filePane.rescanCurrentDirectory(); | |
| } | |
| protected void doSelectedFileChanged(PropertyChangeEvent e) { | |
| super.doSelectedFileChanged(e); | |
| File f = (File) e.getNewValue(); | |
| JFileChooser fc = getFileChooser(); | |
| if (f != null | |
| && ((fc.isFileSelectionEnabled() && !f.isDirectory()) | |
| || (f.isDirectory() && fc.isDirectorySelectionEnabled()))) { | |
| setFileName(fileNameString(f)); | |
| } | |
| } | |
| protected void doSelectedFilesChanged(PropertyChangeEvent e) { | |
| super.doSelectedFilesChanged(e); | |
| File[] files = (File[]) e.getNewValue(); | |
| JFileChooser fc = getFileChooser(); | |
| if (files != null | |
| && files.length > 0 | |
| && (files.length > 1 || fc.isDirectorySelectionEnabled() || !files[0].isDirectory())) { | |
| setFileName(fileNameString(files)); | |
| } | |
| } | |
| protected void doDirectoryChanged(PropertyChangeEvent e) { | |
| super.doDirectoryChanged(e); | |
| JFileChooser fc = getFileChooser(); | |
| FileSystemView fsv = fc.getFileSystemView(); | |
| File currentDirectory = fc.getCurrentDirectory(); | |
| if (!readOnly && currentDirectory != null) { | |
| getNewFolderAction().setEnabled(filePane.canWrite(currentDirectory)); | |
| } | |
| if (currentDirectory != null) { | |
| JComponent cb = getDirectoryComboBox(); | |
| if (cb instanceof JComboBox) { | |
| ComboBoxModel<?> model = ((JComboBox)cb).getModel(); | |
| if (model instanceof DirectoryComboBoxModel) { | |
| ((DirectoryComboBoxModel)model).addItem(currentDirectory); | |
| } | |
| } | |
| if (fc.isDirectorySelectionEnabled() && !fc.isFileSelectionEnabled()) { | |
| if (fsv.isFileSystem(currentDirectory)) { | |
| setFileName(currentDirectory.getPath()); | |
| } else { | |
| setFileName(null); | |
| } | |
| } | |
| } | |
| } | |
| protected void doFileSelectionModeChanged(PropertyChangeEvent e) { | |
| super.doFileSelectionModeChanged(e); | |
| JFileChooser fc = getFileChooser(); | |
| File currentDirectory = fc.getCurrentDirectory(); | |
| if (currentDirectory != null | |
| && fc.isDirectorySelectionEnabled() | |
| && !fc.isFileSelectionEnabled() | |
| && fc.getFileSystemView().isFileSystem(currentDirectory)) { | |
| setFileName(currentDirectory.getPath()); | |
| } else { | |
| setFileName(null); | |
| } | |
| } | |
| protected void doAccessoryChanged(PropertyChangeEvent e) { | |
| if (getAccessoryPanel() != null) { | |
| if (e.getOldValue() != null) { | |
| getAccessoryPanel().remove((JComponent)e.getOldValue()); | |
| } | |
| JComponent accessory = (JComponent)e.getNewValue(); | |
| if (accessory != null) { | |
| getAccessoryPanel().add(accessory, BorderLayout.CENTER); | |
| } | |
| } | |
| } | |
| protected void doControlButtonsChanged(PropertyChangeEvent e) { | |
| super.doControlButtonsChanged(e); | |
| if (getFileChooser().getControlButtonsAreShown()) { | |
| addControlButtons(); | |
| } else { | |
| removeControlButtons(); | |
| } | |
| } | |
| protected void addControlButtons() { | |
| if (bottomPanel != null) { | |
| bottomPanel.add(buttonPanel); | |
| } | |
| } | |
| protected void removeControlButtons() { | |
| if (bottomPanel != null) { | |
| bottomPanel.remove(buttonPanel); | |
| } | |
| } | |
| // ******************************************************* | |
| // ************ FileChooser UI PLAF methods ************** | |
| // ******************************************************* | |
| protected ActionMap createActionMap() { | |
| ActionMap map = new ActionMapUIResource(); | |
| // add standard actions | |
| FilePane.addActionsToMap(map, filePane.getActions()); | |
| // add synth only actions | |
| map.put("fileNameCompletion", getFileNameCompletionAction()); | |
| return map; | |
| } | |
| // ***************************** | |
| // ***** Directory Actions ***** | |
| // ***************************** | |
| protected JComponent getDirectoryComboBox() { | |
| return directoryComboBox; | |
| } | |
| protected Action getDirectoryComboBoxAction() { | |
| return directoryComboBoxAction; | |
| } | |
| protected DirectoryComboBoxRenderer createDirectoryComboBoxRenderer(JFileChooser fc) { | |
| return new DirectoryComboBoxRenderer(directoryComboBox.getRenderer()); | |
| } | |
| // | |
| // Renderer for DirectoryComboBox | |
| // | |
| // Synth has some odd behavior with regards to renderers. Renderers are styled | |
| // in a specific manner by the SynthComboBoxUI. If we extend DefaultListCellRenderer | |
| // here, then we get none of those benefits or behaviors, leading to poor | |
| // looking combo boxes. | |
| // So what we do here is delegate most jobs to the "real" or original renderer, | |
| // and simply monkey with the icon and text of the renderer. | |
| private class DirectoryComboBoxRenderer implements ListCellRenderer<File> { | |
| private ListCellRenderer<? super File> delegate; | |
| IndentIcon ii = new IndentIcon(); | |
| private DirectoryComboBoxRenderer(ListCellRenderer<? super File> delegate) { | |
| this.delegate = delegate; | |
| } | |
| @Override | |
| public Component getListCellRendererComponent(JList<? extends File> list, File value, int index, boolean isSelected, boolean cellHasFocus) { | |
| Component c = delegate.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); | |
| assert c instanceof JLabel; | |
| JLabel label = (JLabel)c; | |
| if (value == null) { | |
| label.setText(""); | |
| return label; | |
| } | |
| label.setText(getFileChooser().getName(value)); | |
| Icon icon = getFileChooser().getIcon(value); | |
| ii.icon = icon; | |
| ii.depth = directoryComboBoxModel.getDepth(index); | |
| label.setIcon(ii); | |
| label.putClientProperty("html.disable", getFileChooser().getClientProperty("html.disable")); | |
| return label; | |
| } | |
| } | |
| static final int space = 10; | |
| static class IndentIcon implements Icon { | |
| Icon icon = null; | |
| int depth = 0; | |
| public void paintIcon(Component c, Graphics g, int x, int y) { | |
| if (icon != null) { | |
| if (c.getComponentOrientation().isLeftToRight()) { | |
| icon.paintIcon(c, g, x+depth*space, y); | |
| } else { | |
| icon.paintIcon(c, g, x, y); | |
| } | |
| } | |
| } | |
| public int getIconWidth() { | |
| return ((icon != null) ? icon.getIconWidth() : 0) + depth*space; | |
| } | |
| public int getIconHeight() { | |
| return (icon != null) ? icon.getIconHeight() : 0; | |
| } | |
| } | |
| // | |
| // DataModel for DirectoryCombobox | |
| // | |
| protected DirectoryComboBoxModel createDirectoryComboBoxModel(JFileChooser fc) { | |
| return new DirectoryComboBoxModel(); | |
| } | |
| /** | |
| * Data model for a type-face selection combo-box. | |
| */ | |
| @SuppressWarnings("serial") // JDK-implementation class | |
| protected class DirectoryComboBoxModel extends AbstractListModel<File> implements ComboBoxModel<File> { | |
| Vector<File> directories = new Vector<File>(); | |
| int[] depths = null; | |
| File selectedDirectory = null; | |
| JFileChooser chooser = getFileChooser(); | |
| FileSystemView fsv = chooser.getFileSystemView(); | |
| public DirectoryComboBoxModel() { | |
| // Add the current directory to the model, and make it the | |
| // selectedDirectory | |
| File dir = getFileChooser().getCurrentDirectory(); | |
| if (dir != null) { | |
| addItem(dir); | |
| } | |
| } | |
| /** | |
| * Adds the directory to the model and sets it to be selected, | |
| * additionally clears out the previous selected directory and | |
| * the paths leading up to it, if any. | |
| */ | |
| public void addItem(File directory) { | |
| if (directory == null) { | |
| return; | |
| } | |
| boolean useShellFolder = FilePane.usesShellFolder(chooser); | |
| int oldSize = directories.size(); | |
| directories.clear(); | |
| if (oldSize > 0) { | |
| fireIntervalRemoved(this, 0, oldSize); | |
| } | |
| File[] baseFolders = (useShellFolder) | |
| ? (File[]) ShellFolder.get("fileChooserComboBoxFolders") | |
| : fsv.getRoots(); | |
| directories.addAll(Arrays.asList(baseFolders)); | |
| // Get the canonical (full) path. This has the side | |
| // benefit of removing extraneous chars from the path, | |
| // for example /foo/bar/ becomes /foo/bar | |
| File canonical; | |
| try { | |
| canonical = ShellFolder.getNormalizedFile(directory); | |
| } catch (IOException e) { | |
| // Maybe drive is not ready. Can't abort here. | |
| canonical = directory; | |
| } | |
| // create File instances of each directory leading up to the top | |
| try { | |
| File sf = useShellFolder ? ShellFolder.getShellFolder(canonical) | |
| : canonical; | |
| File f = sf; | |
| ArrayList<File> path = new ArrayList<File>(10); | |
| do { | |
| path.add(f); | |
| } while ((f = f.getParentFile()) != null); | |
| int pathCount = path.size(); | |
| // Insert chain at appropriate place in vector | |
| for (int i = 0; i < pathCount; i++) { | |
| f = path.get(i); | |
| if (directories.contains(f)) { | |
| int topIndex = directories.indexOf(f); | |
| for (int j = i-1; j >= 0; j--) { | |
| directories.insertElementAt(path.get(j), topIndex+i-j); | |
| } | |
| break; | |
| } | |
| } | |
| calculateDepths(); | |
| setSelectedItem(sf); | |
| } catch (FileNotFoundException ex) { | |
| calculateDepths(); | |
| } | |
| } | |
| private void calculateDepths() { | |
| depths = new int[directories.size()]; | |
| for (int i = 0; i < depths.length; i++) { | |
| File dir = directories.get(i); | |
| File parent = dir.getParentFile(); | |
| depths[i] = 0; | |
| if (parent != null) { | |
| for (int j = i-1; j >= 0; j--) { | |
| if (parent.equals(directories.get(j))) { | |
| depths[i] = depths[j] + 1; | |
| break; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| public int getDepth(int i) { | |
| return (depths != null && i >= 0 && i < depths.length) ? depths[i] : 0; | |
| } | |
| public void setSelectedItem(Object selectedDirectory) { | |
| this.selectedDirectory = (File)selectedDirectory; | |
| fireContentsChanged(this, -1, -1); | |
| } | |
| public Object getSelectedItem() { | |
| return selectedDirectory; | |
| } | |
| public int getSize() { | |
| return directories.size(); | |
| } | |
| public File getElementAt(int index) { | |
| return directories.elementAt(index); | |
| } | |
| } | |
| /** | |
| * Acts when DirectoryComboBox has changed the selected item. | |
| */ | |
| @SuppressWarnings("serial") // JDK-implementation class | |
| protected class DirectoryComboBoxAction extends AbstractAction { | |
| protected DirectoryComboBoxAction() { | |
| super("DirectoryComboBoxAction"); | |
| } | |
| public void actionPerformed(ActionEvent e) { | |
| directoryComboBox.hidePopup(); | |
| JComponent cb = getDirectoryComboBox(); | |
| if (cb instanceof JComboBox) { | |
| File f = (File)((JComboBox)cb).getSelectedItem(); | |
| getFileChooser().setCurrentDirectory(f); | |
| } | |
| } | |
| } | |
| // | |
| // Renderer for Types ComboBox | |
| // | |
| protected FilterComboBoxRenderer createFilterComboBoxRenderer() { | |
| return new FilterComboBoxRenderer(filterComboBox.getRenderer()); | |
| } | |
| /** | |
| * Render different type sizes and styles. | |
| */ | |
| public class FilterComboBoxRenderer implements ListCellRenderer<FileFilter> { | |
| private ListCellRenderer<? super FileFilter> delegate; | |
| private FilterComboBoxRenderer(ListCellRenderer<? super FileFilter> delegate) { | |
| this.delegate = delegate; | |
| } | |
| public Component getListCellRendererComponent(JList<? extends FileFilter> list, FileFilter value, int index, | |
| boolean isSelected, boolean cellHasFocus) { | |
| Component c = delegate.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); | |
| String text = null; | |
| if (value != null) { | |
| text = value.getDescription(); | |
| } | |
| //this should always be true, since SynthComboBoxUI's SynthComboBoxRenderer | |
| //extends JLabel | |
| assert c instanceof JLabel; | |
| if (text != null) { | |
| ((JLabel)c).setText(text); | |
| } | |
| return c; | |
| } | |
| } | |
| // | |
| // DataModel for Types Combobox | |
| // | |
| protected FilterComboBoxModel createFilterComboBoxModel() { | |
| return new FilterComboBoxModel(); | |
| } | |
| /** | |
| * Data model for a type-face selection combo-box. | |
| */ | |
| @SuppressWarnings("serial") // JDK-implementation class | |
| protected class FilterComboBoxModel extends AbstractListModel<FileFilter> implements ComboBoxModel<FileFilter>, | |
| PropertyChangeListener { | |
| protected FileFilter[] filters; | |
| protected FilterComboBoxModel() { | |
| super(); | |
| filters = getFileChooser().getChoosableFileFilters(); | |
| } | |
| public void propertyChange(PropertyChangeEvent e) { | |
| String prop = e.getPropertyName(); | |
| if(prop == JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY) { | |
| filters = (FileFilter[]) e.getNewValue(); | |
| fireContentsChanged(this, -1, -1); | |
| } else if (prop == JFileChooser.FILE_FILTER_CHANGED_PROPERTY) { | |
| fireContentsChanged(this, -1, -1); | |
| } | |
| } | |
| public void setSelectedItem(Object filter) { | |
| if(filter != null) { | |
| getFileChooser().setFileFilter((FileFilter) filter); | |
| fireContentsChanged(this, -1, -1); | |
| } | |
| } | |
| public Object getSelectedItem() { | |
| // Ensure that the current filter is in the list. | |
| // NOTE: we shouldn't have to do this, since JFileChooser adds | |
| // the filter to the choosable filters list when the filter | |
| // is set. Let's be paranoid just in case someone overrides | |
| // setFileFilter in JFileChooser. | |
| FileFilter currentFilter = getFileChooser().getFileFilter(); | |
| boolean found = false; | |
| if(currentFilter != null) { | |
| for (FileFilter filter : filters) { | |
| if (filter == currentFilter) { | |
| found = true; | |
| } | |
| } | |
| if(found == false) { | |
| getFileChooser().addChoosableFileFilter(currentFilter); | |
| } | |
| } | |
| return getFileChooser().getFileFilter(); | |
| } | |
| public int getSize() { | |
| if(filters != null) { | |
| return filters.length; | |
| } else { | |
| return 0; | |
| } | |
| } | |
| public FileFilter getElementAt(int index) { | |
| if(index > getSize() - 1) { | |
| // This shouldn't happen. Try to recover gracefully. | |
| return getFileChooser().getFileFilter(); | |
| } | |
| if(filters != null) { | |
| return filters[index]; | |
| } else { | |
| return null; | |
| } | |
| } | |
| } | |
| /** | |
| * <code>ButtonAreaLayout</code> behaves in a similar manner to | |
| * <code>FlowLayout</code>. It lays out all components from left to | |
| * right, flushed right. The widths of all components will be set | |
| * to the largest preferred size width. | |
| */ | |
| private static class ButtonAreaLayout implements LayoutManager { | |
| private int hGap = 5; | |
| private int topMargin = 17; | |
| public void addLayoutComponent(String string, Component comp) { | |
| } | |
| public void layoutContainer(Container container) { | |
| Component[] children = container.getComponents(); | |
| if (children != null && children.length > 0) { | |
| int numChildren = children.length; | |
| Dimension[] sizes = new Dimension[numChildren]; | |
| Insets insets = container.getInsets(); | |
| int yLocation = insets.top + topMargin; | |
| int maxWidth = 0; | |
| for (int counter = 0; counter < numChildren; counter++) { | |
| sizes[counter] = children[counter].getPreferredSize(); | |
| maxWidth = Math.max(maxWidth, sizes[counter].width); | |
| } | |
| int xLocation, xOffset; | |
| if (container.getComponentOrientation().isLeftToRight()) { | |
| xLocation = container.getSize().width - insets.left - maxWidth; | |
| xOffset = hGap + maxWidth; | |
| } else { | |
| xLocation = insets.left; | |
| xOffset = -(hGap + maxWidth); | |
| } | |
| for (int counter = numChildren - 1; counter >= 0; counter--) { | |
| children[counter].setBounds(xLocation, yLocation, | |
| maxWidth, sizes[counter].height); | |
| xLocation -= xOffset; | |
| } | |
| } | |
| } | |
| public Dimension minimumLayoutSize(Container c) { | |
| if (c != null) { | |
| Component[] children = c.getComponents(); | |
| if (children != null && children.length > 0) { | |
| int numChildren = children.length; | |
| int height = 0; | |
| Insets cInsets = c.getInsets(); | |
| int extraHeight = topMargin + cInsets.top + cInsets.bottom; | |
| int extraWidth = cInsets.left + cInsets.right; | |
| int maxWidth = 0; | |
| for (int counter = 0; counter < numChildren; counter++) { | |
| Dimension aSize = children[counter].getPreferredSize(); | |
| height = Math.max(height, aSize.height); | |
| maxWidth = Math.max(maxWidth, aSize.width); | |
| } | |
| return new Dimension(extraWidth + numChildren * maxWidth + | |
| (numChildren - 1) * hGap, | |
| extraHeight + height); | |
| } | |
| } | |
| return new Dimension(0, 0); | |
| } | |
| public Dimension preferredLayoutSize(Container c) { | |
| return minimumLayoutSize(c); | |
| } | |
| public void removeLayoutComponent(Component c) { } | |
| } | |
| private static void groupLabels(AlignedLabel[] group) { | |
| for (int i = 0; i < group.length; i++) { | |
| group[i].group = group; | |
| } | |
| } | |
| @SuppressWarnings("serial") // JDK-implementation class | |
| private static class AlignedLabel extends JLabel { | |
| private AlignedLabel[] group; | |
| private int maxWidth = 0; | |
| AlignedLabel() { | |
| super(); | |
| setAlignmentX(JComponent.LEFT_ALIGNMENT); | |
| } | |
| AlignedLabel(String text) { | |
| super(text); | |
| setAlignmentX(JComponent.LEFT_ALIGNMENT); | |
| } | |
| public Dimension getPreferredSize() { | |
| Dimension d = super.getPreferredSize(); | |
| // Align the width with all other labels in group. | |
| return new Dimension(getMaxWidth() + 11, d.height); | |
| } | |
| private int getMaxWidth() { | |
| if (maxWidth == 0 && group != null) { | |
| int max = 0; | |
| for (int i = 0; i < group.length; i++) { | |
| max = Math.max(group[i].getSuperPreferredWidth(), max); | |
| } | |
| for (int i = 0; i < group.length; i++) { | |
| group[i].maxWidth = max; | |
| } | |
| } | |
| return maxWidth; | |
| } | |
| private int getSuperPreferredWidth() { | |
| return super.getPreferredSize().width; | |
| } | |
| } | |
| } |