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