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