Path: blob/master/src/java.desktop/share/classes/sun/swing/plaf/synth/SynthFileChooserUIImpl.java
41161 views
/*1* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package sun.swing.plaf.synth;2526import java.awt.*;27import java.awt.event.*;28import java.beans.*;29import java.io.*;30import java.util.*;31import java.security.AccessController;32import java.security.PrivilegedAction;3334import javax.swing.*;35import javax.swing.event.*;36import javax.swing.filechooser.*;37import javax.swing.filechooser.FileFilter;38import javax.swing.plaf.basic.*;39import javax.swing.plaf.synth.*;40import javax.swing.plaf.ActionMapUIResource;4142import sun.awt.shell.ShellFolder;43import sun.swing.*;4445/**46* Synth FileChooserUI implementation.47* <p>48* Note that the classes in the com.sun.java.swing.plaf.synth49* package are not50* part of the core Java APIs. They are a part of Sun's JDK and JRE51* distributions. Although other licensees may choose to distribute52* these classes, developers cannot depend on their availability in53* non-Sun implementations. Additionally this API may change in54* incompatible ways between releases. While this class is public, it55* shoud be considered an implementation detail, and subject to change.56*57* @author Leif Samuelsson58* @author Jeff Dinkins59*/60public class SynthFileChooserUIImpl extends SynthFileChooserUI {61private JLabel lookInLabel;62private JComboBox<File> directoryComboBox;63private DirectoryComboBoxModel directoryComboBoxModel;64private Action directoryComboBoxAction = new DirectoryComboBoxAction();6566private FilterComboBoxModel filterComboBoxModel;6768private JTextField fileNameTextField;6970private FilePane filePane;71private JToggleButton listViewButton;72private JToggleButton detailsViewButton;7374private boolean readOnly;7576private JPanel buttonPanel;77private JPanel bottomPanel;7879private JComboBox<FileFilter> filterComboBox;8081private static final Dimension hstrut5 = new Dimension(5, 1);8283private static final Insets shrinkwrap = new Insets(0,0,0,0);8485// Preferred and Minimum sizes for the dialog box86private static Dimension LIST_PREF_SIZE = new Dimension(405, 135);8788// Labels, mnemonics, and tooltips (oh my!)89private int lookInLabelMnemonic = 0;90private String lookInLabelText = null;91private String saveInLabelText = null;9293private int fileNameLabelMnemonic = 0;94private String fileNameLabelText = null;95private int folderNameLabelMnemonic = 0;96private String folderNameLabelText = null;9798private int filesOfTypeLabelMnemonic = 0;99private String filesOfTypeLabelText = null;100101private String upFolderToolTipText = null;102private String upFolderAccessibleName = null;103104private String homeFolderToolTipText = null;105private String homeFolderAccessibleName = null;106107private String newFolderToolTipText = null;108private String newFolderAccessibleName = null;109110private String listViewButtonToolTipText = null;111private String listViewButtonAccessibleName = null;112113private String detailsViewButtonToolTipText = null;114private String detailsViewButtonAccessibleName = null;115116private AlignedLabel fileNameLabel;117private final PropertyChangeListener modeListener = new PropertyChangeListener() {118public void propertyChange(PropertyChangeEvent event) {119if (fileNameLabel != null) {120populateFileNameLabel();121}122}123};124125private void populateFileNameLabel() {126if (getFileChooser().getFileSelectionMode() == JFileChooser.DIRECTORIES_ONLY) {127fileNameLabel.setText(folderNameLabelText);128fileNameLabel.setDisplayedMnemonic(folderNameLabelMnemonic);129} else {130fileNameLabel.setText(fileNameLabelText);131fileNameLabel.setDisplayedMnemonic(fileNameLabelMnemonic);132}133}134135public SynthFileChooserUIImpl(JFileChooser b) {136super(b);137}138139140private class SynthFileChooserUIAccessor implements FilePane.FileChooserUIAccessor {141public JFileChooser getFileChooser() {142return SynthFileChooserUIImpl.this.getFileChooser();143}144145public BasicDirectoryModel getModel() {146return SynthFileChooserUIImpl.this.getModel();147}148149public JPanel createList() {150return null;151}152153public JPanel createDetailsView() {154return null;155}156157public boolean isDirectorySelected() {158return SynthFileChooserUIImpl.this.isDirectorySelected();159}160161public File getDirectory() {162return SynthFileChooserUIImpl.this.getDirectory();163}164165public Action getChangeToParentDirectoryAction() {166return SynthFileChooserUIImpl.this.getChangeToParentDirectoryAction();167}168169public Action getApproveSelectionAction() {170return SynthFileChooserUIImpl.this.getApproveSelectionAction();171}172173public Action getNewFolderAction() {174return SynthFileChooserUIImpl.this.getNewFolderAction();175}176177public MouseListener createDoubleClickListener(JList<?> list) {178return SynthFileChooserUIImpl.this.createDoubleClickListener(getFileChooser(),179list);180}181182public ListSelectionListener createListSelectionListener() {183return SynthFileChooserUIImpl.this.createListSelectionListener(getFileChooser());184}185}186187protected void installDefaults(JFileChooser fc) {188super.installDefaults(fc);189readOnly = UIManager.getBoolean("FileChooser.readOnly");190}191192@SuppressWarnings("serial") // anonymous classes inside193public void installComponents(JFileChooser fc) {194super.installComponents(fc);195196SynthContext context = getContext(fc, ENABLED);197198fc.setLayout(new BorderLayout(0, 11));199200// ********************************* //201// **** Construct the top panel **** //202// ********************************* //203204// Directory manipulation buttons205JPanel topPanel = new JPanel(new BorderLayout(11, 0));206JPanel topButtonPanel = new JPanel();207topButtonPanel.setLayout(new BoxLayout(topButtonPanel, BoxLayout.LINE_AXIS));208topPanel.add(topButtonPanel, BorderLayout.AFTER_LINE_ENDS);209210// Add the top panel to the fileChooser211fc.add(topPanel, BorderLayout.NORTH);212213// ComboBox Label214lookInLabel = new JLabel(lookInLabelText);215lookInLabel.setDisplayedMnemonic(lookInLabelMnemonic);216topPanel.add(lookInLabel, BorderLayout.BEFORE_LINE_BEGINS);217218// CurrentDir ComboBox219directoryComboBox = new JComboBox<File>();220directoryComboBox.getAccessibleContext().setAccessibleDescription(lookInLabelText);221directoryComboBox.putClientProperty( "JComboBox.isTableCellEditor", Boolean.TRUE );222lookInLabel.setLabelFor(directoryComboBox);223directoryComboBoxModel = createDirectoryComboBoxModel(fc);224directoryComboBox.setModel(directoryComboBoxModel);225directoryComboBox.addActionListener(directoryComboBoxAction);226directoryComboBox.setRenderer(createDirectoryComboBoxRenderer(fc));227directoryComboBox.setAlignmentX(JComponent.LEFT_ALIGNMENT);228directoryComboBox.setAlignmentY(JComponent.TOP_ALIGNMENT);229directoryComboBox.setMaximumRowCount(8);230topPanel.add(directoryComboBox, BorderLayout.CENTER);231232filePane = new FilePane(new SynthFileChooserUIAccessor());233fc.addPropertyChangeListener(filePane);234235// Add 'Go Up' to context menu, plus 'Go Home' if on Unix236JPopupMenu contextMenu = filePane.getComponentPopupMenu();237if (contextMenu != null) {238contextMenu.insert(getChangeToParentDirectoryAction(), 0);239if (File.separatorChar == '/') {240contextMenu.insert(getGoHomeAction(), 1);241}242}243244FileSystemView fsv = fc.getFileSystemView();245246// Up Button247JButton upFolderButton = new JButton(getChangeToParentDirectoryAction());248upFolderButton.setText(null);249upFolderButton.setIcon(upFolderIcon);250upFolderButton.setToolTipText(upFolderToolTipText);251upFolderButton.getAccessibleContext().setAccessibleName(upFolderAccessibleName);252upFolderButton.setAlignmentX(JComponent.LEFT_ALIGNMENT);253upFolderButton.setAlignmentY(JComponent.CENTER_ALIGNMENT);254upFolderButton.setMargin(shrinkwrap);255256topButtonPanel.add(upFolderButton);257topButtonPanel.add(Box.createRigidArea(hstrut5));258259// Home Button260File homeDir = fsv.getHomeDirectory();261String toolTipText = homeFolderToolTipText;262263JButton b = new JButton(homeFolderIcon);264b.setToolTipText(toolTipText);265b.getAccessibleContext().setAccessibleName(homeFolderAccessibleName);266b.setAlignmentX(JComponent.LEFT_ALIGNMENT);267b.setAlignmentY(JComponent.CENTER_ALIGNMENT);268b.setMargin(shrinkwrap);269270b.addActionListener(getGoHomeAction());271topButtonPanel.add(b);272topButtonPanel.add(Box.createRigidArea(hstrut5));273274// New Directory Button275if (!readOnly) {276b = new JButton(filePane.getNewFolderAction());277b.setText(null);278b.setIcon(newFolderIcon);279b.setToolTipText(newFolderToolTipText);280b.getAccessibleContext().setAccessibleName(newFolderAccessibleName);281b.setAlignmentX(JComponent.LEFT_ALIGNMENT);282b.setAlignmentY(JComponent.CENTER_ALIGNMENT);283b.setMargin(shrinkwrap);284topButtonPanel.add(b);285topButtonPanel.add(Box.createRigidArea(hstrut5));286}287288// View button group289ButtonGroup viewButtonGroup = new ButtonGroup();290291// List Button292listViewButton = new JToggleButton(listViewIcon);293listViewButton.setToolTipText(listViewButtonToolTipText);294listViewButton.getAccessibleContext().setAccessibleName(listViewButtonAccessibleName);295listViewButton.setSelected(true);296listViewButton.setAlignmentX(JComponent.LEFT_ALIGNMENT);297listViewButton.setAlignmentY(JComponent.CENTER_ALIGNMENT);298listViewButton.setMargin(shrinkwrap);299listViewButton.addActionListener(filePane.getViewTypeAction(FilePane.VIEWTYPE_LIST));300topButtonPanel.add(listViewButton);301viewButtonGroup.add(listViewButton);302303// Details Button304detailsViewButton = new JToggleButton(detailsViewIcon);305detailsViewButton.setToolTipText(detailsViewButtonToolTipText);306detailsViewButton.getAccessibleContext().setAccessibleName(detailsViewButtonAccessibleName);307detailsViewButton.setAlignmentX(JComponent.LEFT_ALIGNMENT);308detailsViewButton.setAlignmentY(JComponent.CENTER_ALIGNMENT);309detailsViewButton.setMargin(shrinkwrap);310detailsViewButton.addActionListener(filePane.getViewTypeAction(FilePane.VIEWTYPE_DETAILS));311topButtonPanel.add(detailsViewButton);312viewButtonGroup.add(detailsViewButton);313314filePane.addPropertyChangeListener(new PropertyChangeListener() {315public void propertyChange(PropertyChangeEvent e) {316if ("viewType".equals(e.getPropertyName())) {317int viewType = filePane.getViewType();318switch (viewType) {319case FilePane.VIEWTYPE_LIST:320listViewButton.setSelected(true);321break;322case FilePane.VIEWTYPE_DETAILS:323detailsViewButton.setSelected(true);324break;325}326}327}328});329330// ************************************** //331// ******* Add the directory pane ******* //332// ************************************** //333fc.add(getAccessoryPanel(), BorderLayout.AFTER_LINE_ENDS);334JComponent accessory = fc.getAccessory();335if (accessory != null) {336getAccessoryPanel().add(accessory);337}338filePane.setPreferredSize(LIST_PREF_SIZE);339fc.add(filePane, BorderLayout.CENTER);340341342// ********************************** //343// **** Construct the bottom panel ** //344// ********************************** //345bottomPanel = new JPanel();346bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.Y_AXIS));347fc.add(bottomPanel, BorderLayout.SOUTH);348349// FileName label and textfield350JPanel fileNamePanel = new JPanel();351fileNamePanel.setLayout(new BoxLayout(fileNamePanel, BoxLayout.LINE_AXIS));352bottomPanel.add(fileNamePanel);353bottomPanel.add(Box.createRigidArea(new Dimension(1, 5)));354355fileNameLabel = new AlignedLabel();356populateFileNameLabel();357fileNamePanel.add(fileNameLabel);358359fileNameTextField = new JTextField(35) {360public Dimension getMaximumSize() {361return new Dimension(Short.MAX_VALUE, super.getPreferredSize().height);362}363};364fileNamePanel.add(fileNameTextField);365fileNameLabel.setLabelFor(fileNameTextField);366fileNameTextField.addFocusListener(367new FocusAdapter() {368public void focusGained(FocusEvent e) {369if (!getFileChooser().isMultiSelectionEnabled()) {370filePane.clearSelection();371}372}373}374);375if (fc.isMultiSelectionEnabled()) {376setFileName(fileNameString(fc.getSelectedFiles()));377} else {378setFileName(fileNameString(fc.getSelectedFile()));379}380381382// Filetype label and combobox383JPanel filesOfTypePanel = new JPanel();384filesOfTypePanel.setLayout(new BoxLayout(filesOfTypePanel, BoxLayout.LINE_AXIS));385bottomPanel.add(filesOfTypePanel);386387AlignedLabel filesOfTypeLabel = new AlignedLabel(filesOfTypeLabelText);388filesOfTypeLabel.setDisplayedMnemonic(filesOfTypeLabelMnemonic);389filesOfTypePanel.add(filesOfTypeLabel);390391filterComboBoxModel = createFilterComboBoxModel();392fc.addPropertyChangeListener(filterComboBoxModel);393filterComboBox = new JComboBox<FileFilter>(filterComboBoxModel);394filterComboBox.getAccessibleContext().setAccessibleDescription(filesOfTypeLabelText);395filesOfTypeLabel.setLabelFor(filterComboBox);396filterComboBox.setRenderer(createFilterComboBoxRenderer());397filesOfTypePanel.add(filterComboBox);398399400// buttons401buttonPanel = new JPanel();402buttonPanel.setLayout(new ButtonAreaLayout());403404buttonPanel.add(getApproveButton(fc));405buttonPanel.add(getCancelButton(fc));406407if (fc.getControlButtonsAreShown()) {408addControlButtons();409}410411groupLabels(new AlignedLabel[] { fileNameLabel, filesOfTypeLabel });412}413414protected void installListeners(JFileChooser fc) {415super.installListeners(fc);416fc.addPropertyChangeListener(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY, modeListener);417}418419protected void uninstallListeners(JFileChooser fc) {420fc.removePropertyChangeListener(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY, modeListener);421super.uninstallListeners(fc);422}423424private String fileNameString(File file) {425if (file == null) {426return null;427} else {428JFileChooser fc = getFileChooser();429if (fc.isDirectorySelectionEnabled() && !fc.isFileSelectionEnabled()) {430return file.getPath();431} else {432return file.getName();433}434}435}436437private String fileNameString(File[] files) {438StringBuilder sb = new StringBuilder();439for (int i = 0; files != null && i < files.length; i++) {440if (i > 0) {441sb.append(" ");442}443if (files.length > 1) {444sb.append("\"");445}446sb.append(fileNameString(files[i]));447if (files.length > 1) {448sb.append("\"");449}450}451return sb.toString();452}453454public void uninstallUI(JComponent c) {455// Remove listeners456c.removePropertyChangeListener(filterComboBoxModel);457c.removePropertyChangeListener(filePane);458459if (filePane != null) {460filePane.uninstallUI();461filePane = null;462}463464super.uninstallUI(c);465}466467protected void installStrings(JFileChooser fc) {468super.installStrings(fc);469470Locale l = fc.getLocale();471472lookInLabelMnemonic = getMnemonic("FileChooser.lookInLabelMnemonic", l);473lookInLabelText = UIManager.getString("FileChooser.lookInLabelText", l);474saveInLabelText = UIManager.getString("FileChooser.saveInLabelText", l);475476fileNameLabelMnemonic = getMnemonic("FileChooser.fileNameLabelMnemonic", l);477fileNameLabelText = UIManager.getString("FileChooser.fileNameLabelText", l);478folderNameLabelMnemonic = getMnemonic("FileChooser.folderNameLabelMnemonic", l);479folderNameLabelText = UIManager.getString("FileChooser.folderNameLabelText", l);480481filesOfTypeLabelMnemonic = getMnemonic("FileChooser.filesOfTypeLabelMnemonic", l);482filesOfTypeLabelText = UIManager.getString("FileChooser.filesOfTypeLabelText", l);483484upFolderToolTipText = UIManager.getString("FileChooser.upFolderToolTipText",l);485upFolderAccessibleName = UIManager.getString("FileChooser.upFolderAccessibleName",l);486487homeFolderToolTipText = UIManager.getString("FileChooser.homeFolderToolTipText",l);488homeFolderAccessibleName = UIManager.getString("FileChooser.homeFolderAccessibleName",l);489490newFolderToolTipText = UIManager.getString("FileChooser.newFolderToolTipText",l);491newFolderAccessibleName = UIManager.getString("FileChooser.newFolderAccessibleName",l);492493listViewButtonToolTipText = UIManager.getString("FileChooser.listViewButtonToolTipText",l);494listViewButtonAccessibleName = UIManager.getString("FileChooser.listViewButtonAccessibleName",l);495496detailsViewButtonToolTipText = UIManager.getString("FileChooser.detailsViewButtonToolTipText",l);497detailsViewButtonAccessibleName = UIManager.getString("FileChooser.detailsViewButtonAccessibleName",l);498}499500private int getMnemonic(String key, Locale l) {501return SwingUtilities2.getUIDefaultsInt(key, l);502}503504505public String getFileName() {506if (fileNameTextField != null) {507return fileNameTextField.getText();508} else {509return null;510}511}512513public void setFileName(String fileName) {514if (fileNameTextField != null) {515fileNameTextField.setText(fileName);516}517}518519@Override public void rescanCurrentDirectory(JFileChooser fc) {520filePane.rescanCurrentDirectory();521}522523protected void doSelectedFileChanged(PropertyChangeEvent e) {524super.doSelectedFileChanged(e);525526File f = (File) e.getNewValue();527JFileChooser fc = getFileChooser();528if (f != null529&& ((fc.isFileSelectionEnabled() && !f.isDirectory())530|| (f.isDirectory() && fc.isDirectorySelectionEnabled()))) {531532setFileName(fileNameString(f));533}534}535536protected void doSelectedFilesChanged(PropertyChangeEvent e) {537super.doSelectedFilesChanged(e);538539File[] files = (File[]) e.getNewValue();540JFileChooser fc = getFileChooser();541if (files != null542&& files.length > 0543&& (files.length > 1 || fc.isDirectorySelectionEnabled() || !files[0].isDirectory())) {544setFileName(fileNameString(files));545}546}547548protected void doDirectoryChanged(PropertyChangeEvent e) {549super.doDirectoryChanged(e);550551JFileChooser fc = getFileChooser();552FileSystemView fsv = fc.getFileSystemView();553File currentDirectory = fc.getCurrentDirectory();554555if (!readOnly && currentDirectory != null) {556getNewFolderAction().setEnabled(filePane.canWrite(currentDirectory));557}558559if (currentDirectory != null) {560JComponent cb = getDirectoryComboBox();561if (cb instanceof JComboBox) {562ComboBoxModel<?> model = ((JComboBox)cb).getModel();563if (model instanceof DirectoryComboBoxModel) {564((DirectoryComboBoxModel)model).addItem(currentDirectory);565}566}567568if (fc.isDirectorySelectionEnabled() && !fc.isFileSelectionEnabled()) {569if (fsv.isFileSystem(currentDirectory)) {570setFileName(currentDirectory.getPath());571} else {572setFileName(null);573}574}575}576}577578579protected void doFileSelectionModeChanged(PropertyChangeEvent e) {580super.doFileSelectionModeChanged(e);581582JFileChooser fc = getFileChooser();583File currentDirectory = fc.getCurrentDirectory();584if (currentDirectory != null585&& fc.isDirectorySelectionEnabled()586&& !fc.isFileSelectionEnabled()587&& fc.getFileSystemView().isFileSystem(currentDirectory)) {588589setFileName(currentDirectory.getPath());590} else {591setFileName(null);592}593}594595protected void doAccessoryChanged(PropertyChangeEvent e) {596if (getAccessoryPanel() != null) {597if (e.getOldValue() != null) {598getAccessoryPanel().remove((JComponent)e.getOldValue());599}600JComponent accessory = (JComponent)e.getNewValue();601if (accessory != null) {602getAccessoryPanel().add(accessory, BorderLayout.CENTER);603}604}605}606607protected void doControlButtonsChanged(PropertyChangeEvent e) {608super.doControlButtonsChanged(e);609610if (getFileChooser().getControlButtonsAreShown()) {611addControlButtons();612} else {613removeControlButtons();614}615}616617protected void addControlButtons() {618if (bottomPanel != null) {619bottomPanel.add(buttonPanel);620}621}622623protected void removeControlButtons() {624if (bottomPanel != null) {625bottomPanel.remove(buttonPanel);626}627}628629630631632// *******************************************************633// ************ FileChooser UI PLAF methods **************634// *******************************************************635636protected ActionMap createActionMap() {637ActionMap map = new ActionMapUIResource();638// add standard actions639FilePane.addActionsToMap(map, filePane.getActions());640// add synth only actions641map.put("fileNameCompletion", getFileNameCompletionAction());642return map;643}644645// *****************************646// ***** Directory Actions *****647// *****************************648649protected JComponent getDirectoryComboBox() {650return directoryComboBox;651}652653protected Action getDirectoryComboBoxAction() {654return directoryComboBoxAction;655}656657protected DirectoryComboBoxRenderer createDirectoryComboBoxRenderer(JFileChooser fc) {658return new DirectoryComboBoxRenderer(directoryComboBox.getRenderer());659}660661//662// Renderer for DirectoryComboBox663//664// Synth has some odd behavior with regards to renderers. Renderers are styled665// in a specific manner by the SynthComboBoxUI. If we extend DefaultListCellRenderer666// here, then we get none of those benefits or behaviors, leading to poor667// looking combo boxes.668// So what we do here is delegate most jobs to the "real" or original renderer,669// and simply monkey with the icon and text of the renderer.670private class DirectoryComboBoxRenderer implements ListCellRenderer<File> {671private ListCellRenderer<? super File> delegate;672IndentIcon ii = new IndentIcon();673674private DirectoryComboBoxRenderer(ListCellRenderer<? super File> delegate) {675this.delegate = delegate;676}677678@Override679public Component getListCellRendererComponent(JList<? extends File> list, File value, int index, boolean isSelected, boolean cellHasFocus) {680Component c = delegate.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);681682assert c instanceof JLabel;683JLabel label = (JLabel)c;684if (value == null) {685label.setText("");686return label;687}688label.setText(getFileChooser().getName(value));689Icon icon = getFileChooser().getIcon(value);690ii.icon = icon;691ii.depth = directoryComboBoxModel.getDepth(index);692label.setIcon(ii);693694return label;695}696}697698static final int space = 10;699class IndentIcon implements Icon {700701Icon icon = null;702int depth = 0;703704public void paintIcon(Component c, Graphics g, int x, int y) {705if (icon != null) {706if (c.getComponentOrientation().isLeftToRight()) {707icon.paintIcon(c, g, x+depth*space, y);708} else {709icon.paintIcon(c, g, x, y);710}711}712}713714public int getIconWidth() {715return ((icon != null) ? icon.getIconWidth() : 0) + depth*space;716}717718public int getIconHeight() {719return (icon != null) ? icon.getIconHeight() : 0;720}721722}723724//725// DataModel for DirectoryComboxbox726//727protected DirectoryComboBoxModel createDirectoryComboBoxModel(JFileChooser fc) {728return new DirectoryComboBoxModel();729}730731/**732* Data model for a type-face selection combo-box.733*/734@SuppressWarnings("serial") // JDK-implementation class735protected class DirectoryComboBoxModel extends AbstractListModel<File> implements ComboBoxModel<File> {736Vector<File> directories = new Vector<File>();737int[] depths = null;738File selectedDirectory = null;739JFileChooser chooser = getFileChooser();740FileSystemView fsv = chooser.getFileSystemView();741742public DirectoryComboBoxModel() {743// Add the current directory to the model, and make it the744// selectedDirectory745File dir = getFileChooser().getCurrentDirectory();746if (dir != null) {747addItem(dir);748}749}750751/**752* Adds the directory to the model and sets it to be selected,753* additionally clears out the previous selected directory and754* the paths leading up to it, if any.755*/756public void addItem(File directory) {757758if (directory == null) {759return;760}761762boolean useShellFolder = FilePane.usesShellFolder(chooser);763764int oldSize = directories.size();765directories.clear();766if (oldSize > 0) {767fireIntervalRemoved(this, 0, oldSize);768}769770File[] baseFolders = (useShellFolder)771? (File[]) ShellFolder.get("fileChooserComboBoxFolders")772: fsv.getRoots();773directories.addAll(Arrays.asList(baseFolders));774775// Get the canonical (full) path. This has the side776// benefit of removing extraneous chars from the path,777// for example /foo/bar/ becomes /foo/bar778File canonical;779try {780canonical = ShellFolder.getNormalizedFile(directory);781} catch (IOException e) {782// Maybe drive is not ready. Can't abort here.783canonical = directory;784}785786// create File instances of each directory leading up to the top787try {788File sf = useShellFolder ? ShellFolder.getShellFolder(canonical)789: canonical;790File f = sf;791Vector<File> path = new Vector<File>(10);792do {793path.addElement(f);794} while ((f = f.getParentFile()) != null);795796int pathCount = path.size();797// Insert chain at appropriate place in vector798for (int i = 0; i < pathCount; i++) {799f = path.get(i);800if (directories.contains(f)) {801int topIndex = directories.indexOf(f);802for (int j = i-1; j >= 0; j--) {803directories.insertElementAt(path.get(j), topIndex+i-j);804}805break;806}807}808calculateDepths();809setSelectedItem(sf);810} catch (FileNotFoundException ex) {811calculateDepths();812}813}814815private void calculateDepths() {816depths = new int[directories.size()];817for (int i = 0; i < depths.length; i++) {818File dir = directories.get(i);819File parent = dir.getParentFile();820depths[i] = 0;821if (parent != null) {822for (int j = i-1; j >= 0; j--) {823if (parent.equals(directories.get(j))) {824depths[i] = depths[j] + 1;825break;826}827}828}829}830}831832public int getDepth(int i) {833return (depths != null && i >= 0 && i < depths.length) ? depths[i] : 0;834}835836public void setSelectedItem(Object selectedDirectory) {837this.selectedDirectory = (File)selectedDirectory;838fireContentsChanged(this, -1, -1);839}840841public Object getSelectedItem() {842return selectedDirectory;843}844845public int getSize() {846return directories.size();847}848849public File getElementAt(int index) {850return directories.elementAt(index);851}852}853854/**855* Acts when DirectoryComboBox has changed the selected item.856*/857@SuppressWarnings("serial") // JDK-implementation class858protected class DirectoryComboBoxAction extends AbstractAction {859protected DirectoryComboBoxAction() {860super("DirectoryComboBoxAction");861}862863public void actionPerformed(ActionEvent e) {864directoryComboBox.hidePopup();865JComponent cb = getDirectoryComboBox();866if (cb instanceof JComboBox) {867File f = (File)((JComboBox)cb).getSelectedItem();868getFileChooser().setCurrentDirectory(f);869}870}871}872873//874// Renderer for Types ComboBox875//876protected FilterComboBoxRenderer createFilterComboBoxRenderer() {877return new FilterComboBoxRenderer(filterComboBox.getRenderer());878}879880/**881* Render different type sizes and styles.882*/883public class FilterComboBoxRenderer implements ListCellRenderer<FileFilter> {884private ListCellRenderer<? super FileFilter> delegate;885private FilterComboBoxRenderer(ListCellRenderer<? super FileFilter> delegate) {886this.delegate = delegate;887}888889public Component getListCellRendererComponent(JList<? extends FileFilter> list, FileFilter value, int index,890boolean isSelected, boolean cellHasFocus) {891Component c = delegate.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);892893String text = null;894if (value != null) {895text = value.getDescription();896}897898//this should always be true, since SynthComboBoxUI's SynthComboBoxRenderer899//extends JLabel900assert c instanceof JLabel;901if (text != null) {902((JLabel)c).setText(text);903}904return c;905}906}907908//909// DataModel for Types Comboxbox910//911protected FilterComboBoxModel createFilterComboBoxModel() {912return new FilterComboBoxModel();913}914915/**916* Data model for a type-face selection combo-box.917*/918@SuppressWarnings("serial") // JDK-implementation class919protected class FilterComboBoxModel extends AbstractListModel<FileFilter> implements ComboBoxModel<FileFilter>,920PropertyChangeListener {921protected FileFilter[] filters;922protected FilterComboBoxModel() {923super();924filters = getFileChooser().getChoosableFileFilters();925}926927public void propertyChange(PropertyChangeEvent e) {928String prop = e.getPropertyName();929if(prop == JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY) {930filters = (FileFilter[]) e.getNewValue();931fireContentsChanged(this, -1, -1);932} else if (prop == JFileChooser.FILE_FILTER_CHANGED_PROPERTY) {933fireContentsChanged(this, -1, -1);934}935}936937public void setSelectedItem(Object filter) {938if(filter != null) {939getFileChooser().setFileFilter((FileFilter) filter);940fireContentsChanged(this, -1, -1);941}942}943944public Object getSelectedItem() {945// Ensure that the current filter is in the list.946// NOTE: we shouldnt' have to do this, since JFileChooser adds947// the filter to the choosable filters list when the filter948// is set. Lets be paranoid just in case someone overrides949// setFileFilter in JFileChooser.950FileFilter currentFilter = getFileChooser().getFileFilter();951boolean found = false;952if(currentFilter != null) {953for (FileFilter filter : filters) {954if (filter == currentFilter) {955found = true;956}957}958if(found == false) {959getFileChooser().addChoosableFileFilter(currentFilter);960}961}962return getFileChooser().getFileFilter();963}964965public int getSize() {966if(filters != null) {967return filters.length;968} else {969return 0;970}971}972973public FileFilter getElementAt(int index) {974if(index > getSize() - 1) {975// This shouldn't happen. Try to recover gracefully.976return getFileChooser().getFileFilter();977}978if(filters != null) {979return filters[index];980} else {981return null;982}983}984}985986987988/**989* <code>ButtonAreaLayout</code> behaves in a similar manner to990* <code>FlowLayout</code>. It lays out all components from left to991* right, flushed right. The widths of all components will be set992* to the largest preferred size width.993*/994private static class ButtonAreaLayout implements LayoutManager {995private int hGap = 5;996private int topMargin = 17;997998public void addLayoutComponent(String string, Component comp) {999}10001001public void layoutContainer(Container container) {1002Component[] children = container.getComponents();10031004if (children != null && children.length > 0) {1005int numChildren = children.length;1006Dimension[] sizes = new Dimension[numChildren];1007Insets insets = container.getInsets();1008int yLocation = insets.top + topMargin;1009int maxWidth = 0;10101011for (int counter = 0; counter < numChildren; counter++) {1012sizes[counter] = children[counter].getPreferredSize();1013maxWidth = Math.max(maxWidth, sizes[counter].width);1014}1015int xLocation, xOffset;1016if (container.getComponentOrientation().isLeftToRight()) {1017xLocation = container.getSize().width - insets.left - maxWidth;1018xOffset = hGap + maxWidth;1019} else {1020xLocation = insets.left;1021xOffset = -(hGap + maxWidth);1022}1023for (int counter = numChildren - 1; counter >= 0; counter--) {1024children[counter].setBounds(xLocation, yLocation,1025maxWidth, sizes[counter].height);1026xLocation -= xOffset;1027}1028}1029}10301031public Dimension minimumLayoutSize(Container c) {1032if (c != null) {1033Component[] children = c.getComponents();10341035if (children != null && children.length > 0) {1036int numChildren = children.length;1037int height = 0;1038Insets cInsets = c.getInsets();1039int extraHeight = topMargin + cInsets.top + cInsets.bottom;1040int extraWidth = cInsets.left + cInsets.right;1041int maxWidth = 0;10421043for (int counter = 0; counter < numChildren; counter++) {1044Dimension aSize = children[counter].getPreferredSize();1045height = Math.max(height, aSize.height);1046maxWidth = Math.max(maxWidth, aSize.width);1047}1048return new Dimension(extraWidth + numChildren * maxWidth +1049(numChildren - 1) * hGap,1050extraHeight + height);1051}1052}1053return new Dimension(0, 0);1054}10551056public Dimension preferredLayoutSize(Container c) {1057return minimumLayoutSize(c);1058}10591060public void removeLayoutComponent(Component c) { }1061}10621063private static void groupLabels(AlignedLabel[] group) {1064for (int i = 0; i < group.length; i++) {1065group[i].group = group;1066}1067}10681069@SuppressWarnings("serial") // JDK-implementation class1070private class AlignedLabel extends JLabel {1071private AlignedLabel[] group;1072private int maxWidth = 0;10731074AlignedLabel() {1075super();1076setAlignmentX(JComponent.LEFT_ALIGNMENT);1077}10781079AlignedLabel(String text) {1080super(text);1081setAlignmentX(JComponent.LEFT_ALIGNMENT);1082}10831084public Dimension getPreferredSize() {1085Dimension d = super.getPreferredSize();1086// Align the width with all other labels in group.1087return new Dimension(getMaxWidth() + 11, d.height);1088}10891090private int getMaxWidth() {1091if (maxWidth == 0 && group != null) {1092int max = 0;1093for (int i = 0; i < group.length; i++) {1094max = Math.max(group[i].getSuperPreferredWidth(), max);1095}1096for (int i = 0; i < group.length; i++) {1097group[i].maxWidth = max;1098}1099}1100return maxWidth;1101}11021103private int getSuperPreferredWidth() {1104return super.getPreferredSize().width;1105}1106}1107}110811091110