0001 /*
0002 * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025
0026 package javax.swing.plaf.basic;
0027
0028 import javax.swing.*;
0029 import javax.swing.filechooser.*;
0030 import javax.swing.filechooser.FileFilter;
0031 import javax.swing.event.*;
0032 import javax.swing.plaf.*;
0033 import java.awt.*;
0034 import java.awt.event.*;
0035 import java.awt.datatransfer.*;
0036 import java.beans.*;
0037 import java.io.*;
0038 import java.util.*;
0039 import java.util.regex.*;
0040 import sun.awt.shell.ShellFolder;
0041 import sun.swing.*;
0042 import sun.swing.SwingUtilities2;
0043
0044 /**
0045 * Basic L&F implementation of a FileChooser.
0046 *
0047 * @version %i% %g%
0048 * @author Jeff Dinkins
0049 */
0050 public class BasicFileChooserUI extends FileChooserUI {
0051
0052 /* FileView icons */
0053 protected Icon directoryIcon = null;
0054 protected Icon fileIcon = null;
0055 protected Icon computerIcon = null;
0056 protected Icon hardDriveIcon = null;
0057 protected Icon floppyDriveIcon = null;
0058
0059 protected Icon newFolderIcon = null;
0060 protected Icon upFolderIcon = null;
0061 protected Icon homeFolderIcon = null;
0062 protected Icon listViewIcon = null;
0063 protected Icon detailsViewIcon = null;
0064 protected Icon viewMenuIcon = null;
0065
0066 protected int saveButtonMnemonic = 0;
0067 protected int openButtonMnemonic = 0;
0068 protected int cancelButtonMnemonic = 0;
0069 protected int updateButtonMnemonic = 0;
0070 protected int helpButtonMnemonic = 0;
0071
0072 /**
0073 * The mnemonic keycode used for the approve button when a directory
0074 * is selected and the current selection mode is FILES_ONLY.
0075 *
0076 * @since 1.4
0077 */
0078 protected int directoryOpenButtonMnemonic = 0;
0079
0080 protected String saveButtonText = null;
0081 protected String openButtonText = null;
0082 protected String cancelButtonText = null;
0083 protected String updateButtonText = null;
0084 protected String helpButtonText = null;
0085
0086 /**
0087 * The label text displayed on the approve button when a directory
0088 * is selected and the current selection mode is FILES_ONLY.
0089 *
0090 * @since 1.4
0091 */
0092 protected String directoryOpenButtonText = null;
0093
0094 private String openDialogTitleText = null;
0095 private String saveDialogTitleText = null;
0096
0097 protected String saveButtonToolTipText = null;
0098 protected String openButtonToolTipText = null;
0099 protected String cancelButtonToolTipText = null;
0100 protected String updateButtonToolTipText = null;
0101 protected String helpButtonToolTipText = null;
0102
0103 /**
0104 * The tooltip text displayed on the approve button when a directory
0105 * is selected and the current selection mode is FILES_ONLY.
0106 *
0107 * @since 1.4
0108 */
0109 protected String directoryOpenButtonToolTipText = null;
0110
0111 // Some generic FileChooser functions
0112 private Action approveSelectionAction = new ApproveSelectionAction();
0113 private Action cancelSelectionAction = new CancelSelectionAction();
0114 private Action updateAction = new UpdateAction();
0115 private Action newFolderAction;
0116 private Action goHomeAction = new GoHomeAction();
0117 private Action changeToParentDirectoryAction = new ChangeToParentDirectoryAction();
0118
0119 private String newFolderErrorSeparator = null;
0120 private String newFolderErrorText = null;
0121 private String fileDescriptionText = null;
0122 private String directoryDescriptionText = null;
0123
0124 private JFileChooser filechooser = null;
0125
0126 private boolean directorySelected = false;
0127 private File directory = null;
0128
0129 private PropertyChangeListener propertyChangeListener = null;
0130 private AcceptAllFileFilter acceptAllFileFilter = new AcceptAllFileFilter();
0131 private FileFilter actualFileFilter = null;
0132 private GlobFilter globFilter = null;
0133 private BasicDirectoryModel model = null;
0134 private BasicFileView fileView = new BasicFileView();
0135 private boolean usesSingleFilePane;
0136 private boolean readOnly;
0137
0138 // The accessoryPanel is a container to place the JFileChooser accessory component
0139 private JPanel accessoryPanel = null;
0140 private Handler handler;
0141
0142 public BasicFileChooserUI(JFileChooser b) {
0143 }
0144
0145 public void installUI(JComponent c) {
0146 accessoryPanel = new JPanel(new BorderLayout());
0147 filechooser = (JFileChooser) c;
0148
0149 createModel();
0150
0151 clearIconCache();
0152
0153 installDefaults(filechooser);
0154 installComponents(filechooser);
0155 installListeners(filechooser);
0156 filechooser.applyComponentOrientation(filechooser
0157 .getComponentOrientation());
0158 }
0159
0160 public void uninstallUI(JComponent c) {
0161 uninstallListeners((JFileChooser) filechooser);
0162 uninstallComponents((JFileChooser) filechooser);
0163 uninstallDefaults((JFileChooser) filechooser);
0164
0165 if (accessoryPanel != null) {
0166 accessoryPanel.removeAll();
0167 }
0168
0169 accessoryPanel = null;
0170 getFileChooser().removeAll();
0171
0172 handler = null;
0173 }
0174
0175 public void installComponents(JFileChooser fc) {
0176 }
0177
0178 public void uninstallComponents(JFileChooser fc) {
0179 }
0180
0181 protected void installListeners(JFileChooser fc) {
0182 propertyChangeListener = createPropertyChangeListener(fc);
0183 if (propertyChangeListener != null) {
0184 fc.addPropertyChangeListener(propertyChangeListener);
0185 }
0186 fc.addPropertyChangeListener(getModel());
0187
0188 InputMap inputMap = getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
0189 SwingUtilities
0190 .replaceUIInputMap(fc,
0191 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
0192 inputMap);
0193 ActionMap actionMap = getActionMap();
0194 SwingUtilities.replaceUIActionMap(fc, actionMap);
0195 }
0196
0197 InputMap getInputMap(int condition) {
0198 if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
0199 return (InputMap) DefaultLookup.get(getFileChooser(), this ,
0200 "FileChooser.ancestorInputMap");
0201 }
0202 return null;
0203 }
0204
0205 ActionMap getActionMap() {
0206 return createActionMap();
0207 }
0208
0209 ActionMap createActionMap() {
0210 ActionMap map = new ActionMapUIResource();
0211
0212 Action refreshAction = new UIAction(FilePane.ACTION_REFRESH) {
0213 public void actionPerformed(ActionEvent evt) {
0214 getFileChooser().rescanCurrentDirectory();
0215 }
0216 };
0217
0218 map.put(FilePane.ACTION_APPROVE_SELECTION,
0219 getApproveSelectionAction());
0220 map.put(FilePane.ACTION_CANCEL, getCancelSelectionAction());
0221 map.put(FilePane.ACTION_REFRESH, refreshAction);
0222 map.put(FilePane.ACTION_CHANGE_TO_PARENT_DIRECTORY,
0223 getChangeToParentDirectoryAction());
0224 return map;
0225 }
0226
0227 protected void uninstallListeners(JFileChooser fc) {
0228 if (propertyChangeListener != null) {
0229 fc.removePropertyChangeListener(propertyChangeListener);
0230 }
0231 fc.removePropertyChangeListener(getModel());
0232 SwingUtilities.replaceUIInputMap(fc,
0233 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
0234 SwingUtilities.replaceUIActionMap(fc, null);
0235 }
0236
0237 protected void installDefaults(JFileChooser fc) {
0238 installIcons(fc);
0239 installStrings(fc);
0240 usesSingleFilePane = UIManager
0241 .getBoolean("FileChooser.usesSingleFilePane");
0242 readOnly = UIManager.getBoolean("FileChooser.readOnly");
0243 TransferHandler th = fc.getTransferHandler();
0244 if (th == null || th instanceof UIResource) {
0245 fc.setTransferHandler(defaultTransferHandler);
0246 }
0247 LookAndFeel.installProperty(fc, "opaque", Boolean.FALSE);
0248 }
0249
0250 protected void installIcons(JFileChooser fc) {
0251 directoryIcon = UIManager.getIcon("FileView.directoryIcon");
0252 fileIcon = UIManager.getIcon("FileView.fileIcon");
0253 computerIcon = UIManager.getIcon("FileView.computerIcon");
0254 hardDriveIcon = UIManager.getIcon("FileView.hardDriveIcon");
0255 floppyDriveIcon = UIManager.getIcon("FileView.floppyDriveIcon");
0256
0257 newFolderIcon = UIManager.getIcon("FileChooser.newFolderIcon");
0258 upFolderIcon = UIManager.getIcon("FileChooser.upFolderIcon");
0259 homeFolderIcon = UIManager
0260 .getIcon("FileChooser.homeFolderIcon");
0261 detailsViewIcon = UIManager
0262 .getIcon("FileChooser.detailsViewIcon");
0263 listViewIcon = UIManager.getIcon("FileChooser.listViewIcon");
0264 viewMenuIcon = UIManager.getIcon("FileChooser.viewMenuIcon");
0265 }
0266
0267 protected void installStrings(JFileChooser fc) {
0268
0269 Locale l = fc.getLocale();
0270 newFolderErrorText = UIManager.getString(
0271 "FileChooser.newFolderErrorText", l);
0272 newFolderErrorSeparator = UIManager.getString(
0273 "FileChooser.newFolderErrorSeparator", l);
0274
0275 fileDescriptionText = UIManager.getString(
0276 "FileChooser.fileDescriptionText", l);
0277 directoryDescriptionText = UIManager.getString(
0278 "FileChooser.directoryDescriptionText", l);
0279
0280 saveButtonText = UIManager.getString(
0281 "FileChooser.saveButtonText", l);
0282 openButtonText = UIManager.getString(
0283 "FileChooser.openButtonText", l);
0284 saveDialogTitleText = UIManager.getString(
0285 "FileChooser.saveDialogTitleText", l);
0286 openDialogTitleText = UIManager.getString(
0287 "FileChooser.openDialogTitleText", l);
0288 cancelButtonText = UIManager.getString(
0289 "FileChooser.cancelButtonText", l);
0290 updateButtonText = UIManager.getString(
0291 "FileChooser.updateButtonText", l);
0292 helpButtonText = UIManager.getString(
0293 "FileChooser.helpButtonText", l);
0294 directoryOpenButtonText = UIManager.getString(
0295 "FileChooser.directoryOpenButtonText", l);
0296
0297 saveButtonMnemonic = getMnemonic(
0298 "FileChooser.saveButtonMnemonic", l);
0299 openButtonMnemonic = getMnemonic(
0300 "FileChooser.openButtonMnemonic", l);
0301 cancelButtonMnemonic = getMnemonic(
0302 "FileChooser.cancelButtonMnemonic", l);
0303 updateButtonMnemonic = getMnemonic(
0304 "FileChooser.updateButtonMnemonic", l);
0305 helpButtonMnemonic = getMnemonic(
0306 "FileChooser.helpButtonMnemonic", l);
0307 directoryOpenButtonMnemonic = getMnemonic(
0308 "FileChooser.directoryOpenButtonMnemonic", l);
0309
0310 saveButtonToolTipText = UIManager.getString(
0311 "FileChooser.saveButtonToolTipText", l);
0312 openButtonToolTipText = UIManager.getString(
0313 "FileChooser.openButtonToolTipText", l);
0314 cancelButtonToolTipText = UIManager.getString(
0315 "FileChooser.cancelButtonToolTipText", l);
0316 updateButtonToolTipText = UIManager.getString(
0317 "FileChooser.updateButtonToolTipText", l);
0318 helpButtonToolTipText = UIManager.getString(
0319 "FileChooser.helpButtonToolTipText", l);
0320 directoryOpenButtonToolTipText = UIManager.getString(
0321 "FileChooser.directoryOpenButtonToolTipText", l);
0322 }
0323
0324 protected void uninstallDefaults(JFileChooser fc) {
0325 uninstallIcons(fc);
0326 uninstallStrings(fc);
0327 if (fc.getTransferHandler() instanceof UIResource) {
0328 fc.setTransferHandler(null);
0329 }
0330 }
0331
0332 protected void uninstallIcons(JFileChooser fc) {
0333 directoryIcon = null;
0334 fileIcon = null;
0335 computerIcon = null;
0336 hardDriveIcon = null;
0337 floppyDriveIcon = null;
0338
0339 newFolderIcon = null;
0340 upFolderIcon = null;
0341 homeFolderIcon = null;
0342 detailsViewIcon = null;
0343 listViewIcon = null;
0344 viewMenuIcon = null;
0345 }
0346
0347 protected void uninstallStrings(JFileChooser fc) {
0348 saveButtonText = null;
0349 openButtonText = null;
0350 cancelButtonText = null;
0351 updateButtonText = null;
0352 helpButtonText = null;
0353 directoryOpenButtonText = null;
0354
0355 saveButtonToolTipText = null;
0356 openButtonToolTipText = null;
0357 cancelButtonToolTipText = null;
0358 updateButtonToolTipText = null;
0359 helpButtonToolTipText = null;
0360 directoryOpenButtonToolTipText = null;
0361 }
0362
0363 protected void createModel() {
0364 if (model != null) {
0365 model.invalidateFileCache();
0366 }
0367 model = new BasicDirectoryModel(getFileChooser());
0368 }
0369
0370 public BasicDirectoryModel getModel() {
0371 return model;
0372 }
0373
0374 public PropertyChangeListener createPropertyChangeListener(
0375 JFileChooser fc) {
0376 return null;
0377 }
0378
0379 public String getFileName() {
0380 return null;
0381 }
0382
0383 public String getDirectoryName() {
0384 return null;
0385 }
0386
0387 public void setFileName(String filename) {
0388 }
0389
0390 public void setDirectoryName(String dirname) {
0391 }
0392
0393 public void rescanCurrentDirectory(JFileChooser fc) {
0394 }
0395
0396 public void ensureFileIsVisible(JFileChooser fc, File f) {
0397 }
0398
0399 public JFileChooser getFileChooser() {
0400 return filechooser;
0401 }
0402
0403 public JPanel getAccessoryPanel() {
0404 return accessoryPanel;
0405 }
0406
0407 protected JButton getApproveButton(JFileChooser fc) {
0408 return null;
0409 }
0410
0411 public String getApproveButtonToolTipText(JFileChooser fc) {
0412 String tooltipText = fc.getApproveButtonToolTipText();
0413 if (tooltipText != null) {
0414 return tooltipText;
0415 }
0416
0417 if (fc.getDialogType() == JFileChooser.OPEN_DIALOG) {
0418 return openButtonToolTipText;
0419 } else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
0420 return saveButtonToolTipText;
0421 }
0422 return null;
0423 }
0424
0425 public void clearIconCache() {
0426 fileView.clearIconCache();
0427 }
0428
0429 // ********************************************
0430 // ************ Create Listeners **************
0431 // ********************************************
0432
0433 private Handler getHandler() {
0434 if (handler == null) {
0435 handler = new Handler();
0436 }
0437 return handler;
0438 }
0439
0440 protected MouseListener createDoubleClickListener(JFileChooser fc,
0441 JList list) {
0442 return new Handler(list);
0443 }
0444
0445 public ListSelectionListener createListSelectionListener(
0446 JFileChooser fc) {
0447 return getHandler();
0448 }
0449
0450 private class Handler implements MouseListener,
0451 ListSelectionListener {
0452 JList list;
0453
0454 Handler() {
0455 }
0456
0457 Handler(JList list) {
0458 this .list = list;
0459 }
0460
0461 public void mouseClicked(MouseEvent evt) {
0462 // Note: we can't depend on evt.getSource() because of backward
0463 // compatability
0464 if (list != null && SwingUtilities.isLeftMouseButton(evt)
0465 && (evt.getClickCount() % 2 == 0)) {
0466
0467 int index = SwingUtilities2.loc2IndexFileList(list, evt
0468 .getPoint());
0469 if (index >= 0) {
0470 File f = (File) list.getModel().getElementAt(index);
0471 try {
0472 // Strip trailing ".."
0473 f = ShellFolder.getNormalizedFile(f);
0474 } catch (IOException ex) {
0475 // That's ok, we'll use f as is
0476 }
0477 if (getFileChooser().isTraversable(f)) {
0478 list.clearSelection();
0479 changeDirectory(f);
0480 } else {
0481 getFileChooser().approveSelection();
0482 }
0483 }
0484 }
0485 }
0486
0487 public void mouseEntered(MouseEvent evt) {
0488 if (list != null) {
0489 TransferHandler th1 = getFileChooser()
0490 .getTransferHandler();
0491 TransferHandler th2 = list.getTransferHandler();
0492 if (th1 != th2) {
0493 list.setTransferHandler(th1);
0494 }
0495 if (getFileChooser().getDragEnabled() != list
0496 .getDragEnabled()) {
0497 list.setDragEnabled(getFileChooser()
0498 .getDragEnabled());
0499 }
0500 }
0501 }
0502
0503 public void mouseExited(MouseEvent evt) {
0504 }
0505
0506 public void mousePressed(MouseEvent evt) {
0507 }
0508
0509 public void mouseReleased(MouseEvent evt) {
0510 }
0511
0512 public void valueChanged(ListSelectionEvent evt) {
0513 if (!evt.getValueIsAdjusting()) {
0514 JFileChooser chooser = getFileChooser();
0515 FileSystemView fsv = chooser.getFileSystemView();
0516 JList list = (JList) evt.getSource();
0517
0518 int fsm = chooser.getFileSelectionMode();
0519 boolean useSetDirectory = usesSingleFilePane
0520 && (fsm == JFileChooser.FILES_ONLY);
0521
0522 if (chooser.isMultiSelectionEnabled()) {
0523 File[] files = null;
0524 Object[] objects = list.getSelectedValues();
0525 if (objects != null) {
0526 if (objects.length == 1
0527 && ((File) objects[0]).isDirectory()
0528 && chooser
0529 .isTraversable(((File) objects[0]))
0530 && (useSetDirectory || !fsv
0531 .isFileSystem(((File) objects[0])))) {
0532 setDirectorySelected(true);
0533 setDirectory(((File) objects[0]));
0534 } else {
0535 ArrayList fList = new ArrayList(
0536 objects.length);
0537 for (int i = 0; i < objects.length; i++) {
0538 File f = (File) objects[i];
0539 boolean isDir = f.isDirectory();
0540 if ((chooser.isFileSelectionEnabled() && !isDir)
0541 || (chooser
0542 .isDirectorySelectionEnabled()
0543 && fsv.isFileSystem(f) && isDir)) {
0544 fList.add(f);
0545 }
0546 }
0547 if (fList.size() > 0) {
0548 files = (File[]) fList
0549 .toArray(new File[fList.size()]);
0550 }
0551 setDirectorySelected(false);
0552 }
0553 }
0554 chooser.setSelectedFiles(files);
0555 } else {
0556 File file = (File) list.getSelectedValue();
0557 if (file != null
0558 && file.isDirectory()
0559 && chooser.isTraversable(file)
0560 && (useSetDirectory || !fsv
0561 .isFileSystem(file))) {
0562
0563 setDirectorySelected(true);
0564 setDirectory(file);
0565 if (usesSingleFilePane) {
0566 chooser.setSelectedFile(null);
0567 }
0568 } else {
0569 setDirectorySelected(false);
0570 if (file != null) {
0571 chooser.setSelectedFile(file);
0572 }
0573 }
0574 }
0575 }
0576 }
0577 }
0578
0579 protected class DoubleClickListener extends MouseAdapter {
0580 // NOTE: This class exists only for backward compatability. All
0581 // its functionality has been moved into Handler. If you need to add
0582 // new functionality add it to the Handler, but make sure this
0583 // class calls into the Handler.
0584 Handler handler;
0585
0586 public DoubleClickListener(JList list) {
0587 handler = new Handler(list);
0588 }
0589
0590 /**
0591 * The JList used for representing the files is created by subclasses, but the
0592 * selection is monitored in this class. The TransferHandler installed in the
0593 * JFileChooser is also installed in the file list as it is used as the actual
0594 * transfer source. The list is updated on a mouse enter to reflect the current
0595 * data transfer state of the file chooser.
0596 */
0597 public void mouseEntered(MouseEvent e) {
0598 handler.mouseEntered(e);
0599 }
0600
0601 public void mouseClicked(MouseEvent e) {
0602 handler.mouseClicked(e);
0603 }
0604 }
0605
0606 protected class SelectionListener implements ListSelectionListener {
0607 // NOTE: This class exists only for backward compatability. All
0608 // its functionality has been moved into Handler. If you need to add
0609 // new functionality add it to the Handler, but make sure this
0610 // class calls into the Handler.
0611 public void valueChanged(ListSelectionEvent e) {
0612 getHandler().valueChanged(e);
0613 }
0614 }
0615
0616 /**
0617 * Property to remember whether a directory is currently selected in the UI.
0618 *
0619 * @return <code>true</code> iff a directory is currently selected.
0620 * @since 1.4
0621 */
0622 protected boolean isDirectorySelected() {
0623 return directorySelected;
0624 }
0625
0626 /**
0627 * Property to remember whether a directory is currently selected in the UI.
0628 * This is normally called by the UI on a selection event.
0629 *
0630 * @param b iff a directory is currently selected.
0631 * @since 1.4
0632 */
0633 protected void setDirectorySelected(boolean b) {
0634 directorySelected = b;
0635 }
0636
0637 /**
0638 * Property to remember the directory that is currently selected in the UI.
0639 *
0640 * @return the value of the <code>directory</code> property
0641 * @see #setDirectory
0642 * @since 1.4
0643 */
0644 protected File getDirectory() {
0645 return directory;
0646 }
0647
0648 /**
0649 * Property to remember the directory that is currently selected in the UI.
0650 * This is normally called by the UI on a selection event.
0651 *
0652 * @param f the <code>File</code> object representing the directory that is
0653 * currently selected
0654 * @since 1.4
0655 */
0656 protected void setDirectory(File f) {
0657 directory = f;
0658 }
0659
0660 /**
0661 * Returns the mnemonic for the given key.
0662 */
0663 private int getMnemonic(String key, Locale l) {
0664 return SwingUtilities2.getUIDefaultsInt(key, l);
0665 }
0666
0667 // *******************************************************
0668 // ************ FileChooser UI PLAF methods **************
0669 // *******************************************************
0670
0671 /**
0672 * Returns the default accept all file filter
0673 */
0674 public FileFilter getAcceptAllFileFilter(JFileChooser fc) {
0675 return acceptAllFileFilter;
0676 }
0677
0678 public FileView getFileView(JFileChooser fc) {
0679 return fileView;
0680 }
0681
0682 /**
0683 * Returns the title of this dialog
0684 */
0685 public String getDialogTitle(JFileChooser fc) {
0686 String dialogTitle = fc.getDialogTitle();
0687 if (dialogTitle != null) {
0688 return dialogTitle;
0689 } else if (fc.getDialogType() == JFileChooser.OPEN_DIALOG) {
0690 return openDialogTitleText;
0691 } else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
0692 return saveDialogTitleText;
0693 } else {
0694 return getApproveButtonText(fc);
0695 }
0696 }
0697
0698 public int getApproveButtonMnemonic(JFileChooser fc) {
0699 int mnemonic = fc.getApproveButtonMnemonic();
0700 if (mnemonic > 0) {
0701 return mnemonic;
0702 } else if (fc.getDialogType() == JFileChooser.OPEN_DIALOG) {
0703 return openButtonMnemonic;
0704 } else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
0705 return saveButtonMnemonic;
0706 } else {
0707 return mnemonic;
0708 }
0709 }
0710
0711 public String getApproveButtonText(JFileChooser fc) {
0712 String buttonText = fc.getApproveButtonText();
0713 if (buttonText != null) {
0714 return buttonText;
0715 } else if (fc.getDialogType() == JFileChooser.OPEN_DIALOG) {
0716 return openButtonText;
0717 } else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
0718 return saveButtonText;
0719 } else {
0720 return null;
0721 }
0722 }
0723
0724 // *****************************
0725 // ***** Directory Actions *****
0726 // *****************************
0727
0728 public Action getNewFolderAction() {
0729 if (newFolderAction == null) {
0730 newFolderAction = new NewFolderAction();
0731 // Note: Don't return null for readOnly, it might
0732 // break older apps.
0733 if (readOnly) {
0734 newFolderAction.setEnabled(false);
0735 }
0736 }
0737 return newFolderAction;
0738 }
0739
0740 public Action getGoHomeAction() {
0741 return goHomeAction;
0742 }
0743
0744 public Action getChangeToParentDirectoryAction() {
0745 return changeToParentDirectoryAction;
0746 }
0747
0748 public Action getApproveSelectionAction() {
0749 return approveSelectionAction;
0750 }
0751
0752 public Action getCancelSelectionAction() {
0753 return cancelSelectionAction;
0754 }
0755
0756 public Action getUpdateAction() {
0757 return updateAction;
0758 }
0759
0760 /**
0761 * Creates a new folder.
0762 */
0763 protected class NewFolderAction extends AbstractAction {
0764 protected NewFolderAction() {
0765 super (FilePane.ACTION_NEW_FOLDER);
0766 }
0767
0768 public void actionPerformed(ActionEvent e) {
0769 if (readOnly) {
0770 return;
0771 }
0772 JFileChooser fc = getFileChooser();
0773 File currentDirectory = fc.getCurrentDirectory();
0774 File newFolder = null;
0775 try {
0776 newFolder = fc.getFileSystemView().createNewFolder(
0777 currentDirectory);
0778 if (fc.isMultiSelectionEnabled()) {
0779 fc.setSelectedFiles(new File[] { newFolder });
0780 } else {
0781 fc.setSelectedFile(newFolder);
0782 }
0783 } catch (IOException exc) {
0784 JOptionPane.showMessageDialog(fc, newFolderErrorText
0785 + newFolderErrorSeparator + exc,
0786 newFolderErrorText, JOptionPane.ERROR_MESSAGE);
0787 return;
0788 }
0789
0790 fc.rescanCurrentDirectory();
0791 }
0792 }
0793
0794 /**
0795 * Acts on the "home" key event or equivalent event.
0796 */
0797 protected class GoHomeAction extends AbstractAction {
0798 protected GoHomeAction() {
0799 super ("Go Home");
0800 }
0801
0802 public void actionPerformed(ActionEvent e) {
0803 JFileChooser fc = getFileChooser();
0804 changeDirectory(fc.getFileSystemView().getHomeDirectory());
0805 }
0806 }
0807
0808 protected class ChangeToParentDirectoryAction extends
0809 AbstractAction {
0810 protected ChangeToParentDirectoryAction() {
0811 super ("Go Up");
0812 putValue(Action.ACTION_COMMAND_KEY,
0813 FilePane.ACTION_CHANGE_TO_PARENT_DIRECTORY);
0814 }
0815
0816 public void actionPerformed(ActionEvent e) {
0817 Component focusOwner = KeyboardFocusManager
0818 .getCurrentKeyboardFocusManager().getFocusOwner();
0819 if (focusOwner == null
0820 || !(focusOwner instanceof javax.swing.text.JTextComponent)) {
0821 getFileChooser().changeToParentDirectory();
0822 }
0823 }
0824 }
0825
0826 /**
0827 * Responds to an Open or Save request
0828 */
0829 protected class ApproveSelectionAction extends AbstractAction {
0830 protected ApproveSelectionAction() {
0831 super (FilePane.ACTION_APPROVE_SELECTION);
0832 }
0833
0834 public void actionPerformed(ActionEvent e) {
0835 if (isDirectorySelected()) {
0836 File dir = getDirectory();
0837 if (dir != null) {
0838 try {
0839 // Strip trailing ".."
0840 dir = ShellFolder.getNormalizedFile(dir);
0841 } catch (IOException ex) {
0842 // Ok, use f as is
0843 }
0844 changeDirectory(dir);
0845 return;
0846 }
0847 }
0848
0849 JFileChooser chooser = getFileChooser();
0850
0851 String filename = getFileName();
0852 FileSystemView fs = chooser.getFileSystemView();
0853 File dir = chooser.getCurrentDirectory();
0854
0855 if (filename != null) {
0856 // Remove whitespace from beginning and end of filename
0857 filename = filename.trim();
0858 }
0859
0860 if (filename == null || filename.equals("")) {
0861 // no file selected, multiple selection off, therefore cancel the approve action
0862 resetGlobFilter();
0863 return;
0864 }
0865
0866 File selectedFile = null;
0867 File[] selectedFiles = null;
0868
0869 if (filename != null && !filename.equals("")) {
0870 // Unix: Resolve '~' to user's home directory
0871 if (File.separatorChar == '/') {
0872 if (filename.startsWith("~/")) {
0873 filename = System.getProperty("user.home")
0874 + filename.substring(1);
0875 } else if (filename.equals("~")) {
0876 filename = System.getProperty("user.home");
0877 }
0878 }
0879
0880 if (chooser.isMultiSelectionEnabled()
0881 && filename.startsWith("\"")) {
0882 ArrayList fList = new ArrayList();
0883
0884 filename = filename.substring(1);
0885 if (filename.endsWith("\"")) {
0886 filename = filename.substring(0, filename
0887 .length() - 1);
0888 }
0889 File[] children = null;
0890 int childIndex = 0;
0891 do {
0892 String str;
0893 int i = filename.indexOf("\" \"");
0894 if (i > 0) {
0895 str = filename.substring(0, i);
0896 filename = filename.substring(i + 3);
0897 } else {
0898 str = filename;
0899 filename = "";
0900 }
0901 File file = fs.createFileObject(str);
0902 if (!file.isAbsolute()) {
0903 if (children == null) {
0904 children = fs.getFiles(dir, false);
0905 Arrays.sort(children);
0906 }
0907 for (int k = 0; k < children.length; k++) {
0908 int l = (childIndex + k)
0909 % children.length;
0910 if (children[l].getName().equals(str)) {
0911 file = children[l];
0912 childIndex = l + 1;
0913 break;
0914 }
0915 }
0916 }
0917 fList.add(file);
0918 } while (filename.length() > 0);
0919 if (fList.size() > 0) {
0920 selectedFiles = (File[]) fList
0921 .toArray(new File[fList.size()]);
0922 }
0923 resetGlobFilter();
0924 } else {
0925 selectedFile = fs.createFileObject(filename);
0926 if (!selectedFile.isAbsolute()) {
0927 selectedFile = fs.getChild(dir, filename);
0928 }
0929 // check for wildcard pattern
0930 FileFilter currentFilter = chooser.getFileFilter();
0931 if (!selectedFile.exists()
0932 && isGlobPattern(filename)) {
0933 changeDirectory(selectedFile.getParentFile());
0934 if (globFilter == null) {
0935 globFilter = new GlobFilter();
0936 }
0937 try {
0938 globFilter.setPattern(selectedFile
0939 .getName());
0940 if (!(currentFilter instanceof GlobFilter)) {
0941 actualFileFilter = currentFilter;
0942 }
0943 chooser.setFileFilter(null);
0944 chooser.setFileFilter(globFilter);
0945 return;
0946 } catch (PatternSyntaxException pse) {
0947 // Not a valid glob pattern. Abandon filter.
0948 }
0949 }
0950
0951 resetGlobFilter();
0952
0953 // Check for directory change action
0954 boolean isDir = (selectedFile != null && selectedFile
0955 .isDirectory());
0956 boolean isTrav = (selectedFile != null && chooser
0957 .isTraversable(selectedFile));
0958 boolean isDirSelEnabled = chooser
0959 .isDirectorySelectionEnabled();
0960 boolean isFileSelEnabled = chooser
0961 .isFileSelectionEnabled();
0962 boolean isCtrl = (e != null && (e.getModifiers() & ActionEvent.CTRL_MASK) != 0);
0963
0964 if (isDir && isTrav && (isCtrl || !isDirSelEnabled)) {
0965 changeDirectory(selectedFile);
0966 return;
0967 } else if ((isDir || !isFileSelEnabled)
0968 && (!isDir || !isDirSelEnabled)
0969 && (!isDirSelEnabled || selectedFile
0970 .exists())) {
0971 selectedFile = null;
0972 }
0973 }
0974 }
0975 if (selectedFiles != null || selectedFile != null) {
0976 if (selectedFiles != null
0977 || chooser.isMultiSelectionEnabled()) {
0978 if (selectedFiles == null) {
0979 selectedFiles = new File[] { selectedFile };
0980 }
0981 chooser.setSelectedFiles(selectedFiles);
0982 // Do it again. This is a fix for bug 4949273 to force the
0983 // selected value in case the ListSelectionModel clears it
0984 // for non-existing file names.
0985 chooser.setSelectedFiles(selectedFiles);
0986 } else {
0987 chooser.setSelectedFile(selectedFile);
0988 }
0989 chooser.approveSelection();
0990 } else {
0991 if (chooser.isMultiSelectionEnabled()) {
0992 chooser.setSelectedFiles(null);
0993 } else {
0994 chooser.setSelectedFile(null);
0995 }
0996 chooser.cancelSelection();
0997 }
0998 }
0999 }
1000
1001 private void resetGlobFilter() {
1002 if (actualFileFilter != null) {
1003 JFileChooser chooser = getFileChooser();
1004 FileFilter currentFilter = chooser.getFileFilter();
1005 if (currentFilter != null
1006 && currentFilter.equals(globFilter)) {
1007 chooser.setFileFilter(actualFileFilter);
1008 chooser.removeChoosableFileFilter(globFilter);
1009 }
1010 actualFileFilter = null;
1011 }
1012 }
1013
1014 private static boolean isGlobPattern(String filename) {
1015 return ((File.separatorChar == '\\' && (filename.indexOf('*') >= 0 || filename
1016 .indexOf('?') >= 0)) || (File.separatorChar == '/' && (filename
1017 .indexOf('*') >= 0
1018 || filename.indexOf('?') >= 0 || filename.indexOf('[') >= 0)));
1019 }
1020
1021 /* A file filter which accepts file patterns containing
1022 * the special wildcards *? on Windows and *?[] on Unix.
1023 */
1024 class GlobFilter extends FileFilter {
1025 Pattern pattern;
1026 String globPattern;
1027
1028 public void setPattern(String globPattern) {
1029 char[] gPat = globPattern.toCharArray();
1030 char[] rPat = new char[gPat.length * 2];
1031 boolean isWin32 = (File.separatorChar == '\\');
1032 boolean inBrackets = false;
1033 int j = 0;
1034
1035 this .globPattern = globPattern;
1036
1037 if (isWin32) {
1038 // On windows, a pattern ending with *.* is equal to ending with *
1039 int len = gPat.length;
1040 if (globPattern.endsWith("*.*")) {
1041 len -= 2;
1042 }
1043 for (int i = 0; i < len; i++) {
1044 switch (gPat[i]) {
1045 case '*':
1046 rPat[j++] = '.';
1047 rPat[j++] = '*';
1048 break;
1049
1050 case '?':
1051 rPat[j++] = '.';
1052 break;
1053
1054 case '\\':
1055 rPat[j++] = '\\';
1056 rPat[j++] = '\\';
1057 break;
1058
1059 default:
1060 if ("+()^$.{}[]".indexOf(gPat[i]) >= 0) {
1061 rPat[j++] = '\\';
1062 }
1063 rPat[j++] = gPat[i];
1064 break;
1065 }
1066 }
1067 } else {
1068 for (int i = 0; i < gPat.length; i++) {
1069 switch (gPat[i]) {
1070 case '*':
1071 if (!inBrackets) {
1072 rPat[j++] = '.';
1073 }
1074 rPat[j++] = '*';
1075 break;
1076
1077 case '?':
1078 rPat[j++] = inBrackets ? '?' : '.';
1079 break;
1080
1081 case '[':
1082 inBrackets = true;
1083 rPat[j++] = gPat[i];
1084
1085 if (i < gPat.length - 1) {
1086 switch (gPat[i + 1]) {
1087 case '!':
1088 case '^':
1089 rPat[j++] = '^';
1090 i++;
1091 break;
1092
1093 case ']':
1094 rPat[j++] = gPat[++i];
1095 break;
1096 }
1097 }
1098 break;
1099
1100 case ']':
1101 rPat[j++] = gPat[i];
1102 inBrackets = false;
1103 break;
1104
1105 case '\\':
1106 if (i == 0 && gPat.length > 1 && gPat[1] == '~') {
1107 rPat[j++] = gPat[++i];
1108 } else {
1109 rPat[j++] = '\\';
1110 if (i < gPat.length - 1
1111 && "*?[]".indexOf(gPat[i + 1]) >= 0) {
1112 rPat[j++] = gPat[++i];
1113 } else {
1114 rPat[j++] = '\\';
1115 }
1116 }
1117 break;
1118
1119 default:
1120 //if ("+()|^$.{}<>".indexOf(gPat[i]) >= 0) {
1121 if (!Character.isLetterOrDigit(gPat[i])) {
1122 rPat[j++] = '\\';
1123 }
1124 rPat[j++] = gPat[i];
1125 break;
1126 }
1127 }
1128 }
1129 this .pattern = Pattern.compile(new String(rPat, 0, j),
1130 Pattern.CASE_INSENSITIVE);
1131 }
1132
1133 public boolean accept(File f) {
1134 if (f == null) {
1135 return false;
1136 }
1137 if (f.isDirectory()) {
1138 return true;
1139 }
1140 return pattern.matcher(f.getName()).matches();
1141 }
1142
1143 public String getDescription() {
1144 return globPattern;
1145 }
1146 }
1147
1148 /**
1149 * Responds to a cancel request.
1150 */
1151 protected class CancelSelectionAction extends AbstractAction {
1152 public void actionPerformed(ActionEvent e) {
1153 getFileChooser().cancelSelection();
1154 }
1155 }
1156
1157 /**
1158 * Rescans the files in the current directory
1159 */
1160 protected class UpdateAction extends AbstractAction {
1161 public void actionPerformed(ActionEvent e) {
1162 JFileChooser fc = getFileChooser();
1163 fc.setCurrentDirectory(fc.getFileSystemView()
1164 .createFileObject(getDirectoryName()));
1165 fc.rescanCurrentDirectory();
1166 }
1167 }
1168
1169 private void changeDirectory(File dir) {
1170 JFileChooser fc = getFileChooser();
1171 // Traverse shortcuts on Windows
1172 if (dir != null && File.separatorChar == '\\'
1173 && dir.getPath().endsWith(".lnk")) {
1174 try {
1175 File linkedTo = ShellFolder.getShellFolder(dir)
1176 .getLinkLocation();
1177 if (linkedTo != null && fc.isTraversable(linkedTo)) {
1178 dir = linkedTo;
1179 } else {
1180 return;
1181 }
1182 } catch (FileNotFoundException ex) {
1183 return;
1184 }
1185 }
1186 fc.setCurrentDirectory(dir);
1187 if (fc.getFileSelectionMode() == JFileChooser.FILES_AND_DIRECTORIES
1188 && fc.getFileSystemView().isFileSystem(dir)) {
1189
1190 setFileName(dir.getAbsolutePath());
1191 }
1192 }
1193
1194 // *****************************************
1195 // ***** default AcceptAll file filter *****
1196 // *****************************************
1197 protected class AcceptAllFileFilter extends FileFilter {
1198
1199 public AcceptAllFileFilter() {
1200 }
1201
1202 public boolean accept(File f) {
1203 return true;
1204 }
1205
1206 public String getDescription() {
1207 return UIManager
1208 .getString("FileChooser.acceptAllFileFilterText");
1209 }
1210 }
1211
1212 // ***********************
1213 // * FileView operations *
1214 // ***********************
1215 protected class BasicFileView extends FileView {
1216 /* FileView type descriptions */
1217 // PENDING(jeff) - pass in the icon cache size
1218 protected Hashtable<File, Icon> iconCache = new Hashtable<File, Icon>();
1219
1220 public BasicFileView() {
1221 }
1222
1223 public void clearIconCache() {
1224 iconCache = new Hashtable<File, Icon>();
1225 }
1226
1227 public String getName(File f) {
1228 // Note: Returns display name rather than file name
1229 String fileName = null;
1230 if (f != null) {
1231 fileName = getFileChooser().getFileSystemView()
1232 .getSystemDisplayName(f);
1233 }
1234 return fileName;
1235 }
1236
1237 public String getDescription(File f) {
1238 return f.getName();
1239 }
1240
1241 public String getTypeDescription(File f) {
1242 String type = getFileChooser().getFileSystemView()
1243 .getSystemTypeDescription(f);
1244 if (type == null) {
1245 if (f.isDirectory()) {
1246 type = directoryDescriptionText;
1247 } else {
1248 type = fileDescriptionText;
1249 }
1250 }
1251 return type;
1252 }
1253
1254 public Icon getCachedIcon(File f) {
1255 return (Icon) iconCache.get(f);
1256 }
1257
1258 public void cacheIcon(File f, Icon i) {
1259 if (f == null || i == null) {
1260 return;
1261 }
1262 iconCache.put(f, i);
1263 }
1264
1265 public Icon getIcon(File f) {
1266 Icon icon = getCachedIcon(f);
1267 if (icon != null) {
1268 return icon;
1269 }
1270 icon = fileIcon;
1271 if (f != null) {
1272 FileSystemView fsv = getFileChooser()
1273 .getFileSystemView();
1274
1275 if (fsv.isFloppyDrive(f)) {
1276 icon = floppyDriveIcon;
1277 } else if (fsv.isDrive(f)) {
1278 icon = hardDriveIcon;
1279 } else if (fsv.isComputerNode(f)) {
1280 icon = computerIcon;
1281 } else if (f.isDirectory()) {
1282 icon = directoryIcon;
1283 }
1284 }
1285 cacheIcon(f, icon);
1286 return icon;
1287 }
1288
1289 public Boolean isHidden(File f) {
1290 String name = f.getName();
1291 if (name != null && name.charAt(0) == '.') {
1292 return Boolean.TRUE;
1293 } else {
1294 return Boolean.FALSE;
1295 }
1296 }
1297 }
1298
1299 private static final TransferHandler defaultTransferHandler = new FileTransferHandler();
1300
1301 /**
1302 * Data transfer support for the file chooser. Since files are currently presented
1303 * as a list, the list support is reused with the added flavor of DataFlavor.javaFileListFlavor
1304 */
1305 static class FileTransferHandler extends TransferHandler implements
1306 UIResource {
1307
1308 /**
1309 * Create a Transferable to use as the source for a data transfer.
1310 *
1311 * @param c The component holding the data to be transfered. This
1312 * argument is provided to enable sharing of TransferHandlers by
1313 * multiple components.
1314 * @return The representation of the data to be transfered.
1315 *
1316 */
1317 protected Transferable createTransferable(JComponent c) {
1318 Object[] values = null;
1319 if (c instanceof JList) {
1320 values = ((JList) c).getSelectedValues();
1321 } else if (c instanceof JTable) {
1322 JTable table = (JTable) c;
1323 int[] rows = table.getSelectedRows();
1324 if (rows != null) {
1325 values = new Object[rows.length];
1326 for (int i = 0; i < rows.length; i++) {
1327 values[i] = table.getValueAt(rows[i], 0);
1328 }
1329 }
1330 }
1331 if (values == null || values.length == 0) {
1332 return null;
1333 }
1334
1335 StringBuffer plainBuf = new StringBuffer();
1336 StringBuffer htmlBuf = new StringBuffer();
1337
1338 htmlBuf.append("<html>\n<body>\n<ul>\n");
1339
1340 for (int i = 0; i < values.length; i++) {
1341 Object obj = values[i];
1342 String val = ((obj == null) ? "" : obj.toString());
1343 plainBuf.append(val + "\n");
1344 htmlBuf.append(" <li>" + val + "\n");
1345 }
1346
1347 // remove the last newline
1348 plainBuf.deleteCharAt(plainBuf.length() - 1);
1349 htmlBuf.append("</ul>\n</body>\n</html>");
1350
1351 return new FileTransferable(plainBuf.toString(), htmlBuf
1352 .toString(), values);
1353 }
1354
1355 public int getSourceActions(JComponent c) {
1356 return COPY;
1357 }
1358
1359 static class FileTransferable extends BasicTransferable {
1360
1361 Object[] fileData;
1362
1363 FileTransferable(String plainData, String htmlData,
1364 Object[] fileData) {
1365 super (plainData, htmlData);
1366 this .fileData = fileData;
1367 }
1368
1369 /**
1370 * Best format of the file chooser is DataFlavor.javaFileListFlavor.
1371 */
1372 protected DataFlavor[] getRicherFlavors() {
1373 DataFlavor[] flavors = new DataFlavor[1];
1374 flavors[0] = DataFlavor.javaFileListFlavor;
1375 return flavors;
1376 }
1377
1378 /**
1379 * The only richer format supported is the file list flavor
1380 */
1381 protected Object getRicherData(DataFlavor flavor) {
1382 if (DataFlavor.javaFileListFlavor.equals(flavor)) {
1383 ArrayList files = new ArrayList();
1384 for (int i = 0; i < fileData.length; i++) {
1385 files.add(fileData[i]);
1386 }
1387 return files;
1388 }
1389 return null;
1390 }
1391
1392 }
1393 }
1394 }
|