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