1. /*
  2. * @(#)WindowsFileChooserUI.java 1.88 04/03/30
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.java.swing.plaf.windows;
  8. import javax.swing.*;
  9. import javax.swing.border.*;
  10. import javax.swing.filechooser.*;
  11. import javax.swing.event.*;
  12. import javax.swing.plaf.*;
  13. import javax.swing.plaf.basic.*;
  14. import java.awt.*;
  15. import java.awt.event.*;
  16. import java.beans.*;
  17. import java.io.File;
  18. import java.io.FileNotFoundException;
  19. import java.io.IOException;
  20. import java.util.*;
  21. import sun.awt.shell.ShellFolder;
  22. import sun.swing.*;
  23. import com.sun.java.swing.SwingUtilities2;
  24. /**
  25. * Windows L&F implementation of a FileChooser.
  26. *
  27. * @version 1.88 03/30/04
  28. * @author Jeff Dinkins
  29. */
  30. public class WindowsFileChooserUI extends BasicFileChooserUI {
  31. // The following are private because the implementation of the
  32. // Windows FileChooser L&F is not complete yet.
  33. private static final String[] OS_NAMES =
  34. new String[] { "Windows 3.1", "Windows 95", "Windows NT",
  35. "Windows 98", "Windows 2000", "Windows Me", "Windows XP" };
  36. private static int WIN_31 = 0;
  37. private static int WIN_95 = 1;
  38. private static int WIN_NT = 2;
  39. private static int WIN_98 = 3;
  40. private static int WIN_2k = 4;
  41. private static int WIN_Me = 5;
  42. private static int WIN_XP = 6;
  43. private static String osName = System.getProperty("os.name");
  44. private static String osVersion = System.getProperty("os.version");
  45. private static final String OS_NAME = ((osName.equals(OS_NAMES[WIN_98]) && osVersion.startsWith("4.9"))
  46. ? "Windows Me" : osName);
  47. private static final int OS_LEVEL = Arrays.asList(OS_NAMES).indexOf(OS_NAME);
  48. private JPanel centerPanel;
  49. private JLabel lookInLabel;
  50. private JComboBox directoryComboBox;
  51. private DirectoryComboBoxModel directoryComboBoxModel;
  52. private ActionListener directoryComboBoxAction = new DirectoryComboBoxAction();
  53. private FilterComboBoxModel filterComboBoxModel;
  54. private JTextField filenameTextField;
  55. private JToggleButton listViewButton;
  56. private JToggleButton detailsViewButton;
  57. private FilePane filePane;
  58. private WindowsPlacesBar placesBar;
  59. private boolean useShellFolder;
  60. private JButton approveButton;
  61. private JButton cancelButton;
  62. private JPanel buttonPanel;
  63. private JPanel bottomPanel;
  64. private JComboBox filterComboBox;
  65. private static final Dimension hstrut10 = new Dimension(10, 1);
  66. private static final Dimension vstrut4 = new Dimension(1, 4);
  67. private static final Dimension vstrut6 = new Dimension(1, 6);
  68. private static final Dimension vstrut8 = new Dimension(1, 8);
  69. private static final Insets shrinkwrap = new Insets(0,0,0,0);
  70. // Preferred and Minimum sizes for the dialog box
  71. private static int PREF_WIDTH = 425;
  72. private static int PREF_HEIGHT = 245;
  73. private static Dimension PREF_SIZE = new Dimension(PREF_WIDTH, PREF_HEIGHT);
  74. private static int MIN_WIDTH = 425;
  75. private static int MIN_HEIGHT = 245;
  76. private static Dimension MIN_SIZE = new Dimension(MIN_WIDTH, MIN_HEIGHT);
  77. private static int LIST_PREF_WIDTH = 444;
  78. private static int LIST_PREF_HEIGHT = 138;
  79. private static Dimension LIST_PREF_SIZE = new Dimension(LIST_PREF_WIDTH, LIST_PREF_HEIGHT);
  80. // Labels, mnemonics, and tooltips (oh my!)
  81. private int lookInLabelMnemonic = 0;
  82. private String lookInLabelText = null;
  83. private String saveInLabelText = null;
  84. private int fileNameLabelMnemonic = 0;
  85. private String fileNameLabelText = null;
  86. private int filesOfTypeLabelMnemonic = 0;
  87. private String filesOfTypeLabelText = null;
  88. private String upFolderToolTipText = null;
  89. private String upFolderAccessibleName = null;
  90. private String homeFolderToolTipText = null;
  91. private String homeFolderAccessibleName = null;
  92. private String newFolderToolTipText = null;
  93. private String newFolderAccessibleName = null;
  94. private String listViewButtonToolTipText = null;
  95. private String listViewButtonAccessibleName = null;
  96. private String detailsViewButtonToolTipText = null;
  97. private String detailsViewButtonAccessibleName = null;
  98. private BasicFileView fileView = new WindowsFileView();
  99. //
  100. // ComponentUI Interface Implementation methods
  101. //
  102. public static ComponentUI createUI(JComponent c) {
  103. return new WindowsFileChooserUI((JFileChooser) c);
  104. }
  105. public WindowsFileChooserUI(JFileChooser filechooser) {
  106. super(filechooser);
  107. }
  108. public void installUI(JComponent c) {
  109. super.installUI(c);
  110. }
  111. public void uninstallComponents(JFileChooser fc) {
  112. fc.removeAll();
  113. }
  114. private class WindowsFileChooserUIAccessor implements FilePane.FileChooserUIAccessor {
  115. public JFileChooser getFileChooser() {
  116. return WindowsFileChooserUI.this.getFileChooser();
  117. }
  118. public BasicDirectoryModel getModel() {
  119. return WindowsFileChooserUI.this.getModel();
  120. }
  121. public JPanel createList() {
  122. return WindowsFileChooserUI.this.createList(getFileChooser());
  123. }
  124. public JPanel createDetailsView() {
  125. return WindowsFileChooserUI.this.createDetailsView(getFileChooser());
  126. }
  127. public boolean isDirectorySelected() {
  128. return WindowsFileChooserUI.this.isDirectorySelected();
  129. }
  130. public File getDirectory() {
  131. return WindowsFileChooserUI.this.getDirectory();
  132. }
  133. public Action getChangeToParentDirectoryAction() {
  134. return WindowsFileChooserUI.this.getChangeToParentDirectoryAction();
  135. }
  136. public Action getApproveSelectionAction() {
  137. return WindowsFileChooserUI.this.getApproveSelectionAction();
  138. }
  139. public Action getNewFolderAction() {
  140. return WindowsFileChooserUI.this.getNewFolderAction();
  141. }
  142. public MouseListener createDoubleClickListener(JList list) {
  143. return WindowsFileChooserUI.this.createDoubleClickListener(getFileChooser(),
  144. list);
  145. }
  146. public ListSelectionListener createListSelectionListener() {
  147. return WindowsFileChooserUI.this.createListSelectionListener(getFileChooser());
  148. }
  149. }
  150. public void installComponents(JFileChooser fc) {
  151. filePane = new FilePane(new WindowsFileChooserUIAccessor());
  152. fc.addPropertyChangeListener(filePane);
  153. FileSystemView fsv = fc.getFileSystemView();
  154. fc.setBorder(new EmptyBorder(4, 10, 10, 10));
  155. fc.setLayout(new BorderLayout(8, 8));
  156. updateUseShellFolder();
  157. // ********************************* //
  158. // **** Construct the top panel **** //
  159. // ********************************* //
  160. // Directory manipulation buttons
  161. JToolBar topPanel = new JToolBar();
  162. topPanel.setFloatable(false);
  163. if (OS_LEVEL >= WIN_2k) {
  164. topPanel.putClientProperty("JToolBar.isRollover", Boolean.TRUE);
  165. }
  166. // Add the top panel to the fileChooser
  167. fc.add(topPanel, BorderLayout.NORTH);
  168. // ComboBox Label
  169. lookInLabel = new JLabel(lookInLabelText, JLabel.TRAILING) {
  170. public Dimension getPreferredSize() {
  171. return getMinimumSize();
  172. }
  173. public Dimension getMinimumSize() {
  174. Dimension d = super.getPreferredSize();
  175. if (placesBar != null) {
  176. d.width = Math.max(d.width, placesBar.getWidth());
  177. }
  178. return d;
  179. }
  180. };
  181. lookInLabel.setDisplayedMnemonic(lookInLabelMnemonic);
  182. lookInLabel.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  183. lookInLabel.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  184. topPanel.add(lookInLabel);
  185. topPanel.add(Box.createRigidArea(new Dimension(8,0)));
  186. // CurrentDir ComboBox
  187. directoryComboBox = new JComboBox() {
  188. public Dimension getMinimumSize() {
  189. Dimension d = super.getMinimumSize();
  190. d.width = 60;
  191. return d;
  192. }
  193. public Dimension getPreferredSize() {
  194. Dimension d = super.getPreferredSize();
  195. // Must be small enough to not affect total width.
  196. d.width = 150;
  197. return d;
  198. }
  199. };
  200. directoryComboBox.putClientProperty( "JComboBox.lightweightKeyboardNavigation", "Lightweight" );
  201. lookInLabel.setLabelFor(directoryComboBox);
  202. directoryComboBoxModel = createDirectoryComboBoxModel(fc);
  203. directoryComboBox.setModel(directoryComboBoxModel);
  204. directoryComboBox.addActionListener(directoryComboBoxAction);
  205. directoryComboBox.setRenderer(createDirectoryComboBoxRenderer(fc));
  206. directoryComboBox.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  207. directoryComboBox.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  208. directoryComboBox.setMaximumRowCount(8);
  209. topPanel.add(directoryComboBox);
  210. topPanel.add(Box.createRigidArea(hstrut10));
  211. // Up Button
  212. JButton upFolderButton = new JButton(getChangeToParentDirectoryAction());
  213. upFolderButton.setText(null);
  214. upFolderButton.setIcon(upFolderIcon);
  215. upFolderButton.setToolTipText(upFolderToolTipText);
  216. upFolderButton.getAccessibleContext().setAccessibleName(upFolderAccessibleName);
  217. upFolderButton.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  218. upFolderButton.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  219. upFolderButton.setMargin(shrinkwrap);
  220. upFolderButton.setFocusPainted(false);
  221. topPanel.add(upFolderButton);
  222. if (OS_LEVEL < WIN_2k) {
  223. topPanel.add(Box.createRigidArea(hstrut10));
  224. }
  225. JButton b;
  226. if (OS_LEVEL == WIN_98) {
  227. // Desktop Button
  228. File homeDir = fsv.getHomeDirectory();
  229. String toolTipText = homeFolderToolTipText;
  230. if (fsv.isRoot(homeDir)) {
  231. toolTipText = getFileView(fc).getName(homeDir); // Probably "Desktop".
  232. }
  233. b = new JButton(getFileView(fc).getIcon(homeDir));
  234. b.setToolTipText(toolTipText);
  235. b.getAccessibleContext().setAccessibleName(toolTipText);
  236. b.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  237. b.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  238. b.setMargin(shrinkwrap);
  239. b.setFocusPainted(false);
  240. b.addActionListener(getGoHomeAction());
  241. topPanel.add(b);
  242. topPanel.add(Box.createRigidArea(hstrut10));
  243. }
  244. // New Directory Button
  245. if (!UIManager.getBoolean("FileChooser.readOnly")) {
  246. b = new JButton(filePane.getNewFolderAction());
  247. b.setText(null);
  248. b.setIcon(newFolderIcon);
  249. b.setToolTipText(newFolderToolTipText);
  250. b.getAccessibleContext().setAccessibleName(newFolderAccessibleName);
  251. b.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  252. b.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  253. b.setMargin(shrinkwrap);
  254. b.setFocusPainted(false);
  255. topPanel.add(b);
  256. }
  257. if (OS_LEVEL < WIN_2k) {
  258. topPanel.add(Box.createRigidArea(hstrut10));
  259. }
  260. // View button group
  261. ButtonGroup viewButtonGroup = new ButtonGroup();
  262. // List Button
  263. listViewButton = new JToggleButton(listViewIcon);
  264. listViewButton.setToolTipText(listViewButtonToolTipText);
  265. listViewButton.getAccessibleContext().setAccessibleName(listViewButtonAccessibleName);
  266. listViewButton.setFocusPainted(false);
  267. listViewButton.setSelected(true);
  268. listViewButton.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  269. listViewButton.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  270. listViewButton.setMargin(shrinkwrap);
  271. listViewButton.addActionListener(filePane.getViewTypeAction(FilePane.VIEWTYPE_LIST));
  272. topPanel.add(listViewButton);
  273. viewButtonGroup.add(listViewButton);
  274. // Details Button
  275. detailsViewButton = new JToggleButton(detailsViewIcon);
  276. detailsViewButton.setToolTipText(detailsViewButtonToolTipText);
  277. detailsViewButton.getAccessibleContext().setAccessibleName(detailsViewButtonAccessibleName);
  278. detailsViewButton.setFocusPainted(false);
  279. detailsViewButton.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  280. detailsViewButton.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  281. detailsViewButton.setMargin(shrinkwrap);
  282. detailsViewButton.addActionListener(filePane.getViewTypeAction(FilePane.VIEWTYPE_DETAILS));
  283. topPanel.add(detailsViewButton);
  284. viewButtonGroup.add(detailsViewButton);
  285. topPanel.add(Box.createRigidArea(new Dimension(60, 0)));
  286. filePane.addPropertyChangeListener(new PropertyChangeListener() {
  287. public void propertyChange(PropertyChangeEvent e) {
  288. if ("viewType".equals(e.getPropertyName())) {
  289. int viewType = filePane.getViewType();
  290. switch (viewType) {
  291. case FilePane.VIEWTYPE_LIST:
  292. listViewButton.setSelected(true);
  293. break;
  294. case FilePane.VIEWTYPE_DETAILS:
  295. detailsViewButton.setSelected(true);
  296. break;
  297. }
  298. }
  299. }
  300. });
  301. // ************************************** //
  302. // ******* Add the directory pane ******* //
  303. // ************************************** //
  304. centerPanel = new JPanel(new BorderLayout());
  305. centerPanel.add(getAccessoryPanel(), BorderLayout.AFTER_LINE_ENDS);
  306. JComponent accessory = fc.getAccessory();
  307. if(accessory != null) {
  308. getAccessoryPanel().add(accessory);
  309. }
  310. filePane.setPreferredSize(LIST_PREF_SIZE);
  311. centerPanel.add(filePane, BorderLayout.CENTER);
  312. fc.add(centerPanel, BorderLayout.CENTER);
  313. // ********************************** //
  314. // **** Construct the bottom panel ** //
  315. // ********************************** //
  316. getBottomPanel().setLayout(new BoxLayout(getBottomPanel(), BoxLayout.LINE_AXIS));
  317. // Add the bottom panel to file chooser
  318. centerPanel.add(getBottomPanel(), BorderLayout.SOUTH);
  319. // labels
  320. JPanel labelPanel = new JPanel();
  321. labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.PAGE_AXIS));
  322. labelPanel.add(Box.createRigidArea(vstrut4));
  323. JLabel fnl = new JLabel(fileNameLabelText);
  324. fnl.setDisplayedMnemonic(fileNameLabelMnemonic);
  325. fnl.setAlignmentY(0);
  326. labelPanel.add(fnl);
  327. labelPanel.add(Box.createRigidArea(new Dimension(1,12)));
  328. JLabel ftl = new JLabel(filesOfTypeLabelText);
  329. ftl.setDisplayedMnemonic(filesOfTypeLabelMnemonic);
  330. labelPanel.add(ftl);
  331. getBottomPanel().add(labelPanel);
  332. getBottomPanel().add(Box.createRigidArea(new Dimension(15, 0)));
  333. // file entry and filters
  334. JPanel fileAndFilterPanel = new JPanel();
  335. fileAndFilterPanel.add(Box.createRigidArea(vstrut8));
  336. fileAndFilterPanel.setLayout(new BoxLayout(fileAndFilterPanel, BoxLayout.Y_AXIS));
  337. filenameTextField = new JTextField(35) {
  338. public Dimension getMaximumSize() {
  339. return new Dimension(Short.MAX_VALUE, super.getPreferredSize().height);
  340. }
  341. };
  342. fnl.setLabelFor(filenameTextField);
  343. filenameTextField.addFocusListener(
  344. new FocusAdapter() {
  345. public void focusGained(FocusEvent e) {
  346. if (!getFileChooser().isMultiSelectionEnabled()) {
  347. filePane.clearSelection();
  348. }
  349. }
  350. }
  351. );
  352. if (fc.isMultiSelectionEnabled()) {
  353. setFileName(fileNameString(fc.getSelectedFiles()));
  354. } else {
  355. setFileName(fileNameString(fc.getSelectedFile()));
  356. }
  357. fileAndFilterPanel.add(filenameTextField);
  358. fileAndFilterPanel.add(Box.createRigidArea(vstrut8));
  359. filterComboBoxModel = createFilterComboBoxModel();
  360. fc.addPropertyChangeListener(filterComboBoxModel);
  361. filterComboBox = new JComboBox(filterComboBoxModel);
  362. ftl.setLabelFor(filterComboBox);
  363. filterComboBox.setRenderer(createFilterComboBoxRenderer());
  364. fileAndFilterPanel.add(filterComboBox);
  365. getBottomPanel().add(fileAndFilterPanel);
  366. getBottomPanel().add(Box.createRigidArea(new Dimension(30, 0)));
  367. // buttons
  368. getButtonPanel().setLayout(new BoxLayout(getButtonPanel(), BoxLayout.Y_AXIS));
  369. approveButton = new JButton(getApproveButtonText(fc)) {
  370. public Dimension getMaximumSize() {
  371. return approveButton.getPreferredSize().width > cancelButton.getPreferredSize().width ?
  372. approveButton.getPreferredSize() : cancelButton.getPreferredSize();
  373. }
  374. };
  375. Insets buttonMargin = approveButton.getMargin();
  376. buttonMargin = new InsetsUIResource(buttonMargin.top, buttonMargin.left + 5,
  377. buttonMargin.bottom, buttonMargin.right + 5);
  378. approveButton.setMargin(buttonMargin);
  379. approveButton.setMnemonic(getApproveButtonMnemonic(fc));
  380. approveButton.addActionListener(getApproveSelectionAction());
  381. approveButton.setToolTipText(getApproveButtonToolTipText(fc));
  382. getButtonPanel().add(Box.createRigidArea(vstrut6));
  383. getButtonPanel().add(approveButton);
  384. getButtonPanel().add(Box.createRigidArea(vstrut4));
  385. cancelButton = new JButton(cancelButtonText) {
  386. public Dimension getMaximumSize() {
  387. return approveButton.getPreferredSize().width > cancelButton.getPreferredSize().width ?
  388. approveButton.getPreferredSize() : cancelButton.getPreferredSize();
  389. }
  390. };
  391. cancelButton.setMargin(buttonMargin);
  392. cancelButton.setMnemonic(cancelButtonMnemonic);
  393. cancelButton.setToolTipText(cancelButtonToolTipText);
  394. cancelButton.addActionListener(getCancelSelectionAction());
  395. getButtonPanel().add(cancelButton);
  396. if(fc.getControlButtonsAreShown()) {
  397. addControlButtons();
  398. }
  399. }
  400. private void updateUseShellFolder() {
  401. // Decide whether to use the ShellFolder class to populate shortcut
  402. // panel and combobox.
  403. JFileChooser fc = getFileChooser();
  404. Boolean prop =
  405. (Boolean)fc.getClientProperty("FileChooser.useShellFolder");
  406. if (prop != null) {
  407. useShellFolder = prop.booleanValue();
  408. } else {
  409. // See if FileSystemView.getRoots() returns the desktop folder,
  410. // i.e. the normal Windows hierarchy.
  411. useShellFolder = false;
  412. File[] roots = fc.getFileSystemView().getRoots();
  413. if (roots != null && roots.length == 1) {
  414. File[] cbFolders = (File[])ShellFolder.get("fileChooserComboBoxFolders");
  415. if (cbFolders != null && cbFolders.length > 0 && roots[0] == cbFolders[0]) {
  416. useShellFolder = true;
  417. }
  418. }
  419. }
  420. if (OS_LEVEL >= WIN_2k) {
  421. if (useShellFolder) {
  422. if (placesBar == null) {
  423. placesBar = new WindowsPlacesBar(fc, XPStyle.getXP() != null);
  424. fc.add(placesBar, BorderLayout.BEFORE_LINE_BEGINS);
  425. fc.addPropertyChangeListener(placesBar);
  426. }
  427. } else {
  428. if (placesBar != null) {
  429. fc.remove(placesBar);
  430. fc.removePropertyChangeListener(placesBar);
  431. placesBar = null;
  432. }
  433. }
  434. }
  435. }
  436. protected JPanel getButtonPanel() {
  437. if(buttonPanel == null) {
  438. buttonPanel = new JPanel();
  439. }
  440. return buttonPanel;
  441. }
  442. protected JPanel getBottomPanel() {
  443. if(bottomPanel == null) {
  444. bottomPanel = new JPanel();
  445. }
  446. return bottomPanel;
  447. }
  448. protected void installStrings(JFileChooser fc) {
  449. super.installStrings(fc);
  450. Locale l = fc.getLocale();
  451. lookInLabelMnemonic = UIManager.getInt("FileChooser.lookInLabelMnemonic");
  452. lookInLabelText = UIManager.getString("FileChooser.lookInLabelText",l);
  453. saveInLabelText = UIManager.getString("FileChooser.saveInLabelText",l);
  454. fileNameLabelMnemonic = UIManager.getInt("FileChooser.fileNameLabelMnemonic");
  455. fileNameLabelText = UIManager.getString("FileChooser.fileNameLabelText",l);
  456. filesOfTypeLabelMnemonic = UIManager.getInt("FileChooser.filesOfTypeLabelMnemonic");
  457. filesOfTypeLabelText = UIManager.getString("FileChooser.filesOfTypeLabelText",l);
  458. upFolderToolTipText = UIManager.getString("FileChooser.upFolderToolTipText",l);
  459. upFolderAccessibleName = UIManager.getString("FileChooser.upFolderAccessibleName",l);
  460. homeFolderToolTipText = UIManager.getString("FileChooser.homeFolderToolTipText",l);
  461. homeFolderAccessibleName = UIManager.getString("FileChooser.homeFolderAccessibleName",l);
  462. newFolderToolTipText = UIManager.getString("FileChooser.newFolderToolTipText",l);
  463. newFolderAccessibleName = UIManager.getString("FileChooser.newFolderAccessibleName",l);
  464. listViewButtonToolTipText = UIManager.getString("FileChooser.listViewButtonToolTipText",l);
  465. listViewButtonAccessibleName = UIManager.getString("FileChooser.listViewButtonAccessibleName",l);
  466. detailsViewButtonToolTipText = UIManager.getString("FileChooser.detailsViewButtonToolTipText",l);
  467. detailsViewButtonAccessibleName = UIManager.getString("FileChooser.detailsViewButtonAccessibleName",l);
  468. }
  469. protected void installListeners(JFileChooser fc) {
  470. super.installListeners(fc);
  471. ActionMap actionMap = getActionMap();
  472. SwingUtilities.replaceUIActionMap(fc, actionMap);
  473. }
  474. protected ActionMap getActionMap() {
  475. return createActionMap();
  476. }
  477. protected ActionMap createActionMap() {
  478. ActionMap map = new ActionMapUIResource();
  479. FilePane.addActionsToMap(map, filePane.getActions());
  480. return map;
  481. }
  482. protected JPanel createList(JFileChooser fc) {
  483. return filePane.createList();
  484. }
  485. protected JPanel createDetailsView(JFileChooser fc) {
  486. return filePane.createDetailsView();
  487. }
  488. /**
  489. * Creates a selection listener for the list of files and directories.
  490. *
  491. * @param fc a <code>JFileChooser</code>
  492. * @return a <code>ListSelectionListener</code>
  493. */
  494. public ListSelectionListener createListSelectionListener(JFileChooser fc) {
  495. return super.createListSelectionListener(fc);
  496. }
  497. // Obsolete class, not used in this version.
  498. protected class WindowsNewFolderAction extends NewFolderAction {
  499. }
  500. // Obsolete class, not used in this version.
  501. protected class SingleClickListener extends MouseAdapter {
  502. }
  503. // Obsolete class, not used in this version.
  504. protected class FileRenderer extends DefaultListCellRenderer {
  505. }
  506. public void uninstallUI(JComponent c) {
  507. // Remove listeners
  508. c.removePropertyChangeListener(filterComboBoxModel);
  509. c.removePropertyChangeListener(filePane);
  510. if (placesBar != null) {
  511. c.removePropertyChangeListener(placesBar);
  512. }
  513. cancelButton.removeActionListener(getCancelSelectionAction());
  514. approveButton.removeActionListener(getApproveSelectionAction());
  515. filenameTextField.removeActionListener(getApproveSelectionAction());
  516. super.uninstallUI(c);
  517. }
  518. /**
  519. * Returns the preferred size of the specified
  520. * <code>JFileChooser</code>.
  521. * The preferred size is at least as large,
  522. * in both height and width,
  523. * as the preferred size recommended
  524. * by the file chooser's layout manager.
  525. *
  526. * @param c a <code>JFileChooser</code>
  527. * @return a <code>Dimension</code> specifying the preferred
  528. * width and height of the file chooser
  529. */
  530. public Dimension getPreferredSize(JComponent c) {
  531. int prefWidth = PREF_SIZE.width;
  532. Dimension d = c.getLayout().preferredLayoutSize(c);
  533. if (d != null) {
  534. return new Dimension(d.width < prefWidth ? prefWidth : d.width,
  535. d.height < PREF_SIZE.height ? PREF_SIZE.height : d.height);
  536. } else {
  537. return new Dimension(prefWidth, PREF_SIZE.height);
  538. }
  539. }
  540. /**
  541. * Returns the minimum size of the <code>JFileChooser</code>.
  542. *
  543. * @param c a <code>JFileChooser</code>
  544. * @return a <code>Dimension</code> specifying the minimum
  545. * width and height of the file chooser
  546. */
  547. public Dimension getMinimumSize(JComponent c) {
  548. return MIN_SIZE;
  549. }
  550. /**
  551. * Returns the maximum size of the <code>JFileChooser</code>.
  552. *
  553. * @param c a <code>JFileChooser</code>
  554. * @return a <code>Dimension</code> specifying the maximum
  555. * width and height of the file chooser
  556. */
  557. public Dimension getMaximumSize(JComponent c) {
  558. return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
  559. }
  560. private String fileNameString(File file) {
  561. if (file == null) {
  562. return null;
  563. } else {
  564. JFileChooser fc = getFileChooser();
  565. if (fc.isDirectorySelectionEnabled() && !fc.isFileSelectionEnabled()) {
  566. return file.getPath();
  567. } else {
  568. return file.getName();
  569. }
  570. }
  571. }
  572. private String fileNameString(File[] files) {
  573. StringBuffer buf = new StringBuffer();
  574. for (int i = 0; files != null && i < files.length; i++) {
  575. if (i > 0) {
  576. buf.append(" ");
  577. }
  578. if (files.length > 1) {
  579. buf.append("\"");
  580. }
  581. buf.append(fileNameString(files[i]));
  582. if (files.length > 1) {
  583. buf.append("\"");
  584. }
  585. }
  586. return buf.toString();
  587. }
  588. /* The following methods are used by the PropertyChange Listener */
  589. private void doSelectedFileChanged(PropertyChangeEvent e) {
  590. File f = (File) e.getNewValue();
  591. JFileChooser fc = getFileChooser();
  592. if (f != null
  593. && ((fc.isFileSelectionEnabled() && !f.isDirectory())
  594. || (f.isDirectory() && fc.isDirectorySelectionEnabled()))) {
  595. setFileName(fileNameString(f));
  596. }
  597. }
  598. private void doSelectedFilesChanged(PropertyChangeEvent e) {
  599. File[] files = (File[]) e.getNewValue();
  600. JFileChooser fc = getFileChooser();
  601. if (files != null
  602. && files.length > 0
  603. && (files.length > 1 || fc.isDirectorySelectionEnabled() || !files[0].isDirectory())) {
  604. setFileName(fileNameString(files));
  605. }
  606. }
  607. private void doDirectoryChanged(PropertyChangeEvent e) {
  608. JFileChooser fc = getFileChooser();
  609. FileSystemView fsv = fc.getFileSystemView();
  610. clearIconCache();
  611. File currentDirectory = fc.getCurrentDirectory();
  612. if(currentDirectory != null) {
  613. directoryComboBoxModel.addItem(currentDirectory);
  614. if (fc.isDirectorySelectionEnabled() && !fc.isFileSelectionEnabled()) {
  615. if (fsv.isFileSystem(currentDirectory)) {
  616. setFileName(currentDirectory.getPath());
  617. } else {
  618. setFileName(null);
  619. }
  620. }
  621. }
  622. }
  623. private void doFilterChanged(PropertyChangeEvent e) {
  624. clearIconCache();
  625. }
  626. private void doFileSelectionModeChanged(PropertyChangeEvent e) {
  627. clearIconCache();
  628. JFileChooser fc = getFileChooser();
  629. File currentDirectory = fc.getCurrentDirectory();
  630. if (currentDirectory != null
  631. && fc.isDirectorySelectionEnabled()
  632. && !fc.isFileSelectionEnabled()
  633. && fc.getFileSystemView().isFileSystem(currentDirectory)) {
  634. setFileName(currentDirectory.getPath());
  635. } else {
  636. setFileName(null);
  637. }
  638. }
  639. private void doAccessoryChanged(PropertyChangeEvent e) {
  640. if(getAccessoryPanel() != null) {
  641. if(e.getOldValue() != null) {
  642. getAccessoryPanel().remove((JComponent) e.getOldValue());
  643. }
  644. JComponent accessory = (JComponent) e.getNewValue();
  645. if(accessory != null) {
  646. getAccessoryPanel().add(accessory, BorderLayout.CENTER);
  647. }
  648. }
  649. }
  650. private void doApproveButtonTextChanged(PropertyChangeEvent e) {
  651. JFileChooser chooser = getFileChooser();
  652. approveButton.setText(getApproveButtonText(chooser));
  653. approveButton.setToolTipText(getApproveButtonToolTipText(chooser));
  654. approveButton.setMnemonic(getApproveButtonMnemonic(chooser));
  655. }
  656. private void doDialogTypeChanged(PropertyChangeEvent e) {
  657. JFileChooser chooser = getFileChooser();
  658. approveButton.setText(getApproveButtonText(chooser));
  659. approveButton.setToolTipText(getApproveButtonToolTipText(chooser));
  660. approveButton.setMnemonic(getApproveButtonMnemonic(chooser));
  661. if (chooser.getDialogType() == JFileChooser.SAVE_DIALOG) {
  662. lookInLabel.setText(saveInLabelText);
  663. } else {
  664. lookInLabel.setText(lookInLabelText);
  665. }
  666. }
  667. private void doApproveButtonMnemonicChanged(PropertyChangeEvent e) {
  668. approveButton.setMnemonic(getApproveButtonMnemonic(getFileChooser()));
  669. }
  670. private void doControlButtonsChanged(PropertyChangeEvent e) {
  671. if(getFileChooser().getControlButtonsAreShown()) {
  672. addControlButtons();
  673. } else {
  674. removeControlButtons();
  675. }
  676. }
  677. /*
  678. * Listen for filechooser property changes, such as
  679. * the selected file changing, or the type of the dialog changing.
  680. */
  681. public PropertyChangeListener createPropertyChangeListener(JFileChooser fc) {
  682. return new PropertyChangeListener() {
  683. public void propertyChange(PropertyChangeEvent e) {
  684. String s = e.getPropertyName();
  685. if(s.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) {
  686. doSelectedFileChanged(e);
  687. } else if (s.equals(JFileChooser.SELECTED_FILES_CHANGED_PROPERTY)) {
  688. doSelectedFilesChanged(e);
  689. } else if(s.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)) {
  690. doDirectoryChanged(e);
  691. } else if(s.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)) {
  692. doFilterChanged(e);
  693. } else if(s.equals(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY)) {
  694. doFileSelectionModeChanged(e);
  695. } else if(s.equals(JFileChooser.ACCESSORY_CHANGED_PROPERTY)) {
  696. doAccessoryChanged(e);
  697. } else if (s.equals(JFileChooser.APPROVE_BUTTON_TEXT_CHANGED_PROPERTY) ||
  698. s.equals(JFileChooser.APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY)) {
  699. doApproveButtonTextChanged(e);
  700. } else if(s.equals(JFileChooser.DIALOG_TYPE_CHANGED_PROPERTY)) {
  701. doDialogTypeChanged(e);
  702. } else if(s.equals(JFileChooser.APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY)) {
  703. doApproveButtonMnemonicChanged(e);
  704. } else if(s.equals(JFileChooser.CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY)) {
  705. doControlButtonsChanged(e);
  706. } else if (s == "FileChooser.useShellFolder") {
  707. updateUseShellFolder();
  708. doDirectoryChanged(e);
  709. } else if (s.equals("componentOrientation")) {
  710. ComponentOrientation o = (ComponentOrientation)e.getNewValue();
  711. JFileChooser cc = (JFileChooser)e.getSource();
  712. if (o != (ComponentOrientation)e.getOldValue()) {
  713. cc.applyComponentOrientation(o);
  714. }
  715. } else if (s.equals("ancestor")) {
  716. if (e.getOldValue() == null && e.getNewValue() != null) {
  717. // Ancestor was added, set initial focus
  718. filenameTextField.selectAll();
  719. filenameTextField.requestFocus();
  720. }
  721. }
  722. }
  723. };
  724. }
  725. protected void removeControlButtons() {
  726. getBottomPanel().remove(getButtonPanel());
  727. }
  728. protected void addControlButtons() {
  729. getBottomPanel().add(getButtonPanel());
  730. }
  731. public void ensureFileIsVisible(JFileChooser fc, File f) {
  732. filePane.ensureFileIsVisible(fc, f);
  733. }
  734. public void rescanCurrentDirectory(JFileChooser fc) {
  735. filePane.rescanCurrentDirectory();
  736. }
  737. public String getFileName() {
  738. if(filenameTextField != null) {
  739. return filenameTextField.getText();
  740. } else {
  741. return null;
  742. }
  743. }
  744. public void setFileName(String filename) {
  745. if(filenameTextField != null) {
  746. filenameTextField.setText(filename);
  747. }
  748. }
  749. /**
  750. * Property to remember whether a directory is currently selected in the UI.
  751. * This is normally called by the UI on a selection event.
  752. *
  753. * @param directorySelected if a directory is currently selected.
  754. * @since 1.4
  755. */
  756. protected void setDirectorySelected(boolean directorySelected) {
  757. super.setDirectorySelected(directorySelected);
  758. JFileChooser chooser = getFileChooser();
  759. if(directorySelected) {
  760. approveButton.setText(directoryOpenButtonText);
  761. approveButton.setToolTipText(directoryOpenButtonToolTipText);
  762. approveButton.setMnemonic(directoryOpenButtonMnemonic);
  763. } else {
  764. approveButton.setText(getApproveButtonText(chooser));
  765. approveButton.setToolTipText(getApproveButtonToolTipText(chooser));
  766. approveButton.setMnemonic(getApproveButtonMnemonic(chooser));
  767. }
  768. }
  769. public String getDirectoryName() {
  770. // PENDING(jeff) - get the name from the directory combobox
  771. return null;
  772. }
  773. public void setDirectoryName(String dirname) {
  774. // PENDING(jeff) - set the name in the directory combobox
  775. }
  776. protected DirectoryComboBoxRenderer createDirectoryComboBoxRenderer(JFileChooser fc) {
  777. return new DirectoryComboBoxRenderer();
  778. }
  779. //
  780. // Renderer for DirectoryComboBox
  781. //
  782. class DirectoryComboBoxRenderer extends DefaultListCellRenderer {
  783. IndentIcon ii = new IndentIcon();
  784. public Component getListCellRendererComponent(JList list, Object value,
  785. int index, boolean isSelected,
  786. boolean cellHasFocus) {
  787. super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
  788. if (value == null) {
  789. setText("");
  790. return this;
  791. }
  792. File directory = (File)value;
  793. setText(getFileChooser().getName(directory));
  794. Icon icon = getFileChooser().getIcon(directory);
  795. ii.icon = icon;
  796. ii.depth = directoryComboBoxModel.getDepth(index);
  797. setIcon(ii);
  798. return this;
  799. }
  800. }
  801. final static int space = 10;
  802. class IndentIcon implements Icon {
  803. Icon icon = null;
  804. int depth = 0;
  805. public void paintIcon(Component c, Graphics g, int x, int y) {
  806. if (c.getComponentOrientation().isLeftToRight()) {
  807. icon.paintIcon(c, g, x+depth*space, y);
  808. } else {
  809. icon.paintIcon(c, g, x, y);
  810. }
  811. }
  812. public int getIconWidth() {
  813. return icon.getIconWidth() + depth*space;
  814. }
  815. public int getIconHeight() {
  816. return icon.getIconHeight();
  817. }
  818. }
  819. //
  820. // DataModel for DirectoryComboxbox
  821. //
  822. protected DirectoryComboBoxModel createDirectoryComboBoxModel(JFileChooser fc) {
  823. return new DirectoryComboBoxModel();
  824. }
  825. /**
  826. * Data model for a type-face selection combo-box.
  827. */
  828. protected class DirectoryComboBoxModel extends AbstractListModel implements ComboBoxModel {
  829. Vector directories = new Vector();
  830. int[] depths = null;
  831. File selectedDirectory = null;
  832. JFileChooser chooser = getFileChooser();
  833. FileSystemView fsv = chooser.getFileSystemView();
  834. public DirectoryComboBoxModel() {
  835. // Add the current directory to the model, and make it the
  836. // selectedDirectory
  837. File dir = getFileChooser().getCurrentDirectory();
  838. if(dir != null) {
  839. addItem(dir);
  840. }
  841. }
  842. /**
  843. * Adds the directory to the model and sets it to be selected,
  844. * additionally clears out the previous selected directory and
  845. * the paths leading up to it, if any.
  846. */
  847. private void addItem(File directory) {
  848. if(directory == null) {
  849. return;
  850. }
  851. directories.clear();
  852. File[] baseFolders;
  853. if (useShellFolder) {
  854. baseFolders = (File[])ShellFolder.get("fileChooserComboBoxFolders");
  855. } else {
  856. baseFolders = fsv.getRoots();
  857. }
  858. directories.addAll(Arrays.asList(baseFolders));
  859. // Get the canonical (full) path. This has the side
  860. // benefit of removing extraneous chars from the path,
  861. // for example /foo/bar/ becomes /foo/bar
  862. File canonical = null;
  863. try {
  864. canonical = directory.getCanonicalFile();
  865. } catch (IOException e) {
  866. // Maybe drive is not ready. Can't abort here.
  867. canonical = directory;
  868. }
  869. // create File instances of each directory leading up to the top
  870. try {
  871. File sf = useShellFolder ? ShellFolder.getShellFolder(canonical)
  872. : canonical;
  873. File f = sf;
  874. Vector path = new Vector(10);
  875. do {
  876. path.addElement(f);
  877. } while ((f = f.getParentFile()) != null);
  878. int pathCount = path.size();
  879. // Insert chain at appropriate place in vector
  880. for (int i = 0; i < pathCount; i++) {
  881. f = (File)path.get(i);
  882. if (directories.contains(f)) {
  883. int topIndex = directories.indexOf(f);
  884. for (int j = i-1; j >= 0; j--) {
  885. directories.insertElementAt(path.get(j), topIndex+i-j);
  886. }
  887. break;
  888. }
  889. }
  890. calculateDepths();
  891. setSelectedItem(sf);
  892. } catch (FileNotFoundException ex) {
  893. calculateDepths();
  894. }
  895. }
  896. private void calculateDepths() {
  897. depths = new int[directories.size()];
  898. for (int i = 0; i < depths.length; i++) {
  899. File dir = (File)directories.get(i);
  900. File parent = dir.getParentFile();
  901. depths[i] = 0;
  902. if (parent != null) {
  903. for (int j = i-1; j >= 0; j--) {
  904. if (parent.equals((File)directories.get(j))) {
  905. depths[i] = depths[j] + 1;
  906. break;
  907. }
  908. }
  909. }
  910. }
  911. }
  912. public int getDepth(int i) {
  913. return (depths != null && i >= 0 && i < depths.length) ? depths[i] : 0;
  914. }
  915. public void setSelectedItem(Object selectedDirectory) {
  916. this.selectedDirectory = (File)selectedDirectory;
  917. fireContentsChanged(this, -1, -1);
  918. }
  919. public Object getSelectedItem() {
  920. return selectedDirectory;
  921. }
  922. public int getSize() {
  923. return directories.size();
  924. }
  925. public Object getElementAt(int index) {
  926. return directories.elementAt(index);
  927. }
  928. }
  929. //
  930. // Renderer for Types ComboBox
  931. //
  932. protected FilterComboBoxRenderer createFilterComboBoxRenderer() {
  933. return new FilterComboBoxRenderer();
  934. }
  935. /**
  936. * Render different type sizes and styles.
  937. */
  938. public class FilterComboBoxRenderer extends DefaultListCellRenderer {
  939. public Component getListCellRendererComponent(JList list,
  940. Object value, int index, boolean isSelected,
  941. boolean cellHasFocus) {
  942. super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
  943. if (value != null && value instanceof FileFilter) {
  944. setText(((FileFilter)value).getDescription());
  945. }
  946. return this;
  947. }
  948. }
  949. //
  950. // DataModel for Types Comboxbox
  951. //
  952. protected FilterComboBoxModel createFilterComboBoxModel() {
  953. return new FilterComboBoxModel();
  954. }
  955. /**
  956. * Data model for a type-face selection combo-box.
  957. */
  958. protected class FilterComboBoxModel extends AbstractListModel implements ComboBoxModel, PropertyChangeListener {
  959. protected FileFilter[] filters;
  960. protected FilterComboBoxModel() {
  961. super();
  962. filters = getFileChooser().getChoosableFileFilters();
  963. }
  964. public void propertyChange(PropertyChangeEvent e) {
  965. String prop = e.getPropertyName();
  966. if(prop == JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY) {
  967. filters = (FileFilter[]) e.getNewValue();
  968. fireContentsChanged(this, -1, -1);
  969. } else if (prop == JFileChooser.FILE_FILTER_CHANGED_PROPERTY) {
  970. fireContentsChanged(this, -1, -1);
  971. }
  972. }
  973. public void setSelectedItem(Object filter) {
  974. if(filter != null) {
  975. getFileChooser().setFileFilter((FileFilter) filter);
  976. setFileName(null);
  977. fireContentsChanged(this, -1, -1);
  978. }
  979. }
  980. public Object getSelectedItem() {
  981. // Ensure that the current filter is in the list.
  982. // NOTE: we shouldnt' have to do this, since JFileChooser adds
  983. // the filter to the choosable filters list when the filter
  984. // is set. Lets be paranoid just in case someone overrides
  985. // setFileFilter in JFileChooser.
  986. FileFilter currentFilter = getFileChooser().getFileFilter();
  987. boolean found = false;
  988. if(currentFilter != null) {
  989. for(int i=0; i < filters.length; i++) {
  990. if(filters[i] == currentFilter) {
  991. found = true;
  992. }
  993. }
  994. if(found == false) {
  995. getFileChooser().addChoosableFileFilter(currentFilter);
  996. }
  997. }
  998. return getFileChooser().getFileFilter();
  999. }
  1000. public int getSize() {
  1001. if(filters != null) {
  1002. return filters.length;
  1003. } else {
  1004. return 0;
  1005. }
  1006. }
  1007. public Object getElementAt(int index) {
  1008. if(index > getSize() - 1) {
  1009. // This shouldn't happen. Try to recover gracefully.
  1010. return getFileChooser().getFileFilter();
  1011. }
  1012. if(filters != null) {
  1013. return filters[index];
  1014. } else {
  1015. return null;
  1016. }
  1017. }
  1018. }
  1019. public void valueChanged(ListSelectionEvent e) {
  1020. JFileChooser fc = getFileChooser();
  1021. File f = fc.getSelectedFile();
  1022. if (!e.getValueIsAdjusting() && f != null && !getFileChooser().isTraversable(f)) {
  1023. setFileName(fileNameString(f));
  1024. }
  1025. }
  1026. /**
  1027. * Acts when DirectoryComboBox has changed the selected item.
  1028. */
  1029. protected class DirectoryComboBoxAction implements ActionListener {
  1030. public void actionPerformed(ActionEvent e) {
  1031. File f = (File)directoryComboBox.getSelectedItem();
  1032. getFileChooser().setCurrentDirectory(f);
  1033. }
  1034. }
  1035. protected JButton getApproveButton(JFileChooser fc) {
  1036. return approveButton;
  1037. }
  1038. public FileView getFileView(JFileChooser fc) {
  1039. return fileView;
  1040. }
  1041. // ***********************
  1042. // * FileView operations *
  1043. // ***********************
  1044. protected class WindowsFileView extends BasicFileView {
  1045. /* FileView type descriptions */
  1046. public Icon getIcon(File f) {
  1047. Icon icon = getCachedIcon(f);
  1048. if (icon != null) {
  1049. return icon;
  1050. }
  1051. if (f != null) {
  1052. icon = getFileChooser().getFileSystemView().getSystemIcon(f);
  1053. }
  1054. if (icon == null) {
  1055. icon = super.getIcon(f);
  1056. }
  1057. cacheIcon(f, icon);
  1058. return icon;
  1059. }
  1060. }
  1061. }