1. /*
  2. * @(#)BasicFileChooserUI.java 1.47 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.plaf.basic;
  8. import javax.swing.*;
  9. import javax.swing.filechooser.*;
  10. import javax.swing.event.*;
  11. import javax.swing.plaf.*;
  12. import java.awt.*;
  13. import java.awt.event.*;
  14. import java.awt.datatransfer.*;
  15. import java.beans.*;
  16. import java.io.File;
  17. import java.io.IOException;
  18. import java.util.*;
  19. import java.util.regex.*;
  20. /**
  21. * Basic L&F implementation of a FileChooser.
  22. *
  23. * @version %i% %g%
  24. * @author Jeff Dinkins
  25. */
  26. public class BasicFileChooserUI extends FileChooserUI {
  27. /* FileView icons */
  28. protected Icon directoryIcon = null;
  29. protected Icon fileIcon = null;
  30. protected Icon computerIcon = null;
  31. protected Icon hardDriveIcon = null;
  32. protected Icon floppyDriveIcon = null;
  33. protected Icon newFolderIcon = null;
  34. protected Icon upFolderIcon = null;
  35. protected Icon homeFolderIcon = null;
  36. protected Icon listViewIcon = null;
  37. protected Icon detailsViewIcon = null;
  38. protected int saveButtonMnemonic = 0;
  39. protected int openButtonMnemonic = 0;
  40. protected int cancelButtonMnemonic = 0;
  41. protected int updateButtonMnemonic = 0;
  42. protected int helpButtonMnemonic = 0;
  43. /**
  44. * The mnemonic keycode used for the approve button when a directory
  45. * is selected and the current selection mode is not DIRECTORIES_ONLY.
  46. *
  47. * @since 1.4
  48. */
  49. protected int directoryOpenButtonMnemonic = 0;
  50. protected String saveButtonText = null;
  51. protected String openButtonText = null;
  52. protected String cancelButtonText = null;
  53. protected String updateButtonText = null;
  54. protected String helpButtonText = null;
  55. /**
  56. * The label text displayed on the approve button when a directory
  57. * is selected and the current selection mode is not DIRECTORIES_ONLY.
  58. *
  59. * @since 1.4
  60. */
  61. protected String directoryOpenButtonText = null;
  62. private String openDialogTitleText = null;
  63. private String saveDialogTitleText = null;
  64. protected String saveButtonToolTipText = null;
  65. protected String openButtonToolTipText = null;
  66. protected String cancelButtonToolTipText = null;
  67. protected String updateButtonToolTipText = null;
  68. protected String helpButtonToolTipText = null;
  69. /**
  70. * The tooltip text displayed on the approve button when a directory
  71. * is selected and the current selection mode is not DIRECTORIES_ONLY.
  72. *
  73. * @since 1.4
  74. */
  75. protected String directoryOpenButtonToolTipText = null;
  76. // Some generic FileChooser functions
  77. private Action approveSelectionAction = new ApproveSelectionAction();
  78. private Action cancelSelectionAction = new CancelSelectionAction();
  79. private Action updateAction = new UpdateAction();
  80. private Action newFolderAction = new NewFolderAction();
  81. private Action goHomeAction = new GoHomeAction();
  82. private Action changeToParentDirectoryAction = new ChangeToParentDirectoryAction();
  83. private String newFolderErrorSeparator = null;
  84. private String newFolderErrorText = null;
  85. private String fileDescriptionText = null;
  86. private String directoryDescriptionText = null;
  87. private JFileChooser filechooser = null;
  88. private boolean directorySelected = false;
  89. private File directory = null;
  90. private PropertyChangeListener propertyChangeListener = null;
  91. private AcceptAllFileFilter acceptAllFileFilter = new AcceptAllFileFilter();
  92. private FileFilter actualFileFilter = null;
  93. private GlobFilter globFilter = null;
  94. private BasicDirectoryModel model = null;
  95. private BasicFileView fileView = new BasicFileView();
  96. // The accessoryPanel is a container to place the JFileChooser accessory component
  97. private JPanel accessoryPanel = null;
  98. public BasicFileChooserUI(JFileChooser b) {
  99. }
  100. public void installUI(JComponent c) {
  101. accessoryPanel = new JPanel(new BorderLayout());
  102. filechooser = (JFileChooser) c;
  103. createModel();
  104. clearIconCache();
  105. installDefaults(filechooser);
  106. installComponents(filechooser);
  107. installListeners(filechooser);
  108. filechooser.applyComponentOrientation(filechooser.getComponentOrientation());
  109. }
  110. public void uninstallUI(JComponent c) {
  111. uninstallListeners((JFileChooser) filechooser);
  112. uninstallComponents((JFileChooser) filechooser);
  113. uninstallDefaults((JFileChooser) filechooser);
  114. if(accessoryPanel != null) {
  115. accessoryPanel.removeAll();
  116. }
  117. accessoryPanel = null;
  118. getFileChooser().removeAll();
  119. }
  120. public void installComponents(JFileChooser fc) {
  121. }
  122. public void uninstallComponents(JFileChooser fc) {
  123. }
  124. protected void installListeners(JFileChooser fc) {
  125. propertyChangeListener = createPropertyChangeListener(fc);
  126. if(propertyChangeListener != null) {
  127. fc.addPropertyChangeListener(propertyChangeListener);
  128. }
  129. fc.addPropertyChangeListener(getModel());
  130. InputMap inputMap = getInputMap(JComponent.
  131. WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  132. SwingUtilities.replaceUIInputMap(fc, JComponent.
  133. WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, inputMap);
  134. ActionMap actionMap = getActionMap();
  135. SwingUtilities.replaceUIActionMap(fc, actionMap);
  136. }
  137. InputMap getInputMap(int condition) {
  138. if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
  139. return (InputMap)UIManager.get("FileChooser.ancestorInputMap");
  140. }
  141. return null;
  142. }
  143. ActionMap getActionMap() {
  144. return createActionMap();
  145. }
  146. ActionMap createActionMap() {
  147. AbstractAction escAction = new AbstractAction() {
  148. public void actionPerformed(ActionEvent e) {
  149. getFileChooser().cancelSelection();
  150. }
  151. public boolean isEnabled(){
  152. return getFileChooser().isEnabled();
  153. }
  154. };
  155. ActionMap map = new ActionMapUIResource();
  156. map.put("approveSelection", getApproveSelectionAction());
  157. map.put("cancelSelection", escAction);
  158. map.put("Go Up", getChangeToParentDirectoryAction());
  159. return map;
  160. }
  161. protected void uninstallListeners(JFileChooser fc) {
  162. if(propertyChangeListener != null) {
  163. fc.removePropertyChangeListener(propertyChangeListener);
  164. }
  165. fc.removePropertyChangeListener(getModel());
  166. SwingUtilities.replaceUIInputMap(fc, JComponent.
  167. WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
  168. SwingUtilities.replaceUIActionMap(fc, null);
  169. }
  170. protected void installDefaults(JFileChooser fc) {
  171. installIcons(fc);
  172. installStrings(fc);
  173. TransferHandler th = fc.getTransferHandler();
  174. if (th == null || th instanceof UIResource) {
  175. fc.setTransferHandler(defaultTransferHandler);
  176. }
  177. }
  178. protected void installIcons(JFileChooser fc) {
  179. directoryIcon = UIManager.getIcon("FileView.directoryIcon");
  180. fileIcon = UIManager.getIcon("FileView.fileIcon");
  181. computerIcon = UIManager.getIcon("FileView.computerIcon");
  182. hardDriveIcon = UIManager.getIcon("FileView.hardDriveIcon");
  183. floppyDriveIcon = UIManager.getIcon("FileView.floppyDriveIcon");
  184. newFolderIcon = UIManager.getIcon("FileChooser.newFolderIcon");
  185. upFolderIcon = UIManager.getIcon("FileChooser.upFolderIcon");
  186. homeFolderIcon = UIManager.getIcon("FileChooser.homeFolderIcon");
  187. detailsViewIcon = UIManager.getIcon("FileChooser.detailsViewIcon");
  188. listViewIcon = UIManager.getIcon("FileChooser.listViewIcon");
  189. }
  190. protected void installStrings(JFileChooser fc) {
  191. Locale l = fc.getLocale();
  192. newFolderErrorText = UIManager.getString("FileChooser.newFolderErrorText",l);
  193. newFolderErrorSeparator = UIManager.getString("FileChooser.newFolderErrorSeparator",l);
  194. fileDescriptionText = UIManager.getString("FileChooser.fileDescriptionText",l);
  195. directoryDescriptionText = UIManager.getString("FileChooser.directoryDescriptionText",l);
  196. saveButtonText = UIManager.getString("FileChooser.saveButtonText",l);
  197. openButtonText = UIManager.getString("FileChooser.openButtonText",l);
  198. saveDialogTitleText = UIManager.getString("FileChooser.saveDialogTitleText",l);
  199. openDialogTitleText = UIManager.getString("FileChooser.openDialogTitleText",l);
  200. cancelButtonText = UIManager.getString("FileChooser.cancelButtonText",l);
  201. updateButtonText = UIManager.getString("FileChooser.updateButtonText",l);
  202. helpButtonText = UIManager.getString("FileChooser.helpButtonText",l);
  203. directoryOpenButtonText = UIManager.getString("FileChooser.directoryOpenButtonText",l);
  204. saveButtonMnemonic = UIManager.getInt("FileChooser.saveButtonMnemonic");
  205. openButtonMnemonic = UIManager.getInt("FileChooser.openButtonMnemonic");
  206. cancelButtonMnemonic = UIManager.getInt("FileChooser.cancelButtonMnemonic");
  207. updateButtonMnemonic = UIManager.getInt("FileChooser.updateButtonMnemonic");
  208. helpButtonMnemonic = UIManager.getInt("FileChooser.helpButtonMnemonic");
  209. directoryOpenButtonMnemonic = UIManager.getInt("FileChooser.directoryOpenButtonMnemonic");
  210. saveButtonToolTipText = UIManager.getString("FileChooser.saveButtonToolTipText",l);
  211. openButtonToolTipText = UIManager.getString("FileChooser.openButtonToolTipText",l);
  212. cancelButtonToolTipText = UIManager.getString("FileChooser.cancelButtonToolTipText",l);
  213. updateButtonToolTipText = UIManager.getString("FileChooser.updateButtonToolTipText",l);
  214. helpButtonToolTipText = UIManager.getString("FileChooser.helpButtonToolTipText",l);
  215. directoryOpenButtonToolTipText = UIManager.getString("FileChooser.directoryOpenButtonToolTipText",l);
  216. }
  217. protected void uninstallDefaults(JFileChooser fc) {
  218. uninstallIcons(fc);
  219. uninstallStrings(fc);
  220. if (fc.getTransferHandler() instanceof UIResource) {
  221. fc.setTransferHandler(null);
  222. }
  223. }
  224. protected void uninstallIcons(JFileChooser fc) {
  225. directoryIcon = null;
  226. fileIcon = null;
  227. computerIcon = null;
  228. hardDriveIcon = null;
  229. floppyDriveIcon = null;
  230. newFolderIcon = null;
  231. upFolderIcon = null;
  232. homeFolderIcon = null;
  233. detailsViewIcon = null;
  234. listViewIcon = null;
  235. }
  236. protected void uninstallStrings(JFileChooser fc) {
  237. saveButtonText = null;
  238. openButtonText = null;
  239. cancelButtonText = null;
  240. updateButtonText = null;
  241. helpButtonText = null;
  242. directoryOpenButtonText = null;
  243. saveButtonToolTipText = null;
  244. openButtonToolTipText = null;
  245. cancelButtonToolTipText = null;
  246. updateButtonToolTipText = null;
  247. helpButtonToolTipText = null;
  248. directoryOpenButtonToolTipText = null;
  249. }
  250. protected void createModel() {
  251. model = new BasicDirectoryModel(getFileChooser());
  252. }
  253. public BasicDirectoryModel getModel() {
  254. return model;
  255. }
  256. public PropertyChangeListener createPropertyChangeListener(JFileChooser fc) {
  257. return null;
  258. }
  259. public String getFileName() {
  260. return null;
  261. }
  262. public String getDirectoryName() {
  263. return null;
  264. }
  265. public void setFileName(String filename) {
  266. }
  267. public void setDirectoryName(String dirname) {
  268. }
  269. public void rescanCurrentDirectory(JFileChooser fc) {
  270. }
  271. public void ensureFileIsVisible(JFileChooser fc, File f) {
  272. }
  273. public JFileChooser getFileChooser() {
  274. return filechooser;
  275. }
  276. public JPanel getAccessoryPanel() {
  277. return accessoryPanel;
  278. }
  279. protected JButton getApproveButton(JFileChooser fc) {
  280. return null;
  281. }
  282. public String getApproveButtonToolTipText(JFileChooser fc) {
  283. String tooltipText = fc.getApproveButtonToolTipText();
  284. if(tooltipText != null) {
  285. return tooltipText;
  286. }
  287. if(fc.getDialogType() == JFileChooser.OPEN_DIALOG) {
  288. return openButtonToolTipText;
  289. } else if(fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
  290. return saveButtonToolTipText;
  291. }
  292. return null;
  293. }
  294. public void clearIconCache() {
  295. fileView.clearIconCache();
  296. }
  297. // ********************************************
  298. // ************ Create Listeners **************
  299. // ********************************************
  300. public ListSelectionListener createListSelectionListener(JFileChooser fc) {
  301. return new SelectionListener();
  302. }
  303. protected class DoubleClickListener extends MouseAdapter {
  304. JList list;
  305. public DoubleClickListener(JList list) {
  306. this.list = list;
  307. }
  308. /**
  309. * The JList used for representing the files is created by subclasses, but the
  310. * selection is monitored in this class. The TransferHandler installed in the
  311. * JFileChooser is also installed in the file list as it is used as the actual
  312. * transfer source. The list is updated on a mouse enter to reflect the current
  313. * data transfer state of the file chooser.
  314. */
  315. public void mouseEntered(MouseEvent e) {
  316. TransferHandler th1 = filechooser.getTransferHandler();
  317. TransferHandler th2 = list.getTransferHandler();
  318. if (th1 != th2) {
  319. list.setTransferHandler(th1);
  320. }
  321. if (filechooser.getDragEnabled() != list.getDragEnabled()) {
  322. list.setDragEnabled(filechooser.getDragEnabled());
  323. }
  324. }
  325. public void mouseClicked(MouseEvent e) {
  326. if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2) {
  327. int index = list.locationToIndex(e.getPoint());
  328. if(index >= 0) {
  329. File f = (File) list.getModel().getElementAt(index);
  330. try {
  331. // Strip trailing ".."
  332. f = f.getCanonicalFile();
  333. } catch (IOException ex) {
  334. // That's ok, we'll use f as is
  335. }
  336. if(getFileChooser().isTraversable(f)) {
  337. list.clearSelection();
  338. getFileChooser().setCurrentDirectory(f);
  339. } else {
  340. getFileChooser().approveSelection();
  341. }
  342. }
  343. }
  344. }
  345. }
  346. protected MouseListener createDoubleClickListener(JFileChooser fc, JList list) {
  347. return new DoubleClickListener(list);
  348. }
  349. /**
  350. * Property to remember whether a directory is currently selected in the UI.
  351. *
  352. * @return <code>true</code> iff a directory is currently selected.
  353. * @since 1.4
  354. */
  355. protected boolean isDirectorySelected() {
  356. return directorySelected;
  357. }
  358. /**
  359. * Property to remember whether a directory is currently selected in the UI.
  360. * This is normally called by the UI on a selection event.
  361. *
  362. * @param b iff a directory is currently selected.
  363. * @since 1.4
  364. */
  365. protected void setDirectorySelected(boolean b) {
  366. directorySelected = b;
  367. }
  368. /**
  369. * Property to remember the directory that is currently selected in the UI.
  370. *
  371. * @return the value of the <code>directory</code> property
  372. * @see #setDirectory
  373. * @since 1.4
  374. */
  375. protected File getDirectory() {
  376. return directory;
  377. }
  378. /**
  379. * Property to remember the directory that is currently selected in the UI.
  380. * This is normally called by the UI on a selection event.
  381. *
  382. * @param f the <code>File</code> object representing the directory that is
  383. * currently selected
  384. * @since 1.4
  385. */
  386. protected void setDirectory(File f) {
  387. directory = f;
  388. }
  389. protected class SelectionListener implements ListSelectionListener {
  390. public void valueChanged(ListSelectionEvent e) {
  391. if(!e.getValueIsAdjusting()) {
  392. JFileChooser chooser = getFileChooser();
  393. JList list = (JList) e.getSource();
  394. if (chooser.isMultiSelectionEnabled()) {
  395. File[] files = null;
  396. Object[] objects = list.getSelectedValues();
  397. if (objects != null) {
  398. if (objects.length == 1
  399. && ((File)objects[0]).isDirectory()
  400. && chooser.isTraversable(((File)objects[0]))
  401. && (chooser.getFileSelectionMode() != chooser.DIRECTORIES_ONLY
  402. || !chooser.getFileSystemView().isFileSystem(((File)objects[0])))) {
  403. setDirectorySelected(true);
  404. setDirectory(((File)objects[0]));
  405. } else {
  406. ArrayList fList = new ArrayList(objects.length);
  407. for (int i = 0; i < objects.length; i++) {
  408. File f = (File)objects[i];
  409. if ((chooser.isFileSelectionEnabled() && f.isFile())
  410. || (chooser.isDirectorySelectionEnabled() && f.isDirectory())) {
  411. fList.add(f);
  412. }
  413. }
  414. if (fList.size() > 0) {
  415. files = (File[])fList.toArray(new File[fList.size()]);
  416. }
  417. setDirectorySelected(false);
  418. }
  419. }
  420. chooser.setSelectedFiles(files);
  421. } else {
  422. File file = (File)list.getSelectedValue();
  423. if (file != null
  424. && file.isDirectory()
  425. && chooser.isTraversable(file)
  426. && (chooser.getFileSelectionMode() != chooser.DIRECTORIES_ONLY
  427. || !chooser.getFileSystemView().isFileSystem(file))) {
  428. setDirectorySelected(true);
  429. setDirectory(file);
  430. } else {
  431. setDirectorySelected(false);
  432. if (file != null) {
  433. chooser.setSelectedFile(file);
  434. }
  435. }
  436. }
  437. }
  438. }
  439. }
  440. // *******************************************************
  441. // ************ FileChooser UI PLAF methods **************
  442. // *******************************************************
  443. /**
  444. * Returns the default accept all file filter
  445. */
  446. public FileFilter getAcceptAllFileFilter(JFileChooser fc) {
  447. return acceptAllFileFilter;
  448. }
  449. public FileView getFileView(JFileChooser fc) {
  450. return fileView;
  451. }
  452. /**
  453. * Returns the title of this dialog
  454. */
  455. public String getDialogTitle(JFileChooser fc) {
  456. String dialogTitle = fc.getDialogTitle();
  457. if (dialogTitle != null) {
  458. return dialogTitle;
  459. } else if (fc.getDialogType() == JFileChooser.OPEN_DIALOG) {
  460. return openDialogTitleText;
  461. } else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
  462. return saveDialogTitleText;
  463. } else {
  464. return getApproveButtonText(fc);
  465. }
  466. }
  467. public int getApproveButtonMnemonic(JFileChooser fc) {
  468. int mnemonic = fc.getApproveButtonMnemonic();
  469. if (mnemonic > 0) {
  470. return mnemonic;
  471. } else if (fc.getDialogType() == JFileChooser.OPEN_DIALOG) {
  472. return openButtonMnemonic;
  473. } else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
  474. return saveButtonMnemonic;
  475. } else {
  476. return mnemonic;
  477. }
  478. }
  479. public String getApproveButtonText(JFileChooser fc) {
  480. String buttonText = fc.getApproveButtonText();
  481. if (buttonText != null) {
  482. return buttonText;
  483. } else if (fc.getDialogType() == JFileChooser.OPEN_DIALOG) {
  484. return openButtonText;
  485. } else if (fc.getDialogType() == JFileChooser.SAVE_DIALOG) {
  486. return saveButtonText;
  487. } else {
  488. return null;
  489. }
  490. }
  491. // *****************************
  492. // ***** Directory Actions *****
  493. // *****************************
  494. public Action getNewFolderAction() {
  495. return newFolderAction;
  496. }
  497. public Action getGoHomeAction() {
  498. return goHomeAction;
  499. }
  500. public Action getChangeToParentDirectoryAction() {
  501. return changeToParentDirectoryAction;
  502. }
  503. public Action getApproveSelectionAction() {
  504. return approveSelectionAction;
  505. }
  506. public Action getCancelSelectionAction() {
  507. return cancelSelectionAction;
  508. }
  509. public Action getUpdateAction() {
  510. return updateAction;
  511. }
  512. /**
  513. * Creates a new folder.
  514. */
  515. protected class NewFolderAction extends AbstractAction {
  516. protected NewFolderAction() {
  517. super("New Folder");
  518. }
  519. public void actionPerformed(ActionEvent e) {
  520. JFileChooser fc = getFileChooser();
  521. File currentDirectory = fc.getCurrentDirectory();
  522. File newFolder = null;
  523. try {
  524. newFolder = fc.getFileSystemView().createNewFolder(currentDirectory);
  525. if (fc.isMultiSelectionEnabled()) {
  526. fc.setSelectedFiles(new File[] { newFolder });
  527. } else {
  528. fc.setSelectedFile(newFolder);
  529. }
  530. } catch (IOException exc) {
  531. JOptionPane.showMessageDialog(
  532. fc,
  533. newFolderErrorText + newFolderErrorSeparator + exc,
  534. newFolderErrorText, JOptionPane.ERROR_MESSAGE);
  535. return;
  536. }
  537. fc.rescanCurrentDirectory();
  538. }
  539. }
  540. /**
  541. * Acts on the "home" key event or equivalent event.
  542. */
  543. protected class GoHomeAction extends AbstractAction {
  544. protected GoHomeAction() {
  545. super("Go Home");
  546. }
  547. public void actionPerformed(ActionEvent e) {
  548. JFileChooser fc = getFileChooser();
  549. fc.setCurrentDirectory(fc.getFileSystemView().getHomeDirectory());
  550. }
  551. }
  552. protected class ChangeToParentDirectoryAction extends AbstractAction {
  553. protected ChangeToParentDirectoryAction() {
  554. super("Go Up");
  555. }
  556. public void actionPerformed(ActionEvent e) {
  557. Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
  558. if (focusOwner == null || !(focusOwner instanceof javax.swing.text.JTextComponent)) {
  559. getFileChooser().changeToParentDirectory();
  560. }
  561. }
  562. }
  563. /**
  564. * Responds to an Open or Save request
  565. */
  566. protected class ApproveSelectionAction extends AbstractAction {
  567. protected ApproveSelectionAction() {
  568. super("approveSelection");
  569. }
  570. public void actionPerformed(ActionEvent e) {
  571. if (isDirectorySelected()) {
  572. File dir = getDirectory();
  573. if (dir != null) {
  574. try {
  575. // Strip trailing ".."
  576. dir = dir.getCanonicalFile();
  577. } catch (IOException ex) {
  578. // Ok, use f as is
  579. }
  580. getFileChooser().setCurrentDirectory(dir);
  581. return;
  582. }
  583. }
  584. JFileChooser chooser = getFileChooser();
  585. String filename = getFileName();
  586. FileSystemView fs = chooser.getFileSystemView();
  587. File dir = chooser.getCurrentDirectory();
  588. if (filename != null) {
  589. // Remove whitespace from beginning and end of filename
  590. filename = filename.trim();
  591. }
  592. if (filename == null || filename.equals("")) {
  593. // no file selected, multiple selection off, therefore cancel the approve action
  594. resetGlobFilter();
  595. return;
  596. }
  597. File selectedFile = null;
  598. File[] selectedFiles = null;
  599. if (filename != null && !filename.equals("")) {
  600. // Unix: Resolve '~' to user's home directory
  601. if (File.separatorChar == '/') {
  602. if (filename.startsWith("~/")) {
  603. filename = System.getProperty("user.home") + filename.substring(1);
  604. } else if (filename.equals("~")) {
  605. filename = System.getProperty("user.home");
  606. }
  607. }
  608. if (chooser.isMultiSelectionEnabled() && filename.startsWith("\"")) {
  609. ArrayList fList = new ArrayList();
  610. filename = filename.substring(1);
  611. if (filename.endsWith("\"")) {
  612. filename = filename.substring(0, filename.length()-1);
  613. }
  614. File[] children = null;
  615. int childIndex = 0;
  616. do {
  617. String str;
  618. int i = filename.indexOf("\" \"");
  619. if (i > 0) {
  620. str = filename.substring(0, i);
  621. filename = filename.substring(i+3);
  622. } else {
  623. str = filename;
  624. filename = "";
  625. }
  626. File file = fs.createFileObject(str);
  627. if (!file.isAbsolute()) {
  628. if (children == null) {
  629. children = fs.getFiles(dir, false);
  630. Arrays.sort(children);
  631. }
  632. for (int k = 0; k < children.length; k++) {
  633. int l = (childIndex + k) % children.length;
  634. if (children[l].getName().equals(str)) {
  635. file = children[l];
  636. childIndex = l + 1;
  637. break;
  638. }
  639. }
  640. }
  641. fList.add(file);
  642. } while (filename.length() > 0);
  643. if (fList.size() > 0) {
  644. selectedFiles = (File[])fList.toArray(new File[fList.size()]);
  645. }
  646. resetGlobFilter();
  647. } else {
  648. selectedFile = fs.createFileObject(filename);
  649. if(!selectedFile.isAbsolute()) {
  650. selectedFile = fs.getChild(dir, filename);
  651. }
  652. // check for wildcard pattern
  653. FileFilter currentFilter = chooser.getFileFilter();
  654. if (!selectedFile.exists() && isGlobPattern(filename)) {
  655. if (globFilter == null) {
  656. globFilter = new GlobFilter();
  657. }
  658. try {
  659. globFilter.setPattern(filename);
  660. if (!(currentFilter instanceof GlobFilter)) {
  661. actualFileFilter = currentFilter;
  662. }
  663. chooser.setFileFilter(null);
  664. chooser.setFileFilter(globFilter);
  665. return;
  666. } catch (PatternSyntaxException pse) {
  667. // Not a valid glob pattern. Abandon filter.
  668. }
  669. }
  670. resetGlobFilter();
  671. // Check for directory change action
  672. boolean isDir = (selectedFile != null && selectedFile.isDirectory());
  673. boolean isTrav = (selectedFile != null && chooser.isTraversable(selectedFile));
  674. boolean isDirSelEnabled = chooser.isDirectorySelectionEnabled();
  675. boolean isFileSelEnabled = chooser.isFileSelectionEnabled();
  676. if (isDir && isTrav && !isDirSelEnabled) {
  677. chooser.setCurrentDirectory(selectedFile);
  678. return;
  679. } else if ((isDir || !isFileSelEnabled)
  680. && (!isDir || !isDirSelEnabled)
  681. && (!isDirSelEnabled || selectedFile.exists())) {
  682. selectedFile = null;
  683. }
  684. }
  685. }
  686. if (selectedFiles != null || selectedFile != null) {
  687. if (selectedFiles != null) {
  688. chooser.setSelectedFiles(selectedFiles);
  689. } else if (chooser.isMultiSelectionEnabled()) {
  690. chooser.setSelectedFiles(new File[] { selectedFile });
  691. } else {
  692. chooser.setSelectedFile(selectedFile);
  693. }
  694. chooser.approveSelection();
  695. } else {
  696. if (chooser.isMultiSelectionEnabled()) {
  697. chooser.setSelectedFiles(null);
  698. } else {
  699. chooser.setSelectedFile(null);
  700. }
  701. chooser.cancelSelection();
  702. }
  703. }
  704. }
  705. private void resetGlobFilter() {
  706. if (actualFileFilter != null) {
  707. JFileChooser chooser = getFileChooser();
  708. FileFilter currentFilter = chooser.getFileFilter();
  709. if (currentFilter != null && currentFilter.equals(globFilter)) {
  710. chooser.setFileFilter(actualFileFilter);
  711. chooser.removeChoosableFileFilter(globFilter);
  712. }
  713. actualFileFilter = null;
  714. }
  715. }
  716. private static boolean isGlobPattern(String filename) {
  717. return ((File.separatorChar == '\\' && filename.indexOf('*') >= 0)
  718. || (File.separatorChar == '/' && (filename.indexOf('*') >= 0
  719. || filename.indexOf('?') >= 0
  720. || filename.indexOf('[') >= 0)));
  721. }
  722. /* A file filter which accepts file patterns containing
  723. * the special wildcard '*' on windows, plus '?', and '[ ]' on Unix.
  724. */
  725. class GlobFilter extends FileFilter {
  726. Pattern pattern;
  727. String globPattern;
  728. public void setPattern(String globPattern) {
  729. char[] gPat = globPattern.toCharArray();
  730. char[] rPat = new char[gPat.length * 2];
  731. boolean isWin32 = (File.separatorChar == '\\');
  732. boolean inBrackets = false;
  733. StringBuffer buf = new StringBuffer();
  734. int j = 0;
  735. this.globPattern = globPattern;
  736. if (isWin32) {
  737. // On windows, a pattern ending with *.* is equal to ending with *
  738. int len = gPat.length;
  739. if (globPattern.endsWith("*.*")) {
  740. len -= 2;
  741. }
  742. for (int i = 0; i < len; i++) {
  743. switch(gPat[i]) {
  744. case '*':
  745. rPat[j++] = '.';
  746. rPat[j++] = '*';
  747. break;
  748. case '\\':
  749. rPat[j++] = '\\';
  750. rPat[j++] = '\\';
  751. break;
  752. default:
  753. if ("+()^$.{}[]".indexOf(gPat[i]) >= 0) {
  754. rPat[j++] = '\\';
  755. }
  756. rPat[j++] = gPat[i];
  757. break;
  758. }
  759. }
  760. } else {
  761. for (int i = 0; i < gPat.length; i++) {
  762. switch(gPat[i]) {
  763. case '*':
  764. if (!inBrackets) {
  765. rPat[j++] = '.';
  766. }
  767. rPat[j++] = '*';
  768. break;
  769. case '?':
  770. rPat[j++] = inBrackets ? '?' : '.';
  771. break;
  772. case '[':
  773. inBrackets = true;
  774. rPat[j++] = gPat[i];
  775. if (i < gPat.length - 1) {
  776. switch (gPat[i+1]) {
  777. case '!':
  778. case '^':
  779. rPat[j++] = '^';
  780. i++;
  781. break;
  782. case ']':
  783. rPat[j++] = gPat[++i];
  784. break;
  785. }
  786. }
  787. break;
  788. case ']':
  789. rPat[j++] = gPat[i];
  790. inBrackets = false;
  791. break;
  792. case '\\':
  793. if (i == 0 && gPat.length > 1 && gPat[1] == '~') {
  794. rPat[j++] = gPat[++i];
  795. } else {
  796. rPat[j++] = '\\';
  797. if (i < gPat.length - 1 && "*?[]".indexOf(gPat[i+1]) >= 0) {
  798. rPat[j++] = gPat[++i];
  799. } else {
  800. rPat[j++] = '\\';
  801. }
  802. }
  803. break;
  804. default:
  805. //if ("+()|^$.{}<>".indexOf(gPat[i]) >= 0) {
  806. if (!Character.isLetterOrDigit(gPat[i])) {
  807. rPat[j++] = '\\';
  808. }
  809. rPat[j++] = gPat[i];
  810. break;
  811. }
  812. }
  813. }
  814. this.pattern = Pattern.compile(new String(rPat, 0, j), Pattern.CASE_INSENSITIVE);
  815. }
  816. public boolean accept(File f) {
  817. if (f == null) {
  818. return false;
  819. }
  820. if (f.isDirectory()) {
  821. return true;
  822. }
  823. return pattern.matcher(f.getName()).matches();
  824. }
  825. public String getDescription() {
  826. return globPattern;
  827. }
  828. }
  829. /**
  830. * Responds to a cancel request.
  831. */
  832. protected class CancelSelectionAction extends AbstractAction {
  833. public void actionPerformed(ActionEvent e) {
  834. getFileChooser().cancelSelection();
  835. }
  836. }
  837. /**
  838. * Rescans the files in the current directory
  839. */
  840. protected class UpdateAction extends AbstractAction {
  841. public void actionPerformed(ActionEvent e) {
  842. JFileChooser fc = getFileChooser();
  843. fc.setCurrentDirectory(fc.getFileSystemView().createFileObject(getDirectoryName()));
  844. fc.rescanCurrentDirectory();
  845. }
  846. }
  847. // *****************************************
  848. // ***** default AcceptAll file filter *****
  849. // *****************************************
  850. protected class AcceptAllFileFilter extends FileFilter {
  851. public AcceptAllFileFilter() {
  852. }
  853. public boolean accept(File f) {
  854. return true;
  855. }
  856. public String getDescription() {
  857. return UIManager.getString("FileChooser.acceptAllFileFilterText",
  858. getFileChooser().getLocale());
  859. }
  860. }
  861. // ***********************
  862. // * FileView operations *
  863. // ***********************
  864. protected class BasicFileView extends FileView {
  865. /* FileView type descriptions */
  866. // PENDING(jeff) - pass in the icon cache size
  867. protected Hashtable iconCache = new Hashtable();
  868. public BasicFileView() {
  869. }
  870. public void clearIconCache() {
  871. iconCache = new Hashtable();
  872. }
  873. public String getName(File f) {
  874. // Note: Returns display name rather than file name
  875. String fileName = null;
  876. if(f != null) {
  877. fileName = getFileChooser().getFileSystemView().getSystemDisplayName(f);
  878. }
  879. return fileName;
  880. }
  881. public String getDescription(File f) {
  882. return f.getName();
  883. }
  884. public String getTypeDescription(File f) {
  885. String type = getFileChooser().getFileSystemView().getSystemTypeDescription(f);
  886. if (type == null) {
  887. if (f.isDirectory()) {
  888. type = directoryDescriptionText;
  889. } else {
  890. type = fileDescriptionText;
  891. }
  892. }
  893. return type;
  894. }
  895. public Icon getCachedIcon(File f) {
  896. return (Icon) iconCache.get(f);
  897. }
  898. public void cacheIcon(File f, Icon i) {
  899. if(f == null || i == null) {
  900. return;
  901. }
  902. iconCache.put(f, i);
  903. }
  904. public Icon getIcon(File f) {
  905. Icon icon = getCachedIcon(f);
  906. if(icon != null) {
  907. return icon;
  908. }
  909. icon = fileIcon;
  910. if (f != null) {
  911. FileSystemView fsv = getFileChooser().getFileSystemView();
  912. if (fsv.isFloppyDrive(f)) {
  913. icon = floppyDriveIcon;
  914. } else if (fsv.isDrive(f)) {
  915. icon = hardDriveIcon;
  916. } else if (fsv.isComputerNode(f)) {
  917. icon = computerIcon;
  918. } else if (f.isDirectory()) {
  919. icon = directoryIcon;
  920. }
  921. }
  922. cacheIcon(f, icon);
  923. return icon;
  924. }
  925. public Boolean isHidden(File f) {
  926. String name = f.getName();
  927. if(name != null && name.charAt(0) == '.') {
  928. return Boolean.TRUE;
  929. } else {
  930. return Boolean.FALSE;
  931. }
  932. }
  933. }
  934. private static final TransferHandler defaultTransferHandler = new FileTransferHandler();
  935. /**
  936. * Data transfer support for the file chooser. Since files are currently presented
  937. * as a list, the list support is reused with the added flavor of DataFlavor.javaFileListFlavor
  938. */
  939. static class FileTransferHandler extends TransferHandler implements UIResource {
  940. /**
  941. * Create a Transferable to use as the source for a data transfer.
  942. *
  943. * @param c The component holding the data to be transfered. This
  944. * argument is provided to enable sharing of TransferHandlers by
  945. * multiple components.
  946. * @return The representation of the data to be transfered.
  947. *
  948. */
  949. protected Transferable createTransferable(JComponent c) {
  950. Object[] values = null;
  951. if (c instanceof JList) {
  952. values = ((JList)c).getSelectedValues();
  953. } else if (c instanceof JTable) {
  954. JTable table = (JTable)c;
  955. int[] rows = table.getSelectedRows();
  956. if (rows != null) {
  957. values = new Object[rows.length];
  958. for (int i=0; i<rows.length; i++) {
  959. values[i] = table.getValueAt(rows[i], 0);
  960. }
  961. }
  962. }
  963. if (values == null || values.length == 0) {
  964. return null;
  965. }
  966. StringBuffer plainBuf = new StringBuffer();
  967. StringBuffer htmlBuf = new StringBuffer();
  968. htmlBuf.append("<html>\n<body>\n<ul>\n");
  969. for (int i = 0; i < values.length; i++) {
  970. Object obj = values[i];
  971. String val = ((obj == null) ? "" : obj.toString());
  972. plainBuf.append(val + "\n");
  973. htmlBuf.append(" <li>" + val + "\n");
  974. }
  975. // remove the last newline
  976. plainBuf.deleteCharAt(plainBuf.length() - 1);
  977. htmlBuf.append("</ul>\n</body>\n</html>");
  978. return new FileTransferable(plainBuf.toString(), htmlBuf.toString(), values);
  979. }
  980. public int getSourceActions(JComponent c) {
  981. return COPY;
  982. }
  983. static class FileTransferable extends BasicTransferable {
  984. Object[] fileData;
  985. FileTransferable(String plainData, String htmlData, Object[] fileData) {
  986. super(plainData, htmlData);
  987. this.fileData = fileData;
  988. }
  989. /**
  990. * Best format of the file chooser is DataFlavor.javaFileListFlavor.
  991. */
  992. protected DataFlavor[] getRicherFlavors() {
  993. DataFlavor[] flavors = new DataFlavor[1];
  994. flavors[0] = DataFlavor.javaFileListFlavor;
  995. return flavors;
  996. }
  997. /**
  998. * The only richer format supported is the file list flavor
  999. */
  1000. protected Object getRicherData(DataFlavor flavor) {
  1001. if (DataFlavor.javaFileListFlavor.equals(flavor)) {
  1002. ArrayList files = new ArrayList();
  1003. for (int i = 0; i < fileData.length; i++) {
  1004. files.add(fileData[i]);
  1005. }
  1006. return files;
  1007. }
  1008. return null;
  1009. }
  1010. }
  1011. }
  1012. }