1. /*
  2. * @(#)WindowsFileChooserUI.java 1.38 00/02/02
  3. *
  4. * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package com.sun.java.swing.plaf.windows;
  11. import javax.swing.*;
  12. import javax.swing.filechooser.*;
  13. import javax.swing.event.*;
  14. import javax.swing.plaf.*;
  15. import javax.swing.plaf.basic.*;
  16. import java.awt.*;
  17. import java.awt.event.*;
  18. import java.beans.*;
  19. import java.io.File;
  20. import java.io.IOException;
  21. import java.util.*;
  22. /**
  23. * Basic L&F implementation of a FileChooser.
  24. *
  25. * @version 1.38 02/02/00
  26. * @author Jeff Dinkins
  27. */
  28. public class WindowsFileChooserUI extends BasicFileChooserUI {
  29. // The following are private because the implementation of the
  30. // Windows FileChooser L&F is not complete yet.
  31. private JPanel centerPanel;
  32. private JComboBox directoryComboBox;
  33. private DirectoryComboBoxModel directoryComboBoxModel;
  34. private ActionListener directoryComboBoxAction = new DirectoryComboBoxAction();
  35. private FilterComboBoxModel filterComboBoxModel;
  36. private JTextField filenameTextField;
  37. private JList list;
  38. private JButton approveButton;
  39. private JButton cancelButton;
  40. private JButton upFolderButton;
  41. private JPanel buttonPanel;
  42. private JPanel bottomPanel;
  43. private JComboBox filterComboBox;
  44. private static final Dimension hstrut10 = new Dimension(10, 1);
  45. private static final Dimension hstrut25 = new Dimension(25, 1);
  46. private static final Dimension vstrut1 = new Dimension(1, 1);
  47. private static final Dimension vstrut10 = new Dimension(1, 10);
  48. private static final Dimension vstrut15 = new Dimension(1, 15);
  49. private static final Dimension vstrut20 = new Dimension(1, 20);
  50. private Component bottomBox = Box.createRigidArea(hstrut10);
  51. private static final Insets shrinkwrap = new Insets(0,0,0,0);
  52. // Preferred and Minimum sizes for the dialog box
  53. private static int PREF_WIDTH = 425;
  54. private static int PREF_HEIGHT = 245;
  55. private static Dimension PREF_SIZE = new Dimension(PREF_WIDTH, PREF_HEIGHT);
  56. private static int MIN_WIDTH = 400;
  57. private static int MIN_HEIGHT = 200;
  58. private static Dimension MIN_SIZE = new Dimension(MIN_WIDTH, MIN_HEIGHT);
  59. private static int LIST_MIN_WIDTH = 400;
  60. private static int LIST_MIN_HEIGHT = 100;
  61. private static Dimension LIST_MIN_SIZE = new Dimension(LIST_MIN_WIDTH, LIST_MIN_HEIGHT);
  62. // Labels, mnemonics, and tooltips (oh my!)
  63. private int lookInLabelMnemonic = 0;
  64. private String lookInLabelText = null;
  65. private int fileNameLabelMnemonic = 0;
  66. private String fileNameLabelText = null;
  67. private int filesOfTypeLabelMnemonic = 0;
  68. private String filesOfTypeLabelText = null;
  69. private String upFolderToolTipText = null;
  70. private String upFolderAccessibleName = null;
  71. private String homeFolderToolTipText = null;
  72. private String homeFolderAccessibleName = null;
  73. private String newFolderToolTipText = null;
  74. private String newFolderAccessibleName = null;
  75. private String listViewButtonToolTipText = null;
  76. private String listViewButtonAccessibleName = null;
  77. private String detailsViewButtonToolTipText = null;
  78. private String detailsViewButtonAccessibleName = null;
  79. //
  80. // ComponentUI Interface Implementation methods
  81. //
  82. public static ComponentUI createUI(JComponent c) {
  83. return new WindowsFileChooserUI((JFileChooser) c);
  84. }
  85. public WindowsFileChooserUI(JFileChooser filechooser) {
  86. super(filechooser);
  87. }
  88. public void installUI(JComponent c) {
  89. super.installUI(c);
  90. }
  91. public void uninstallComponents(JFileChooser fc) {
  92. fc.removeAll();
  93. }
  94. public void installComponents(JFileChooser fc) {
  95. // set to a Y BoxLayout. The chooser will be layed out top to bottom.
  96. fc.setLayout(new BoxLayout(fc, BoxLayout.Y_AXIS));
  97. fc.add(Box.createRigidArea(vstrut10));
  98. // ********************************* //
  99. // **** Construct the top panel **** //
  100. // ********************************* //
  101. // Directory manipulation buttons
  102. JPanel topPanel = new JPanel();
  103. topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.X_AXIS));
  104. // Add the top panel to the fileChooser
  105. fc.add(topPanel);
  106. fc.add(Box.createRigidArea(vstrut10));
  107. // ComboBox Label
  108. JLabel l = new JLabel(lookInLabelText);
  109. l.setDisplayedMnemonic(lookInLabelMnemonic);
  110. l.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  111. l.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  112. topPanel.add(Box.createRigidArea(new Dimension(14,0)));
  113. topPanel.add(l);
  114. topPanel.add(Box.createRigidArea(new Dimension(29,0)));
  115. // CurrentDir ComboBox
  116. directoryComboBox = new JComboBox();
  117. directoryComboBox.putClientProperty( "JComboBox.lightweightKeyboardNavigation", "Lightweight" );
  118. l.setLabelFor(directoryComboBox);
  119. directoryComboBoxModel = createDirectoryComboBoxModel(fc);
  120. directoryComboBox.setModel(directoryComboBoxModel);
  121. directoryComboBox.addActionListener(directoryComboBoxAction);
  122. directoryComboBox.setRenderer(createDirectoryComboBoxRenderer(fc));
  123. directoryComboBox.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  124. directoryComboBox.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  125. topPanel.add(directoryComboBox);
  126. topPanel.add(Box.createRigidArea(hstrut10));
  127. // Up Button
  128. upFolderButton = new JButton(upFolderIcon);
  129. upFolderButton.setToolTipText(upFolderToolTipText);
  130. upFolderButton.getAccessibleContext().setAccessibleName(upFolderAccessibleName);
  131. upFolderButton.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  132. upFolderButton.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  133. upFolderButton.setMargin(shrinkwrap);
  134. upFolderButton.setFocusPainted(false);
  135. upFolderButton.addActionListener(getChangeToParentDirectoryAction());
  136. topPanel.add(upFolderButton);
  137. topPanel.add(Box.createRigidArea(hstrut10));
  138. // Home Button
  139. JButton b = new JButton(homeFolderIcon);
  140. b.setToolTipText(homeFolderToolTipText);
  141. b.getAccessibleContext().setAccessibleName(homeFolderAccessibleName);
  142. b.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  143. b.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  144. b.setMargin(shrinkwrap);
  145. b.setFocusPainted(false);
  146. b.addActionListener(getGoHomeAction());
  147. topPanel.add(b);
  148. topPanel.add(Box.createRigidArea(hstrut10));
  149. // New Directory Button
  150. b = new JButton(newFolderIcon);
  151. b.setToolTipText(newFolderToolTipText);
  152. b.getAccessibleContext().setAccessibleName(newFolderAccessibleName);
  153. b.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  154. b.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  155. b.setMargin(shrinkwrap);
  156. b.setFocusPainted(false);
  157. b.addActionListener(getNewFolderAction());
  158. topPanel.add(b);
  159. topPanel.add(Box.createRigidArea(hstrut10));
  160. // List Button
  161. JToggleButton tb = new JToggleButton(listViewIcon);
  162. tb.setToolTipText(listViewButtonToolTipText);
  163. tb.getAccessibleContext().setAccessibleName(listViewButtonAccessibleName);
  164. tb.setEnabled(false);
  165. tb.setFocusPainted(false);
  166. tb.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  167. tb.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  168. tb.setMargin(shrinkwrap);
  169. topPanel.add(tb);
  170. // Details Button
  171. tb = new JToggleButton(detailsViewIcon);
  172. tb.setToolTipText(detailsViewButtonToolTipText);
  173. tb.getAccessibleContext().setAccessibleName(detailsViewButtonAccessibleName);
  174. tb.setFocusPainted(false);
  175. tb.setSelected(true);
  176. tb.setEnabled(false);
  177. tb.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  178. tb.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  179. tb.setMargin(shrinkwrap);
  180. topPanel.add(tb);
  181. topPanel.add(Box.createRigidArea(hstrut10));
  182. // ************************************** //
  183. // ******* Add the directory pane ******* //
  184. // ************************************** //
  185. centerPanel = new JPanel(new BorderLayout());
  186. JPanel p = createList(fc);
  187. p.setMinimumSize(LIST_MIN_SIZE);
  188. centerPanel.add(p, BorderLayout.CENTER);
  189. centerPanel.add(getAccessoryPanel(), BorderLayout.EAST);
  190. JComponent accessory = fc.getAccessory();
  191. if(accessory != null) {
  192. getAccessoryPanel().add(accessory);
  193. }
  194. fc.add(centerPanel);
  195. // ********************************** //
  196. // **** Construct the bottom panel ** //
  197. // ********************************** //
  198. getBottomPanel().setLayout(new BoxLayout(getBottomPanel(), BoxLayout.X_AXIS));
  199. getBottomPanel().add(Box.createRigidArea(hstrut10));
  200. // Add the bottom panel to file chooser
  201. fc.add(Box.createRigidArea(vstrut10));
  202. fc.add(getBottomPanel());
  203. fc.add(Box.createRigidArea(vstrut10));
  204. // labels
  205. JPanel labelPanel = new JPanel();
  206. labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.Y_AXIS));
  207. JLabel fnl = new JLabel(fileNameLabelText);
  208. fnl.setDisplayedMnemonic(fileNameLabelMnemonic);
  209. fnl.setAlignmentY(0);
  210. labelPanel.add(fnl);
  211. labelPanel.add(Box.createRigidArea(vstrut20));
  212. JLabel ftl = new JLabel(filesOfTypeLabelText);
  213. ftl.setDisplayedMnemonic(filesOfTypeLabelMnemonic);
  214. labelPanel.add(ftl);
  215. getBottomPanel().add(labelPanel);
  216. getBottomPanel().add(Box.createRigidArea(new Dimension(15, 0)));
  217. // file entry and filters
  218. JPanel fileAndFilterPanel = new JPanel();
  219. fileAndFilterPanel.setLayout(new BoxLayout(fileAndFilterPanel, BoxLayout.Y_AXIS));
  220. filenameTextField = new JTextField() {
  221. public Dimension getMaximumSize() {
  222. return new Dimension(Short.MAX_VALUE, super.getPreferredSize().height);
  223. }
  224. };
  225. fnl.setLabelFor(filenameTextField);
  226. filenameTextField.addActionListener(getApproveSelectionAction());
  227. filenameTextField.addFocusListener(
  228. new FocusAdapter() {
  229. public void focusGained(FocusEvent e) {
  230. list.clearSelection();
  231. }
  232. }
  233. );
  234. File f = fc.getSelectedFile();
  235. if(f != null) {
  236. setFileName(fc.getName(f));
  237. }
  238. fileAndFilterPanel.add(filenameTextField);
  239. fileAndFilterPanel.add(Box.createRigidArea(vstrut15));
  240. filterComboBoxModel = createFilterComboBoxModel();
  241. fc.addPropertyChangeListener(filterComboBoxModel);
  242. filterComboBox = new JComboBox(filterComboBoxModel);
  243. ftl.setLabelFor(filterComboBox);
  244. filterComboBox.setRenderer(createFilterComboBoxRenderer());
  245. fileAndFilterPanel.add(filterComboBox);
  246. getBottomPanel().add(fileAndFilterPanel);
  247. getBottomPanel().add(Box.createRigidArea(hstrut10));
  248. // buttons
  249. getButtonPanel().setLayout(new BoxLayout(getButtonPanel(), BoxLayout.Y_AXIS));
  250. approveButton = new JButton(getApproveButtonText(fc)) {
  251. public Dimension getMaximumSize() {
  252. return approveButton.getPreferredSize().width > cancelButton.getPreferredSize().width ?
  253. approveButton.getPreferredSize() : cancelButton.getPreferredSize();
  254. }
  255. };
  256. approveButton.setMnemonic(getApproveButtonMnemonic(fc));
  257. approveButton.addActionListener(getApproveSelectionAction());
  258. approveButton.setToolTipText(getApproveButtonToolTipText(fc));
  259. getButtonPanel().add(approveButton);
  260. getButtonPanel().add(Box.createRigidArea(vstrut10));
  261. cancelButton = new JButton(cancelButtonText) {
  262. public Dimension getMaximumSize() {
  263. return approveButton.getPreferredSize().width > cancelButton.getPreferredSize().width ?
  264. approveButton.getPreferredSize() : cancelButton.getPreferredSize();
  265. }
  266. };
  267. cancelButton.setMnemonic(cancelButtonMnemonic);
  268. cancelButton.setToolTipText(cancelButtonToolTipText);
  269. cancelButton.addActionListener(getCancelSelectionAction());
  270. getButtonPanel().add(cancelButton);
  271. if(fc.getControlButtonsAreShown()) {
  272. addControlButtons();
  273. }
  274. }
  275. protected JPanel getButtonPanel() {
  276. if(buttonPanel == null) {
  277. buttonPanel = new JPanel();
  278. }
  279. return buttonPanel;
  280. }
  281. protected JPanel getBottomPanel() {
  282. if(bottomPanel == null) {
  283. bottomPanel = new JPanel();
  284. }
  285. return bottomPanel;
  286. }
  287. protected void installStrings(JFileChooser fc) {
  288. super.installStrings(fc);
  289. lookInLabelMnemonic = UIManager.getInt("FileChooser.lookInLabelMnemonic");
  290. lookInLabelText = UIManager.getString("FileChooser.lookInLabelText");
  291. fileNameLabelMnemonic = UIManager.getInt("FileChooser.fileNameLabelMnemonic");
  292. fileNameLabelText = UIManager.getString("FileChooser.fileNameLabelText");
  293. filesOfTypeLabelMnemonic = UIManager.getInt("FileChooser.filesOfTypeLabelMnemonic");
  294. filesOfTypeLabelText = UIManager.getString("FileChooser.filesOfTypeLabelText");
  295. upFolderToolTipText = UIManager.getString("FileChooser.upFolderToolTipText");
  296. upFolderAccessibleName = UIManager.getString("FileChooser.upFolderAccessibleName");
  297. homeFolderToolTipText = UIManager.getString("FileChooser.homeFolderToolTipText");
  298. homeFolderAccessibleName = UIManager.getString("FileChooser.homeFolderAccessibleName");
  299. newFolderToolTipText = UIManager.getString("FileChooser.newFolderToolTipText");
  300. newFolderAccessibleName = UIManager.getString("FileChooser.newFolderAccessibleName");
  301. listViewButtonToolTipText = UIManager.getString("FileChooser.listViewButtonToolTipText");
  302. listViewButtonAccessibleName = UIManager.getString("FileChooser.listViewButtonAccessibleName");
  303. detailsViewButtonToolTipText = UIManager.getString("FileChooser.detailsViewButtonToolTipText");
  304. detailsViewButtonAccessibleName = UIManager.getString("FileChooser.detailsViewButtonAccessibleName");
  305. }
  306. protected void installListeners(JFileChooser fc) {
  307. super.installListeners(fc);
  308. ActionMap actionMap = getActionMap();
  309. SwingUtilities.replaceUIActionMap(fc, actionMap);
  310. }
  311. protected ActionMap getActionMap() {
  312. return createActionMap();
  313. }
  314. protected ActionMap createActionMap() {
  315. AbstractAction escAction = new AbstractAction() {
  316. public void actionPerformed(ActionEvent e) {
  317. if(editing) {
  318. cancelEdit();
  319. list.repaint();
  320. } else {
  321. getFileChooser().cancelSelection();
  322. }
  323. }
  324. public boolean isEnabled(){
  325. return getFileChooser().isEnabled();
  326. }
  327. };
  328. ActionMap map = new ActionMapUIResource();
  329. map.put("cancelSelection", escAction);
  330. return map;
  331. }
  332. protected JPanel createList(JFileChooser fc) {
  333. JPanel p = new JPanel(new BorderLayout());
  334. list = new JList();
  335. list.setCellRenderer(new FileRenderer());
  336. if(fc.isMultiSelectionEnabled()) {
  337. list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
  338. } else {
  339. list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
  340. }
  341. list.setModel(getModel());
  342. list.addListSelectionListener(createListSelectionListener(fc));
  343. list.addMouseListener(createDoubleClickListener(fc, list));
  344. list.addMouseListener(createSingleClickListener(fc, list));
  345. JScrollPane scrollpane = new JScrollPane(list);
  346. scrollpane.setBorder(BorderFactory.createLoweredBevelBorder());
  347. p.add(scrollpane, BorderLayout.CENTER);
  348. return p;
  349. }
  350. private MouseListener createSingleClickListener(JFileChooser fc, JList list) {
  351. return new SingleClickListener(list);
  352. }
  353. int lastIndex = -1;
  354. boolean editing = false;
  355. int editX = 20;
  356. int editWidth = 200;
  357. private void setEditIndex(int i) {
  358. lastIndex = i;
  359. }
  360. private void resetEditIndex() {
  361. lastIndex = -1;
  362. }
  363. private void cancelEdit() {
  364. editing = false;
  365. if(editCell != null) {
  366. list.remove(editCell);
  367. }
  368. }
  369. JTextField editCell = null;
  370. protected class SingleClickListener extends MouseAdapter {
  371. JList list;
  372. public SingleClickListener(JList list) {
  373. this.list = list;
  374. editCell = new JTextField();
  375. editCell.addActionListener(new EditActionListener());
  376. }
  377. public void mouseClicked(MouseEvent e) {
  378. if (e.getClickCount() == 1) {
  379. int index = list.locationToIndex(e.getPoint());
  380. if(index >= 0 && lastIndex == index && editing == false) {
  381. editing = true;
  382. Rectangle r = list.getCellBounds(index, index);
  383. list.add(editCell);
  384. File f = (File) list.getSelectedValue();
  385. editCell.setText(getFileChooser().getName(f));
  386. editCell.setBounds(editX + r.x, r.y, editWidth, r.height);
  387. editCell.selectAll();
  388. } else {
  389. if(index >= 0) {
  390. setEditIndex(index);
  391. } else {
  392. resetEditIndex();
  393. }
  394. cancelEdit();
  395. }
  396. } else {
  397. // on double click (open or drill down one directory) be
  398. // sure to clear the edit index
  399. resetEditIndex();
  400. cancelEdit();
  401. }
  402. list.repaint();
  403. }
  404. }
  405. class EditActionListener implements ActionListener {
  406. public void actionPerformed(ActionEvent e) {
  407. JTextField tf = (JTextField) e.getSource();
  408. File f = (File) list.getSelectedValue();
  409. String newFileName = tf.getText();
  410. newFileName = newFileName.trim();
  411. if(!newFileName.equals(getFileChooser().getName(f))) {
  412. // rename
  413. File f2 = getFileChooser().getFileSystemView().createFileObject(
  414. getFileChooser().getCurrentDirectory(), newFileName
  415. );
  416. if(f.renameTo(f2)) {
  417. rescanCurrentDirectory(getFileChooser());
  418. } else {
  419. // PENDING(jeff) - show a dialog indicating failure
  420. }
  421. }
  422. cancelEdit();
  423. list.repaint();
  424. }
  425. }
  426. protected class FileRenderer extends DefaultListCellRenderer {
  427. public Component getListCellRendererComponent(JList list, Object value,
  428. int index, boolean isSelected,
  429. boolean cellHasFocus) {
  430. super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
  431. File file = (File) value;
  432. String fileName = getFileChooser().getName(file);
  433. setText(fileName);
  434. Icon icon = getFileChooser().getIcon(file);
  435. setIcon(icon);
  436. if(isSelected) {
  437. // PENDING(jeff) - grab padding (4) below from defaults table.
  438. editX = icon.getIconWidth() + 4;
  439. }
  440. return this;
  441. }
  442. }
  443. public void uninstallUI(JComponent c) {
  444. // Remove listeners
  445. c.removePropertyChangeListener(filterComboBoxModel);
  446. cancelButton.removeActionListener(getCancelSelectionAction());
  447. approveButton.removeActionListener(getApproveSelectionAction());
  448. filenameTextField.removeActionListener(getApproveSelectionAction());
  449. super.uninstallUI(c);
  450. }
  451. public Dimension getPreferredSize(JComponent c) {
  452. return PREF_SIZE;
  453. }
  454. public Dimension getMinimumSize(JComponent c) {
  455. return MIN_SIZE;
  456. }
  457. public Dimension getMaximumSize(JComponent c) {
  458. return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
  459. }
  460. void setFileSelected() {
  461. File f = getFileChooser().getSelectedFile();
  462. if(f != null && getModel().contains(f)) {
  463. list.setSelectedIndex(getModel().indexOf(f));
  464. list.ensureIndexIsVisible(list.getSelectedIndex());
  465. } else {
  466. list.clearSelection();
  467. }
  468. }
  469. /* The following are used by the PropertyChange Listener */
  470. private void doSelectedFileChanged(PropertyChangeEvent e) {
  471. cancelEdit();
  472. File f = (File) e.getNewValue();
  473. if(f != null) {
  474. setFileName(getFileChooser().getName(f));
  475. } else {
  476. setFileName(null);
  477. }
  478. setFileSelected();
  479. }
  480. private void doDirectoryChanged(PropertyChangeEvent e) {
  481. cancelEdit();
  482. resetEditIndex();
  483. clearIconCache();
  484. list.clearSelection();
  485. File currentDirectory = getFileChooser().getCurrentDirectory();
  486. if(currentDirectory != null) {
  487. directoryComboBoxModel.addItem(currentDirectory);
  488. // Enable the newFolder action if the current directory
  489. // is writable.
  490. // PENDING(jeff) - broken - fix
  491. getNewFolderAction().setEnabled(currentDirectory.canWrite());
  492. if(currentDirectory.getParent() == null) {
  493. upFolderButton.setEnabled(false);
  494. } else {
  495. upFolderButton.setEnabled(true);
  496. }
  497. }
  498. }
  499. private void doFilterChanged(PropertyChangeEvent e) {
  500. cancelEdit();
  501. resetEditIndex();
  502. clearIconCache();
  503. list.clearSelection();
  504. }
  505. private void doFileSelectionModeChanged(PropertyChangeEvent e) {
  506. cancelEdit();
  507. resetEditIndex();
  508. clearIconCache();
  509. list.clearSelection();
  510. }
  511. private void doMultiSelectionChanged(PropertyChangeEvent e) {
  512. if(getFileChooser().isMultiSelectionEnabled()) {
  513. list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
  514. } else {
  515. list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
  516. list.clearSelection();
  517. getFileChooser().setSelectedFiles(null);
  518. }
  519. }
  520. private void doAccessoryChanged(PropertyChangeEvent e) {
  521. if(getAccessoryPanel() != null) {
  522. if(e.getOldValue() != null) {
  523. getAccessoryPanel().remove((JComponent) e.getOldValue());
  524. }
  525. JComponent accessory = (JComponent) e.getNewValue();
  526. if(accessory != null) {
  527. getAccessoryPanel().add(accessory, BorderLayout.CENTER);
  528. }
  529. }
  530. }
  531. private void doApproveButtonTextChanged(PropertyChangeEvent e) {
  532. JFileChooser chooser = getFileChooser();
  533. approveButton.setText(getApproveButtonText(chooser));
  534. approveButton.setToolTipText(getApproveButtonToolTipText(chooser));
  535. approveButton.setMnemonic(getApproveButtonMnemonic(chooser));
  536. }
  537. private void doDialogTypeChanged(PropertyChangeEvent e) {
  538. JFileChooser chooser = getFileChooser();
  539. approveButton.setText(getApproveButtonText(chooser));
  540. approveButton.setToolTipText(getApproveButtonToolTipText(chooser));
  541. approveButton.setMnemonic(getApproveButtonMnemonic(chooser));
  542. }
  543. private void doApproveButtonMnemonicChanged(PropertyChangeEvent e) {
  544. approveButton.setMnemonic(getApproveButtonMnemonic(getFileChooser()));
  545. }
  546. private void doControlButtonsChanged(PropertyChangeEvent e) {
  547. if(getFileChooser().getControlButtonsAreShown()) {
  548. addControlButtons();
  549. } else {
  550. removeControlButtons();
  551. }
  552. }
  553. /*
  554. * Listen for filechooser property changes, such as
  555. * the selected file changing, or the type of the dialog changing.
  556. */
  557. public PropertyChangeListener createPropertyChangeListener(JFileChooser fc) {
  558. return new PropertyChangeListener() {
  559. public void propertyChange(PropertyChangeEvent e) {
  560. String s = e.getPropertyName();
  561. if(s.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) {
  562. doSelectedFileChanged(e);
  563. } else if(s.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)) {
  564. doDirectoryChanged(e);
  565. } else if(s.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)) {
  566. doFilterChanged(e);
  567. } else if(s.equals(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY)) {
  568. doFileSelectionModeChanged(e);
  569. } else if(s.equals(JFileChooser.MULTI_SELECTION_ENABLED_CHANGED_PROPERTY)) {
  570. doMultiSelectionChanged(e);
  571. } else if(s.equals(JFileChooser.ACCESSORY_CHANGED_PROPERTY)) {
  572. doAccessoryChanged(e);
  573. } else if(s.equals(JFileChooser.APPROVE_BUTTON_TEXT_CHANGED_PROPERTY)) {
  574. doApproveButtonTextChanged(e);
  575. } else if(s.equals(JFileChooser.DIALOG_TYPE_CHANGED_PROPERTY)) {
  576. doDialogTypeChanged(e);
  577. } else if(s.equals(JFileChooser.APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY)) {
  578. doApproveButtonMnemonicChanged(e);
  579. } else if(s.equals(JFileChooser.CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY)) {
  580. doControlButtonsChanged(e);
  581. }
  582. }
  583. };
  584. }
  585. protected void removeControlButtons() {
  586. getBottomPanel().remove(getButtonPanel());
  587. getBottomPanel().remove(bottomBox);
  588. }
  589. protected void addControlButtons() {
  590. getBottomPanel().add(getButtonPanel());
  591. getBottomPanel().add(bottomBox);
  592. }
  593. public void ensureFileIsVisible(JFileChooser fc, File f) {
  594. if(getModel().contains(f)) {
  595. list.ensureIndexIsVisible(getModel().indexOf(f));
  596. }
  597. }
  598. public void rescanCurrentDirectory(JFileChooser fc) {
  599. getModel().invalidateFileCache();
  600. getModel().validateFileCache();
  601. }
  602. public String getFileName() {
  603. if(filenameTextField != null) {
  604. return filenameTextField.getText();
  605. } else {
  606. return null;
  607. }
  608. }
  609. public void setFileName(String filename) {
  610. if(filenameTextField != null) {
  611. filenameTextField.setText(filename);
  612. }
  613. }
  614. public String getDirectoryName() {
  615. // PENDING(jeff) - get the name from the directory combobox
  616. return null;
  617. }
  618. public void setDirectoryName(String dirname) {
  619. // PENDING(jeff) - set the name in the directory combobox
  620. }
  621. protected DirectoryComboBoxRenderer createDirectoryComboBoxRenderer(JFileChooser fc) {
  622. return new DirectoryComboBoxRenderer();
  623. }
  624. //
  625. // Renderer for DirectoryComboBox
  626. //
  627. class DirectoryComboBoxRenderer extends DefaultListCellRenderer {
  628. IndentIcon ii = new IndentIcon();
  629. public Component getListCellRendererComponent(JList list, Object value,
  630. int index, boolean isSelected,
  631. boolean cellHasFocus) {
  632. super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
  633. File directory = (File) value;
  634. if(directory == null) {
  635. setText("");
  636. return this;
  637. }
  638. setText(getFileChooser().getName(directory));
  639. // Find the depth of the directory
  640. int depth = 0;
  641. if(index != -1) {
  642. File f = directory;
  643. while(f.getParent() != null) {
  644. depth++;
  645. f = getFileChooser().getFileSystemView().createFileObject(
  646. f.getParent()
  647. );
  648. }
  649. }
  650. Icon icon = getFileChooser().getIcon(directory);
  651. ii.icon = icon;
  652. ii.depth = depth;
  653. setIcon(ii);
  654. return this;
  655. }
  656. }
  657. final static int space = 10;
  658. class IndentIcon implements Icon {
  659. Icon icon = null;
  660. int depth = 0;
  661. public void paintIcon(Component c, Graphics g, int x, int y) {
  662. icon.paintIcon(c, g, x+depth*space, y);
  663. }
  664. public int getIconWidth() {
  665. return icon.getIconWidth() + depth*space;
  666. }
  667. public int getIconHeight() {
  668. return icon.getIconHeight();
  669. }
  670. }
  671. //
  672. // DataModel for DirectoryComboxbox
  673. //
  674. protected DirectoryComboBoxModel createDirectoryComboBoxModel(JFileChooser fc) {
  675. return new DirectoryComboBoxModel();
  676. }
  677. /**
  678. * Data model for a type-face selection combo-box.
  679. */
  680. protected class DirectoryComboBoxModel extends AbstractListModel implements ComboBoxModel {
  681. Vector directories = new Vector();
  682. int topIndex = -1;
  683. int pathCount = 0;
  684. File selectedDirectory = null;
  685. public DirectoryComboBoxModel() {
  686. super();
  687. // Add root files to the model
  688. File[] roots = getFileChooser().getFileSystemView().getRoots();
  689. for(int i = 0; i < roots.length; i++) {
  690. directories.addElement(roots[i]);
  691. }
  692. // Add the current directory to the model, and make it the
  693. // selectedDirectory
  694. File dir = getFileChooser().getCurrentDirectory();
  695. if(dir != null) {
  696. addItem(dir);
  697. }
  698. }
  699. /**
  700. * Removes the selected directory, and clears out the
  701. * path file entries leading up to that directory.
  702. */
  703. private void removeSelectedDirectory() {
  704. if(topIndex >= 0 ) {
  705. for(int i = topIndex; i < topIndex + pathCount; i++) {
  706. directories.removeElementAt(topIndex+1);
  707. }
  708. }
  709. topIndex = -1;
  710. pathCount = 0;
  711. selectedDirectory = null;
  712. }
  713. /**
  714. * Adds the directory to the model and sets it to be selected,
  715. * additionally clears out the previous selected directory and
  716. * the paths leading up to it, if any.
  717. */
  718. private void addItem(File directory) {
  719. if(directory == null) {
  720. return;
  721. }
  722. if(selectedDirectory != null) {
  723. removeSelectedDirectory();
  724. }
  725. // Get the canonical (full) path. This has the side
  726. // benefit of removing extraneous chars from the path,
  727. // for example /foo/bar/ becomes /foo/bar
  728. File canonical = null;
  729. try {
  730. canonical = getFileChooser().getFileSystemView().createFileObject(
  731. directory.getCanonicalPath()
  732. );
  733. } catch (IOException e) {
  734. return;
  735. }
  736. // create File instances of each directory leading up to the top
  737. File f = canonical;
  738. Vector path = new Vector(10);
  739. while(f.getParent() != null) {
  740. path.addElement(f);
  741. // Find the index of the top leveo of the passed
  742. // in directory
  743. if(directories.contains(f)) {
  744. topIndex = directories.indexOf(f);
  745. }
  746. f = getFileChooser().getFileSystemView().createFileObject(f.getParent());
  747. }
  748. pathCount = path.size();
  749. // if we didn't find the top index above, check
  750. // the remaining parent
  751. // PENDING(jeff) - if this fails, we need might
  752. // need to scan all the other roots?
  753. if(topIndex < 0) {
  754. if(directories.contains(f)) {
  755. topIndex = directories.indexOf(f);
  756. } else {
  757. directories.addElement(f);
  758. }
  759. }
  760. // insert all the path directories leading up to the
  761. // selected directory.
  762. for(int i = 0; i < path.size(); i++) {
  763. directories.insertElementAt(path.elementAt(i), topIndex+1);
  764. }
  765. setSelectedItem(canonical);
  766. }
  767. public void setSelectedItem(Object selectedDirectory) {
  768. this.selectedDirectory = (File) selectedDirectory;
  769. fireContentsChanged(this, -1, -1);
  770. }
  771. public Object getSelectedItem() {
  772. return selectedDirectory;
  773. }
  774. public int getSize() {
  775. return directories.size();
  776. }
  777. public Object getElementAt(int index) {
  778. return directories.elementAt(index);
  779. }
  780. }
  781. //
  782. // Renderer for Types ComboBox
  783. //
  784. protected FilterComboBoxRenderer createFilterComboBoxRenderer() {
  785. return new FilterComboBoxRenderer();
  786. }
  787. /**
  788. * Render different type sizes and styles.
  789. */
  790. public class FilterComboBoxRenderer extends DefaultListCellRenderer {
  791. public Component getListCellRendererComponent(JList list,
  792. Object value, int index, boolean isSelected,
  793. boolean cellHasFocus) {
  794. super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
  795. FileFilter filter = (FileFilter) value;
  796. if(filter != null) {
  797. setText(filter.getDescription());
  798. }
  799. return this;
  800. }
  801. }
  802. //
  803. // DataModel for Types Comboxbox
  804. //
  805. protected FilterComboBoxModel createFilterComboBoxModel() {
  806. return new FilterComboBoxModel();
  807. }
  808. /**
  809. * Data model for a type-face selection combo-box.
  810. */
  811. protected class FilterComboBoxModel extends AbstractListModel implements ComboBoxModel, PropertyChangeListener {
  812. protected FileFilter[] filters;
  813. protected FilterComboBoxModel() {
  814. super();
  815. filters = getFileChooser().getChoosableFileFilters();
  816. }
  817. public void propertyChange(PropertyChangeEvent e) {
  818. String prop = e.getPropertyName();
  819. if(prop == JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY) {
  820. filters = (FileFilter[]) e.getNewValue();
  821. fireContentsChanged(this, -1, -1);
  822. }
  823. }
  824. public void setSelectedItem(Object filter) {
  825. if(filter != null) {
  826. getFileChooser().setFileFilter((FileFilter) filter);
  827. fireContentsChanged(this, -1, -1);
  828. }
  829. }
  830. public Object getSelectedItem() {
  831. // Ensure that the current filter is in the list.
  832. // NOTE: we shouldnt' have to do this, since JFileChooser adds
  833. // the filter to the choosable filters list when the filter
  834. // is set. Lets be paranoid just in case someone overrides
  835. // setFileFilter in JFileChooser.
  836. FileFilter currentFilter = getFileChooser().getFileFilter();
  837. boolean found = false;
  838. if(currentFilter != null) {
  839. for(int i=0; i < filters.length; i++) {
  840. if(filters[i] == currentFilter) {
  841. found = true;
  842. }
  843. }
  844. if(found == false) {
  845. getFileChooser().addChoosableFileFilter(currentFilter);
  846. }
  847. }
  848. return getFileChooser().getFileFilter();
  849. }
  850. public int getSize() {
  851. if(filters != null) {
  852. return filters.length;
  853. } else {
  854. return 0;
  855. }
  856. }
  857. public Object getElementAt(int index) {
  858. if(index > getSize() - 1) {
  859. // This shouldn't happen. Try to recover gracefully.
  860. return getFileChooser().getFileFilter();
  861. }
  862. if(filters != null) {
  863. return filters[index];
  864. } else {
  865. return null;
  866. }
  867. }
  868. }
  869. public void valueChanged(ListSelectionEvent e) {
  870. File f = getFileChooser().getSelectedFile();
  871. if (!e.getValueIsAdjusting() && f != null && !getFileChooser().isTraversable(f)) {
  872. setFileName(getFileChooser().getName(f));
  873. }
  874. }
  875. /**
  876. * Acts when DirectoryComboBox has changed the selected item.
  877. */
  878. protected class DirectoryComboBoxAction implements ActionListener {
  879. public void actionPerformed(ActionEvent e) {
  880. getFileChooser().setCurrentDirectory((File) directoryComboBox.getSelectedItem());
  881. }
  882. }
  883. protected JButton getApproveButton(JFileChooser fc) {
  884. return approveButton;
  885. }
  886. }