/*
* Copyright (c) 2003, 2010, 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 java.security.AccessController;
import java.security.PrivilegedAction;
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
* shoud 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 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 filterComboBox;
private static final Dimension hstrut5 = new Dimension(5, 1);
private static final Dimension vstrut5 = new Dimension(1, 5);
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();
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;
if (fsv.isRoot(homeDir)) {
toolTipText = getFileView(fc).getName(homeDir); // Probably "Desktop".
}
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(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) {
StringBuffer buf = new StringBuffer();
for (int i = 0; files != null && i < files.length; i++) {
if (i > 0) {
buf.append(" ");
}
if (files.length > 1) {
buf.append("\"");
}
buf.append(fileNameString(files[i]));
if (files.length > 1) {
buf.append("\"");
}
}
return buf.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 {
private ListCellRenderer delegate;
IndentIcon ii = new IndentIcon();
private DirectoryComboBoxRenderer(ListCellRenderer delegate) {
this.delegate = delegate;
}
@Override
public Component getListCellRendererComponent(JList list, Object 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;
}
File directory = (File) value;
label.setText(getFileChooser().getName(directory));
Icon icon = getFileChooser().getIcon(directory);
ii.icon = icon;
ii.depth = directoryComboBoxModel.getDepth(index);
label.setIcon(ii);
return label;
}
}
final static int space = 10;
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 DirectoryComboxbox
//
protected DirectoryComboBoxModel createDirectoryComboBoxModel(JFileChooser fc) {
return new DirectoryComboBoxModel();
}
/**
* Data model for a type-face selection combo-box.
*/
protected class DirectoryComboBoxModel extends AbstractListModel implements ComboBoxModel {
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;
if (useShellFolder) {
baseFolders = AccessController.doPrivileged(new PrivilegedAction<File[]>() {
public File[] run() {
return (File[]) ShellFolder.get("fileChooserComboBoxFolders");
}
});
} else {
baseFolders = 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;
Vector<File> path = new Vector<File>(10);
do {
path.addElement(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 Object getElementAt(int index) {
return directories.elementAt(index);
}
}
/**
* Acts when DirectoryComboBox has changed the selected item.
*/
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 {
private ListCellRenderer delegate;
private FilterComboBoxRenderer(ListCellRenderer delegate) {
this.delegate = delegate;
}
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Component c = delegate.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
String text = null;
if (value != null && value instanceof FileFilter) {
text = ((FileFilter) 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 Comboxbox
//
protected FilterComboBoxModel createFilterComboBoxModel() {
return new FilterComboBoxModel();
}
/**
* Data model for a type-face selection combo-box.
*/
protected class FilterComboBoxModel extends AbstractListModel implements ComboBoxModel, 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 shouldnt' have to do this, since JFileChooser adds
// the filter to the choosable filters list when the filter
// is set. Lets 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 Object 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;
}
}
private 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;
}
}
}