1. /*
  2. * @(#)WindowsFileChooserUI.java 1.80 04/01/13
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.java.swing.plaf.windows;
  8. import javax.swing.*;
  9. import javax.swing.border.*;
  10. import javax.swing.filechooser.*;
  11. import javax.swing.event.*;
  12. import javax.swing.plaf.*;
  13. import javax.swing.plaf.basic.*;
  14. import javax.swing.table.*;
  15. import javax.swing.text.Position;
  16. import java.awt.*;
  17. import java.awt.event.*;
  18. import java.beans.*;
  19. import java.io.File;
  20. import java.io.FileNotFoundException;
  21. import java.io.IOException;
  22. import java.text.DateFormat;
  23. import java.util.*;
  24. import sun.awt.shell.ShellFolder;
  25. /**
  26. * Windows L&F implementation of a FileChooser.
  27. *
  28. * @version 1.80 01/13/04
  29. * @author Jeff Dinkins
  30. */
  31. public class WindowsFileChooserUI extends BasicFileChooserUI {
  32. // The following are private because the implementation of the
  33. // Windows FileChooser L&F is not complete yet.
  34. private static final String[] OS_NAMES =
  35. new String[] { "Windows 3.1", "Windows 95", "Windows NT",
  36. "Windows 98", "Windows 2000", "Windows Me", "Windows XP" };
  37. private static int WIN_31 = 0;
  38. private static int WIN_95 = 1;
  39. private static int WIN_NT = 2;
  40. private static int WIN_98 = 3;
  41. private static int WIN_2k = 4;
  42. private static int WIN_Me = 5;
  43. private static int WIN_XP = 6;
  44. private static String osName = System.getProperty("os.name");
  45. private static String osVersion = System.getProperty("os.version");
  46. private static final String OS_NAME = ((osName.equals(OS_NAMES[WIN_98]) && osVersion.startsWith("4.9"))
  47. ? "Windows Me" : osName);
  48. private static final int OS_LEVEL = Arrays.asList(OS_NAMES).indexOf(OS_NAME);
  49. private JPanel centerPanel;
  50. private JLabel lookInLabel;
  51. private JComboBox directoryComboBox;
  52. private DirectoryComboBoxModel directoryComboBoxModel;
  53. private ActionListener directoryComboBoxAction = new DirectoryComboBoxAction();
  54. private FilterComboBoxModel filterComboBoxModel;
  55. private JTextField filenameTextField;
  56. private ShortCutPanel shortCutPanel;
  57. private JToggleButton listViewButton;
  58. private JToggleButton detailsViewButton;
  59. private JPanel listViewPanel;
  60. private JPanel detailsViewPanel;
  61. private JPanel currentViewPanel;
  62. private FocusListener editorFocusListener = new FocusAdapter() {
  63. public void focusLost(FocusEvent e) {
  64. if (! e.isTemporary()) {
  65. applyEdit();
  66. }
  67. }
  68. };
  69. private boolean smallIconsView = false;
  70. private Border listViewBorder;
  71. private boolean useShellFolder;
  72. private ListSelectionModel listSelectionModel;
  73. private JList list;
  74. private JTable detailsTable;
  75. private JButton approveButton;
  76. private JButton cancelButton;
  77. private JPanel buttonPanel;
  78. private JPanel bottomPanel;
  79. private JComboBox filterComboBox;
  80. private static final Dimension hstrut10 = new Dimension(10, 1);
  81. private static final Dimension hstrut25 = new Dimension(25, 1);
  82. private static final Dimension vstrut1 = new Dimension(1, 1);
  83. private static final Dimension vstrut4 = new Dimension(1, 4);
  84. private static final Dimension vstrut5 = new Dimension(1, 5);
  85. private static final Dimension vstrut6 = new Dimension(1, 6);
  86. private static final Dimension vstrut8 = new Dimension(1, 8);
  87. private static final Insets shrinkwrap = new Insets(0,0,0,0);
  88. // Preferred and Minimum sizes for the dialog box
  89. private static int PREF_WIDTH = 425;
  90. private static int PREF_HEIGHT = 245;
  91. private static Dimension PREF_SIZE = new Dimension(PREF_WIDTH, PREF_HEIGHT);
  92. private static int MIN_WIDTH = 425;
  93. private static int MIN_HEIGHT = 245;
  94. private static Dimension MIN_SIZE = new Dimension(MIN_WIDTH, MIN_HEIGHT);
  95. private static int LIST_PREF_WIDTH = 444;
  96. private static int LIST_PREF_HEIGHT = 138;
  97. private static Dimension LIST_PREF_SIZE = new Dimension(LIST_PREF_WIDTH, LIST_PREF_HEIGHT);
  98. private static final int COLUMN_FILENAME = 0;
  99. private static final int COLUMN_FILESIZE = 1;
  100. private static final int COLUMN_FILETYPE = 2;
  101. private static final int COLUMN_FILEDATE = 3;
  102. private static final int COLUMN_FILEATTR = 4;
  103. private static final int COLUMN_COLCOUNT = 5;
  104. private int[] COLUMN_WIDTHS = { 150, 75, 130, 130, 40 };
  105. // Labels, mnemonics, and tooltips (oh my!)
  106. private int lookInLabelMnemonic = 0;
  107. private String lookInLabelText = null;
  108. private String saveInLabelText = null;
  109. private int fileNameLabelMnemonic = 0;
  110. private String fileNameLabelText = null;
  111. private int filesOfTypeLabelMnemonic = 0;
  112. private String filesOfTypeLabelText = null;
  113. private String upFolderToolTipText = null;
  114. private String upFolderAccessibleName = null;
  115. private String homeFolderToolTipText = null;
  116. private String homeFolderAccessibleName = null;
  117. private String newFolderToolTipText = null;
  118. private String newFolderAccessibleName = null;
  119. private String listViewButtonToolTipText = null;
  120. private String listViewButtonAccessibleName = null;
  121. private String detailsViewButtonToolTipText = null;
  122. private String detailsViewButtonAccessibleName = null;
  123. private String fileNameHeaderText = null;
  124. private String fileSizeHeaderText = null;
  125. private String fileTypeHeaderText = null;
  126. private String fileDateHeaderText = null;
  127. private String fileAttrHeaderText = null;
  128. private Action newFolderAction = new WindowsNewFolderAction();
  129. private File newFolderFile;
  130. private BasicFileView fileView = new WindowsFileView();
  131. //
  132. // ComponentUI Interface Implementation methods
  133. //
  134. public static ComponentUI createUI(JComponent c) {
  135. return new WindowsFileChooserUI((JFileChooser) c);
  136. }
  137. public WindowsFileChooserUI(JFileChooser filechooser) {
  138. super(filechooser);
  139. }
  140. public void installUI(JComponent c) {
  141. super.installUI(c);
  142. }
  143. public void uninstallComponents(JFileChooser fc) {
  144. fc.removeAll();
  145. }
  146. public void installComponents(JFileChooser fc) {
  147. FileSystemView fsv = fc.getFileSystemView();
  148. XPStyle xp = XPStyle.getXP();
  149. if (xp != null) {
  150. listViewBorder = xp.getBorder("listview");
  151. } else {
  152. listViewBorder = new BevelBorder(BevelBorder.LOWERED,
  153. UIManager.getColor("ToolBar.highlight"),
  154. UIManager.getColor("ToolBar.background"),
  155. UIManager.getColor("ToolBar.darkShadow"),
  156. UIManager.getColor("ToolBar.shadow"));
  157. }
  158. fc.setBorder(new EmptyBorder(4, 10, 10, 10));
  159. fc.setLayout(new BorderLayout(8, 8));
  160. // ********************************* //
  161. // **** Construct the top panel **** //
  162. // ********************************* //
  163. // Directory manipulation buttons
  164. JToolBar topPanel = new JToolBar();
  165. topPanel.setFloatable(false);
  166. if (OS_LEVEL >= WIN_2k) {
  167. topPanel.putClientProperty("JToolBar.isRollover", Boolean.TRUE);
  168. }
  169. // Add the top panel to the fileChooser
  170. fc.add(topPanel, BorderLayout.NORTH);
  171. // ComboBox Label
  172. lookInLabel = new JLabel(lookInLabelText);
  173. lookInLabel.setDisplayedMnemonic(lookInLabelMnemonic);
  174. lookInLabel.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  175. lookInLabel.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  176. topPanel.add(Box.createRigidArea(new Dimension(14,0)));
  177. topPanel.add(lookInLabel);
  178. topPanel.add(Box.createRigidArea(new Dimension(29,0)));
  179. // CurrentDir ComboBox
  180. directoryComboBox = new JComboBox();
  181. directoryComboBox.putClientProperty( "JComboBox.lightweightKeyboardNavigation", "Lightweight" );
  182. lookInLabel.setLabelFor(directoryComboBox);
  183. directoryComboBoxModel = createDirectoryComboBoxModel(fc);
  184. directoryComboBox.setModel(directoryComboBoxModel);
  185. directoryComboBox.addActionListener(directoryComboBoxAction);
  186. directoryComboBox.setRenderer(createDirectoryComboBoxRenderer(fc));
  187. directoryComboBox.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  188. directoryComboBox.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  189. directoryComboBox.setMaximumRowCount(8);
  190. topPanel.add(directoryComboBox);
  191. topPanel.add(Box.createRigidArea(hstrut10));
  192. // Up Button
  193. JButton upFolderButton = new JButton(getChangeToParentDirectoryAction());
  194. upFolderButton.setText(null);
  195. upFolderButton.setIcon(upFolderIcon);
  196. upFolderButton.setToolTipText(upFolderToolTipText);
  197. upFolderButton.getAccessibleContext().setAccessibleName(upFolderAccessibleName);
  198. upFolderButton.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  199. upFolderButton.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  200. upFolderButton.setMargin(shrinkwrap);
  201. upFolderButton.setFocusPainted(false);
  202. topPanel.add(upFolderButton);
  203. if (OS_LEVEL < WIN_2k) {
  204. topPanel.add(Box.createRigidArea(hstrut10));
  205. }
  206. JButton b;
  207. if (OS_LEVEL == WIN_98) {
  208. // Desktop Button
  209. File homeDir = fsv.getHomeDirectory();
  210. String toolTipText = homeFolderToolTipText;
  211. if (fsv.isRoot(homeDir)) {
  212. toolTipText = getFileView(fc).getName(homeDir); // Probably "Desktop".
  213. }
  214. b = new JButton(getFileView(fc).getIcon(homeDir));
  215. b.setToolTipText(toolTipText);
  216. b.getAccessibleContext().setAccessibleName(toolTipText);
  217. b.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  218. b.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  219. b.setMargin(shrinkwrap);
  220. b.setFocusPainted(false);
  221. b.addActionListener(getGoHomeAction());
  222. topPanel.add(b);
  223. topPanel.add(Box.createRigidArea(hstrut10));
  224. }
  225. // New Directory Button
  226. b = new JButton(getNewFolderAction());
  227. b.setText(null);
  228. b.setIcon(newFolderIcon);
  229. b.setToolTipText(newFolderToolTipText);
  230. b.getAccessibleContext().setAccessibleName(newFolderAccessibleName);
  231. b.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  232. b.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  233. b.setMargin(shrinkwrap);
  234. b.setFocusPainted(false);
  235. topPanel.add(b);
  236. if (OS_LEVEL < WIN_2k) {
  237. topPanel.add(Box.createRigidArea(hstrut10));
  238. }
  239. // View button group
  240. ButtonGroup viewButtonGroup = new ButtonGroup();
  241. class ViewButtonListener implements ActionListener {
  242. JFileChooser fc;
  243. ViewButtonListener(JFileChooser fc) {
  244. this.fc = fc;
  245. }
  246. public void actionPerformed(ActionEvent e) {
  247. JToggleButton b = (JToggleButton)e.getSource();
  248. JPanel oldViewPanel = currentViewPanel;
  249. if (b == detailsViewButton) {
  250. if (detailsViewPanel == null) {
  251. detailsViewPanel = createDetailsView(fc);
  252. detailsViewPanel.setPreferredSize(LIST_PREF_SIZE);
  253. }
  254. currentViewPanel = detailsViewPanel;
  255. } else {
  256. currentViewPanel = listViewPanel;
  257. }
  258. if (currentViewPanel != oldViewPanel) {
  259. centerPanel.remove(oldViewPanel);
  260. centerPanel.add(currentViewPanel, BorderLayout.CENTER);
  261. centerPanel.revalidate();
  262. centerPanel.repaint();
  263. }
  264. }
  265. }
  266. ViewButtonListener viewButtonListener = new ViewButtonListener(fc);
  267. // List Button
  268. listViewButton = new JToggleButton(listViewIcon);
  269. listViewButton.setToolTipText(listViewButtonToolTipText);
  270. listViewButton.getAccessibleContext().setAccessibleName(listViewButtonAccessibleName);
  271. listViewButton.setFocusPainted(false);
  272. listViewButton.setSelected(true);
  273. listViewButton.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  274. listViewButton.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  275. listViewButton.setMargin(shrinkwrap);
  276. listViewButton.addActionListener(viewButtonListener);
  277. topPanel.add(listViewButton);
  278. viewButtonGroup.add(listViewButton);
  279. // Details Button
  280. detailsViewButton = new JToggleButton(detailsViewIcon);
  281. detailsViewButton.setToolTipText(detailsViewButtonToolTipText);
  282. detailsViewButton.getAccessibleContext().setAccessibleName(detailsViewButtonAccessibleName);
  283. detailsViewButton.setFocusPainted(false);
  284. detailsViewButton.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  285. detailsViewButton.setAlignmentY(JComponent.CENTER_ALIGNMENT);
  286. detailsViewButton.setMargin(shrinkwrap);
  287. detailsViewButton.addActionListener(viewButtonListener);
  288. topPanel.add(detailsViewButton);
  289. viewButtonGroup.add(detailsViewButton);
  290. updateUseShellFolder();
  291. // ************************************** //
  292. // ******* Add the directory pane ******* //
  293. // ************************************** //
  294. centerPanel = new JPanel(new BorderLayout());
  295. listViewPanel = createList(fc);
  296. listSelectionModel = list.getSelectionModel();
  297. listViewPanel.setPreferredSize(LIST_PREF_SIZE);
  298. centerPanel.add(listViewPanel, BorderLayout.CENTER);
  299. currentViewPanel = listViewPanel;
  300. centerPanel.add(getAccessoryPanel(), BorderLayout.AFTER_LINE_ENDS);
  301. JComponent accessory = fc.getAccessory();
  302. if(accessory != null) {
  303. getAccessoryPanel().add(accessory);
  304. }
  305. fc.add(centerPanel, BorderLayout.CENTER);
  306. // ********************************** //
  307. // **** Construct the bottom panel ** //
  308. // ********************************** //
  309. getBottomPanel().setLayout(new BoxLayout(getBottomPanel(), BoxLayout.LINE_AXIS));
  310. // Add the bottom panel to file chooser
  311. centerPanel.add(getBottomPanel(), BorderLayout.SOUTH);
  312. // labels
  313. JPanel labelPanel = new JPanel();
  314. labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.PAGE_AXIS));
  315. labelPanel.add(Box.createRigidArea(vstrut4));
  316. JLabel fnl = new JLabel(fileNameLabelText);
  317. fnl.setDisplayedMnemonic(fileNameLabelMnemonic);
  318. fnl.setAlignmentY(0);
  319. labelPanel.add(fnl);
  320. labelPanel.add(Box.createRigidArea(new Dimension(1,12)));
  321. JLabel ftl = new JLabel(filesOfTypeLabelText);
  322. ftl.setDisplayedMnemonic(filesOfTypeLabelMnemonic);
  323. labelPanel.add(ftl);
  324. getBottomPanel().add(labelPanel);
  325. getBottomPanel().add(Box.createRigidArea(new Dimension(15, 0)));
  326. // file entry and filters
  327. JPanel fileAndFilterPanel = new JPanel();
  328. fileAndFilterPanel.add(Box.createRigidArea(vstrut8));
  329. fileAndFilterPanel.setLayout(new BoxLayout(fileAndFilterPanel, BoxLayout.Y_AXIS));
  330. filenameTextField = new JTextField(35) {
  331. public Dimension getMaximumSize() {
  332. return new Dimension(Short.MAX_VALUE, super.getPreferredSize().height);
  333. }
  334. };
  335. fnl.setLabelFor(filenameTextField);
  336. filenameTextField.addFocusListener(
  337. new FocusAdapter() {
  338. public void focusGained(FocusEvent e) {
  339. if (!getFileChooser().isMultiSelectionEnabled()) {
  340. listSelectionModel.clearSelection();
  341. }
  342. }
  343. }
  344. );
  345. if (fc.isMultiSelectionEnabled()) {
  346. setFileName(fileNameString(fc.getSelectedFiles()));
  347. } else {
  348. setFileName(fileNameString(fc.getSelectedFile()));
  349. }
  350. fileAndFilterPanel.add(filenameTextField);
  351. fileAndFilterPanel.add(Box.createRigidArea(vstrut8));
  352. filterComboBoxModel = createFilterComboBoxModel();
  353. fc.addPropertyChangeListener(filterComboBoxModel);
  354. filterComboBox = new JComboBox(filterComboBoxModel);
  355. ftl.setLabelFor(filterComboBox);
  356. filterComboBox.setRenderer(createFilterComboBoxRenderer());
  357. fileAndFilterPanel.add(filterComboBox);
  358. getBottomPanel().add(fileAndFilterPanel);
  359. getBottomPanel().add(Box.createRigidArea(hstrut10));
  360. // buttons
  361. getButtonPanel().setLayout(new BoxLayout(getButtonPanel(), BoxLayout.Y_AXIS));
  362. approveButton = new JButton(getApproveButtonText(fc)) {
  363. public Dimension getMaximumSize() {
  364. return approveButton.getPreferredSize().width > cancelButton.getPreferredSize().width ?
  365. approveButton.getPreferredSize() : cancelButton.getPreferredSize();
  366. }
  367. };
  368. approveButton.setMnemonic(getApproveButtonMnemonic(fc));
  369. approveButton.addActionListener(getApproveSelectionAction());
  370. approveButton.setToolTipText(getApproveButtonToolTipText(fc));
  371. getButtonPanel().add(Box.createRigidArea(vstrut4));
  372. getButtonPanel().add(approveButton);
  373. getButtonPanel().add(Box.createRigidArea(vstrut6));
  374. cancelButton = new JButton(cancelButtonText) {
  375. public Dimension getMaximumSize() {
  376. return approveButton.getPreferredSize().width > cancelButton.getPreferredSize().width ?
  377. approveButton.getPreferredSize() : cancelButton.getPreferredSize();
  378. }
  379. };
  380. cancelButton.setMnemonic(cancelButtonMnemonic);
  381. cancelButton.setToolTipText(cancelButtonToolTipText);
  382. cancelButton.addActionListener(getCancelSelectionAction());
  383. getButtonPanel().add(cancelButton);
  384. if(fc.getControlButtonsAreShown()) {
  385. addControlButtons();
  386. }
  387. }
  388. private void updateUseShellFolder() {
  389. // Decide whether to use the ShellFolder class to populate shortcut
  390. // panel and combobox.
  391. JFileChooser fc = getFileChooser();
  392. Boolean prop =
  393. (Boolean)fc.getClientProperty("FileChooser.useShellFolder");
  394. if (prop != null) {
  395. useShellFolder = prop.booleanValue();
  396. } else {
  397. // See if FileSystemView.getRoots() returns the desktop folder,
  398. // i.e. the normal Windows hierarchy.
  399. useShellFolder = false;
  400. File[] roots = fc.getFileSystemView().getRoots();
  401. if (roots != null && roots.length == 1) {
  402. File[] cbFolders = (File[])ShellFolder.get("fileChooserComboBoxFolders");
  403. if (cbFolders != null && cbFolders.length > 0 && roots[0] == cbFolders[0]) {
  404. useShellFolder = true;
  405. }
  406. }
  407. }
  408. if (OS_LEVEL >= WIN_2k) {
  409. if (useShellFolder) {
  410. if (shortCutPanel == null) {
  411. shortCutPanel = new ShortCutPanel();
  412. fc.add(shortCutPanel, BorderLayout.BEFORE_LINE_BEGINS);
  413. }
  414. } else {
  415. if (shortCutPanel != null) {
  416. fc.remove(shortCutPanel);
  417. shortCutPanel = null;
  418. }
  419. }
  420. }
  421. }
  422. protected JPanel getButtonPanel() {
  423. if(buttonPanel == null) {
  424. buttonPanel = new JPanel();
  425. }
  426. return buttonPanel;
  427. }
  428. protected JPanel getBottomPanel() {
  429. if(bottomPanel == null) {
  430. bottomPanel = new JPanel();
  431. }
  432. return bottomPanel;
  433. }
  434. protected void installStrings(JFileChooser fc) {
  435. super.installStrings(fc);
  436. Locale l = fc.getLocale();
  437. lookInLabelMnemonic = UIManager.getInt("FileChooser.lookInLabelMnemonic");
  438. lookInLabelText = UIManager.getString("FileChooser.lookInLabelText",l);
  439. saveInLabelText = UIManager.getString("FileChooser.saveInLabelText",l);
  440. fileNameLabelMnemonic = UIManager.getInt("FileChooser.fileNameLabelMnemonic");
  441. fileNameLabelText = UIManager.getString("FileChooser.fileNameLabelText",l);
  442. filesOfTypeLabelMnemonic = UIManager.getInt("FileChooser.filesOfTypeLabelMnemonic");
  443. filesOfTypeLabelText = UIManager.getString("FileChooser.filesOfTypeLabelText",l);
  444. upFolderToolTipText = UIManager.getString("FileChooser.upFolderToolTipText",l);
  445. upFolderAccessibleName = UIManager.getString("FileChooser.upFolderAccessibleName",l);
  446. homeFolderToolTipText = UIManager.getString("FileChooser.homeFolderToolTipText",l);
  447. homeFolderAccessibleName = UIManager.getString("FileChooser.homeFolderAccessibleName",l);
  448. newFolderToolTipText = UIManager.getString("FileChooser.newFolderToolTipText",l);
  449. newFolderAccessibleName = UIManager.getString("FileChooser.newFolderAccessibleName",l);
  450. listViewButtonToolTipText = UIManager.getString("FileChooser.listViewButtonToolTipText",l);
  451. listViewButtonAccessibleName = UIManager.getString("FileChooser.listViewButtonAccessibleName",l);
  452. detailsViewButtonToolTipText = UIManager.getString("FileChooser.detailsViewButtonToolTipText",l);
  453. detailsViewButtonAccessibleName = UIManager.getString("FileChooser.detailsViewButtonAccessibleName",l);
  454. fileNameHeaderText = UIManager.getString("FileChooser.fileNameHeaderText",l);
  455. fileSizeHeaderText = UIManager.getString("FileChooser.fileSizeHeaderText",l);
  456. fileTypeHeaderText = UIManager.getString("FileChooser.fileTypeHeaderText",l);
  457. fileDateHeaderText = UIManager.getString("FileChooser.fileDateHeaderText",l);
  458. fileAttrHeaderText = UIManager.getString("FileChooser.fileAttrHeaderText",l);
  459. }
  460. protected void installListeners(JFileChooser fc) {
  461. super.installListeners(fc);
  462. ActionMap actionMap = getActionMap();
  463. SwingUtilities.replaceUIActionMap(fc, actionMap);
  464. }
  465. protected ActionMap getActionMap() {
  466. return createActionMap();
  467. }
  468. protected ActionMap createActionMap() {
  469. AbstractAction escAction = new AbstractAction() {
  470. public void actionPerformed(ActionEvent e) {
  471. if (editFile != null) {
  472. cancelEdit();
  473. } else {
  474. getFileChooser().cancelSelection();
  475. }
  476. }
  477. public boolean isEnabled(){
  478. return getFileChooser().isEnabled();
  479. }
  480. };
  481. ActionMap map = new ActionMapUIResource();
  482. map.put("approveSelection", getApproveSelectionAction());
  483. map.put("cancelSelection", escAction);
  484. map.put("Go Up", getChangeToParentDirectoryAction());
  485. return map;
  486. }
  487. class ShortCutPanel extends JToolBar implements ActionListener {
  488. JToggleButton[] buttons;
  489. File[] files;
  490. XPStyle xp = XPStyle.getXP();
  491. final Dimension buttonSize = new Dimension(83, (xp != null) ? 69 : 54);
  492. ShortCutPanel() {
  493. super(JToolBar.VERTICAL);
  494. setFloatable(false);
  495. putClientProperty("JToolBar.isRollover", Boolean.TRUE);
  496. if (xp != null) {
  497. putClientProperty("XPStyle.subClass", "placesbar");
  498. setBorder(new EmptyBorder(1, 1, 1, 1));
  499. } else {
  500. setBorder(listViewBorder);
  501. }
  502. Color bgColor = new Color(UIManager.getColor("ToolBar.shadow").getRGB());
  503. setBackground(bgColor);
  504. JFileChooser chooser = getFileChooser();
  505. FileSystemView fsv = chooser.getFileSystemView();
  506. files = (File[])ShellFolder.get("fileChooserShortcutPanelFolders");
  507. buttons = new JToggleButton[files.length];
  508. ButtonGroup buttonGroup = new ButtonGroup();
  509. for (int i = 0; i < files.length; i++) {
  510. if (fsv.isFileSystemRoot(files[i])) {
  511. // Create special File wrapper for drive path
  512. files[i] = fsv.createFileObject(files[i].getAbsolutePath());
  513. }
  514. String folderName = fsv.getSystemDisplayName(files[i]);
  515. int index = folderName.lastIndexOf(File.separatorChar);
  516. if (index >= 0 && index < folderName.length() - 1) {
  517. folderName = folderName.substring(index + 1);
  518. }
  519. Icon icon = null;
  520. if (files[i] instanceof ShellFolder) {
  521. // We want a large icon, fsv only gives us a small.
  522. ShellFolder sf = (ShellFolder)files[i];
  523. icon = new ImageIcon(sf.getIcon(true), sf.getFolderType());
  524. } else {
  525. icon = fsv.getSystemIcon(files[i]);
  526. }
  527. buttons[i] = new JToggleButton(folderName, icon);
  528. if (xp != null) {
  529. buttons[i].setIconTextGap(2);
  530. buttons[i].setMargin(new Insets(2, 2, 2, 2));
  531. buttons[i].setText("<html><center>"+folderName+"</center></html>");
  532. } else {
  533. Color fgColor = new Color(UIManager.getColor("List.selectionForeground").getRGB());
  534. buttons[i].setBackground(bgColor);
  535. buttons[i].setForeground(fgColor);
  536. }
  537. buttons[i].setHorizontalTextPosition(JToggleButton.CENTER);
  538. buttons[i].setVerticalTextPosition(JToggleButton.BOTTOM);
  539. buttons[i].setAlignmentX(JComponent.CENTER_ALIGNMENT);
  540. buttons[i].setPreferredSize(buttonSize);
  541. buttons[i].setMaximumSize(buttonSize);
  542. buttons[i].addActionListener(this);
  543. add(buttons[i]);
  544. if (i < files.length-1 && xp != null) {
  545. add(Box.createRigidArea(vstrut1));
  546. }
  547. buttonGroup.add(buttons[i]);
  548. }
  549. doDirectoryChanged(chooser.getCurrentDirectory());
  550. }
  551. void doDirectoryChanged(File f) {
  552. for (int i=0; i<buttons.length; i++) {
  553. buttons[i].setSelected(files[i].equals(f));
  554. }
  555. }
  556. public void actionPerformed(ActionEvent e) {
  557. JToggleButton b = (JToggleButton)e.getSource();
  558. for (int i=0; i<buttons.length; i++) {
  559. if (b == buttons[i]) {
  560. getFileChooser().setCurrentDirectory(files[i]);
  561. break;
  562. }
  563. }
  564. }
  565. public Dimension getPreferredSize() {
  566. Dimension min = super.getMinimumSize();
  567. Dimension pref = super.getPreferredSize();
  568. if (min.height > pref.height) {
  569. pref = new Dimension(pref.width, min.height);
  570. }
  571. return pref;
  572. }
  573. } // class ShortCutPanel
  574. private void updateListRowCount() {
  575. if (smallIconsView) {
  576. list.setVisibleRowCount(getModel().getSize() / 3);
  577. } else {
  578. list.setVisibleRowCount(-1);
  579. }
  580. }
  581. protected JPanel createList(JFileChooser fc) {
  582. JPanel p = new JPanel(new BorderLayout());
  583. final JFileChooser fileChooser = fc;
  584. list = new JList() {
  585. public int getNextMatch(String prefix, int startIndex, Position.Bias bias) {
  586. ListModel model = getModel();
  587. int max = model.getSize();
  588. if (prefix == null || startIndex < 0 || startIndex >= max) {
  589. throw new IllegalArgumentException();
  590. }
  591. // start search from the next element before/after the selected element
  592. boolean backwards = (bias == Position.Bias.Backward);
  593. for (int i = startIndex; backwards ? i >= 0 : i < max; i += (backwards ? -1 : 1)) {
  594. String filename = fileChooser.getName((File)model.getElementAt(i));
  595. if (filename.regionMatches(true, 0, prefix, 0, prefix.length())) {
  596. return i;
  597. }
  598. }
  599. return -1;
  600. }
  601. };
  602. list.setCellRenderer(new FileRenderer());
  603. list.setLayoutOrientation(JList.VERTICAL_WRAP);
  604. updateListRowCount();
  605. getModel().addListDataListener(new ListDataListener() {
  606. public void intervalAdded(ListDataEvent e) {
  607. updateListRowCount();
  608. }
  609. public void intervalRemoved(ListDataEvent e) {
  610. updateListRowCount();
  611. }
  612. public void contentsChanged(ListDataEvent e) {
  613. updateListRowCount();
  614. }
  615. });
  616. if (fc.isMultiSelectionEnabled()) {
  617. list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
  618. } else {
  619. list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
  620. }
  621. list.setModel(getModel());
  622. list.addListSelectionListener(createListSelectionListener(fc));
  623. list.addMouseListener(createDoubleClickListener(fc, list));
  624. list.addMouseListener(createSingleClickListener(fc, list));
  625. getModel().addListDataListener(new ListDataListener() {
  626. public void contentsChanged(ListDataEvent e) {
  627. // Update the selection after JList has been updated
  628. new DelayedSelectionUpdater();
  629. }
  630. public void intervalAdded(ListDataEvent e) {
  631. int i0 = e.getIndex0();
  632. int i1 = e.getIndex1();
  633. if (i0 == i1) {
  634. File file = (File)getModel().getElementAt(i0);
  635. if (file.equals(newFolderFile)) {
  636. new DelayedSelectionUpdater(file);
  637. newFolderFile = null;
  638. }
  639. }
  640. }
  641. public void intervalRemoved(ListDataEvent e) {
  642. }
  643. });
  644. JScrollPane scrollpane = new JScrollPane(list);
  645. XPStyle xp = XPStyle.getXP();
  646. if (xp != null) {
  647. Color bg = xp.getColor("listview.fillcolor", null);
  648. if (bg != null) {
  649. list.setBackground(bg);
  650. }
  651. }
  652. if (listViewBorder != null) {
  653. scrollpane.setBorder(listViewBorder);
  654. }
  655. p.add(scrollpane, BorderLayout.CENTER);
  656. return p;
  657. }
  658. class DetailsTableModel extends AbstractTableModel implements ListDataListener {
  659. String[] columnNames = {
  660. fileNameHeaderText,
  661. fileSizeHeaderText,
  662. fileTypeHeaderText,
  663. fileDateHeaderText,
  664. fileAttrHeaderText
  665. };
  666. JFileChooser chooser;
  667. ListModel listModel;
  668. DetailsTableModel(JFileChooser fc) {
  669. this.chooser = fc;
  670. listModel = getModel();
  671. listModel.addListDataListener(this);
  672. }
  673. public int getRowCount() {
  674. return listModel.getSize();
  675. }
  676. public int getColumnCount() {
  677. return COLUMN_COLCOUNT;
  678. }
  679. public String getColumnName(int column) {
  680. return columnNames[column];
  681. }
  682. public Class getColumnClass(int column) {
  683. switch (column) {
  684. case COLUMN_FILENAME:
  685. return File.class;
  686. case COLUMN_FILEDATE:
  687. return Date.class;
  688. default:
  689. return super.getColumnClass(column);
  690. }
  691. }
  692. public Object getValueAt(int row, int col) {
  693. // Note: It is very important to avoid getting info on drives, as
  694. // this will trigger "No disk in A:" and similar dialogs.
  695. //
  696. // Use (f.exists() && !chooser.getFileSystemView().isFileSystemRoot(f)) to
  697. // determine if it is safe to call methods directly on f.
  698. File f = (File)listModel.getElementAt(row);
  699. switch (col) {
  700. case COLUMN_FILENAME:
  701. return f;
  702. case COLUMN_FILESIZE:
  703. if (!f.exists() || f.isDirectory()) {
  704. return null;
  705. }
  706. return (f.length() / 1024 + 1) + "KB";
  707. case COLUMN_FILETYPE:
  708. if (!f.exists()) {
  709. return null;
  710. }
  711. return chooser.getFileSystemView().getSystemTypeDescription(f);
  712. case COLUMN_FILEDATE:
  713. if (!f.exists() || chooser.getFileSystemView().isFileSystemRoot(f)) {
  714. return null;
  715. }
  716. long time = f.lastModified();
  717. return (time == 0L) ? null : new Date(time);
  718. case COLUMN_FILEATTR:
  719. if (!f.exists() || chooser.getFileSystemView().isFileSystemRoot(f)) {
  720. return null;
  721. }
  722. String attributes = "";
  723. if (!f.canWrite()) {
  724. attributes += "R";
  725. }
  726. if (f.isHidden()) {
  727. attributes += "H";
  728. }
  729. return attributes;
  730. }
  731. return null;
  732. }
  733. public void setValueAt(Object value, int row, int col) {
  734. if (col == COLUMN_FILENAME) {
  735. JFileChooser chooser = getFileChooser();
  736. File f = (File)getValueAt(row, col);
  737. String oldDisplayName = chooser.getName(f);
  738. String oldFileName = f.getName();
  739. String newDisplayName = ((String)value).trim();
  740. String newFileName;
  741. if (!newDisplayName.equals(oldDisplayName)) {
  742. newFileName = newDisplayName;
  743. //Check if extension is hidden from user
  744. int i1 = oldFileName.length();
  745. int i2 = oldDisplayName.length();
  746. if (i1 > i2 && oldFileName.charAt(i2) == '.') {
  747. newFileName = newDisplayName + oldFileName.substring(i2);
  748. }
  749. // rename
  750. FileSystemView fsv = chooser.getFileSystemView();
  751. File f2 = fsv.createFileObject(f.getParentFile(), newFileName);
  752. if (!f2.exists() && WindowsFileChooserUI.this.getModel().renameFile(f, f2)) {
  753. if (fsv.isParent(chooser.getCurrentDirectory(), f2)) {
  754. if (chooser.isMultiSelectionEnabled()) {
  755. chooser.setSelectedFiles(new File[] { f2 });
  756. } else {
  757. chooser.setSelectedFile(f2);
  758. }
  759. } else {
  760. //Could be because of delay in updating Desktop folder
  761. //chooser.setSelectedFile(null);
  762. }
  763. } else {
  764. // PENDING(jeff) - show a dialog indicating failure
  765. }
  766. }
  767. }
  768. }
  769. public boolean isCellEditable(int row, int column) {
  770. return (column == COLUMN_FILENAME);
  771. }
  772. public void contentsChanged(ListDataEvent e) {
  773. fireTableDataChanged();
  774. }
  775. public void intervalAdded(ListDataEvent e) {
  776. fireTableDataChanged();
  777. }
  778. public void intervalRemoved(ListDataEvent e) {
  779. fireTableDataChanged();
  780. }
  781. }
  782. class DetailsTableCellRenderer extends DefaultTableCellRenderer {
  783. JFileChooser chooser;
  784. DateFormat df;
  785. DetailsTableCellRenderer(JFileChooser chooser) {
  786. this.chooser = chooser;
  787. df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT,
  788. chooser.getLocale());
  789. }
  790. public void setBounds(int x, int y, int width, int height) {
  791. super.setBounds(x, y, Math.min(width, this.getPreferredSize().width+4), height);
  792. }
  793. public Component getTableCellRendererComponent(JTable table, Object value,
  794. boolean isSelected, boolean hasFocus, int row, int column) {
  795. if (column == COLUMN_FILESIZE || column == COLUMN_FILEATTR) {
  796. setHorizontalAlignment(SwingConstants.TRAILING);
  797. } else {
  798. setHorizontalAlignment(SwingConstants.LEADING);
  799. }
  800. if (column == COLUMN_FILENAME && table.isRowSelected(row) && table.isFocusOwner()) {
  801. super.setForeground(table.getSelectionForeground());
  802. super.setBackground(table.getSelectionBackground());
  803. } else {
  804. super.setForeground(table.getForeground());
  805. super.setBackground(table.getBackground());
  806. }
  807. setFont(table.getFont());
  808. setValue(value);
  809. return this;
  810. }
  811. public void setValue(Object value) {
  812. setIcon(null);
  813. if (value instanceof File) {
  814. File file = (File)value;
  815. String fileName = chooser.getName(file);
  816. setText(fileName);
  817. Icon icon = chooser.getIcon(file);
  818. setIcon(icon);
  819. } else if (value instanceof Date) {
  820. setText((value == null) ? "" : df.format((Date)value));
  821. } else {
  822. super.setValue(value);
  823. }
  824. }
  825. }
  826. protected JPanel createDetailsView(JFileChooser fc) {
  827. final JFileChooser chooser = fc;
  828. JPanel p = new JPanel(new BorderLayout());
  829. DetailsTableModel detailsTableModel = new DetailsTableModel(chooser);
  830. detailsTable = new JTable(detailsTableModel) {
  831. // Handle Escape key events here
  832. protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
  833. if (e.getKeyCode() == KeyEvent.VK_ESCAPE && getCellEditor() == null) {
  834. // We are not editing, forward to filechooser.
  835. chooser.dispatchEvent(e);
  836. return true;
  837. }
  838. return super.processKeyBinding(ks, e, condition, pressed);
  839. }
  840. };
  841. detailsTable.setComponentOrientation(chooser.getComponentOrientation());
  842. detailsTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
  843. detailsTable.setShowGrid(false);
  844. detailsTable.setSelectionModel(listSelectionModel);
  845. detailsTable.putClientProperty("JTable.autoStartsEdit", Boolean.FALSE);
  846. Font font = detailsTable.getFont();
  847. detailsTable.setRowHeight(Math.max(font.getSize(), 19)+3);
  848. TableColumnModel columnModel = detailsTable.getColumnModel();
  849. TableColumn[] columns = new TableColumn[COLUMN_COLCOUNT];
  850. for (int i = 0; i < COLUMN_COLCOUNT; i++) {
  851. columns[i] = columnModel.getColumn(i);
  852. columns[i].setPreferredWidth(COLUMN_WIDTHS[i]);
  853. }
  854. TableCellRenderer cellRenderer = new DetailsTableCellRenderer(chooser);
  855. detailsTable.setDefaultRenderer(File.class, cellRenderer);
  856. detailsTable.setDefaultRenderer(Date.class, cellRenderer);
  857. detailsTable.setDefaultRenderer(Object.class, cellRenderer);
  858. // Install cell editor for editing file name
  859. final JTextField tf = new JTextField();
  860. tf.addFocusListener(editorFocusListener);
  861. columns[COLUMN_FILENAME].setCellEditor(new DefaultCellEditor(tf) {
  862. public boolean isCellEditable(EventObject e) {
  863. if (e instanceof MouseEvent) {
  864. MouseEvent me = (MouseEvent)e;
  865. int index = detailsTable.rowAtPoint(me.getPoint());
  866. return (me.getClickCount() == 1 && detailsTable.isRowSelected(index));
  867. }
  868. return super.isCellEditable(e);
  869. }
  870. public Component getTableCellEditorComponent(JTable table, Object value,
  871. boolean isSelected, int row, int column) {
  872. Component comp = super.getTableCellEditorComponent(table, value, isSelected, row, column);
  873. if (value instanceof File) {
  874. tf.setText(chooser.getName((File)value));
  875. tf.requestFocus();
  876. tf.selectAll();
  877. }
  878. return comp;
  879. }
  880. });
  881. JList fakeList = new JList(detailsTableModel.listModel) {
  882. JTable table = detailsTable;
  883. public int locationToIndex(Point location) {
  884. return table.rowAtPoint(location);
  885. }
  886. public Rectangle getCellBounds(int index0, int index1) {
  887. Rectangle r0 = table.getCellRect(index0, COLUMN_FILENAME, false);
  888. Rectangle r1 = table.getCellRect(index1, COLUMN_FILENAME, false);
  889. return r0.union(r1);
  890. }
  891. public Object getSelectedValue() {
  892. return table.getValueAt(table.getSelectedRow(), COLUMN_FILENAME);
  893. }
  894. public Component add(Component comp) {
  895. if (comp instanceof JTextField) {
  896. return table.add(comp);
  897. } else {
  898. return super.add(comp);
  899. }
  900. }
  901. public void repaint() {
  902. if (table != null)
  903. table.repaint();
  904. }
  905. public TransferHandler getTransferHandler() {
  906. if (table != null) {
  907. return table.getTransferHandler();
  908. } else {
  909. return super.getTransferHandler();
  910. }
  911. }
  912. public void setTransferHandler(TransferHandler newHandler) {
  913. if (table != null) {
  914. table.setTransferHandler(newHandler);
  915. } else {
  916. super.setTransferHandler(newHandler);
  917. }
  918. }
  919. public boolean getDragEnabled() {
  920. if (table != null) {
  921. return table.getDragEnabled();
  922. } else {
  923. return super.getDragEnabled();
  924. }
  925. }
  926. public void setDragEnabled(boolean b) {
  927. if (table != null) {
  928. table.setDragEnabled(b);
  929. } else {
  930. super.setDragEnabled(b);
  931. }
  932. }
  933. };
  934. fakeList.setSelectionModel(listSelectionModel);
  935. detailsTable.addMouseListener(createDoubleClickListener(chooser, fakeList));
  936. //detailsTable.addMouseListener(createSingleClickListener(chooser, fakeList));
  937. JScrollPane scrollpane = new JScrollPane(detailsTable);
  938. scrollpane.setComponentOrientation(chooser.getComponentOrientation());
  939. LookAndFeel.installColors(scrollpane.getViewport(), "Table.background", "Table.foreground");
  940. scrollpane.addComponentListener(new ComponentAdapter() {
  941. public void componentResized(ComponentEvent e) {
  942. JScrollPane sp = (JScrollPane)e.getComponent();
  943. fixNameColumnWidth(sp.getViewport().getSize().width);
  944. sp.removeComponentListener(this);
  945. }
  946. });
  947. XPStyle xp = XPStyle.getXP();
  948. if (xp != null) {
  949. Color bg = xp.getColor("listview.fillcolor", null);
  950. if (bg != null) {
  951. list.setBackground(bg);
  952. }
  953. }
  954. if (listViewBorder != null) {
  955. scrollpane.setBorder(listViewBorder);
  956. }
  957. p.add(scrollpane, BorderLayout.CENTER);
  958. return p;
  959. }
  960. private void fixNameColumnWidth(int viewWidth) {
  961. TableColumn nameCol = detailsTable.getColumnModel().getColumn(COLUMN_FILENAME);
  962. int tableWidth = detailsTable.getPreferredSize().width;
  963. if (tableWidth < viewWidth) {
  964. nameCol.setPreferredWidth(nameCol.getPreferredWidth() + viewWidth - tableWidth);
  965. }
  966. }
  967. private class DelayedSelectionUpdater implements Runnable {
  968. File editFile;
  969. DelayedSelectionUpdater() {
  970. this(null);
  971. }
  972. DelayedSelectionUpdater(File editFile) {
  973. this.editFile = editFile;
  974. SwingUtilities.invokeLater(this);
  975. }
  976. public void run() {
  977. setFileSelected();
  978. if (editFile != null) {
  979. editFileName(getModel().indexOf(editFile));
  980. editFile = null;
  981. }
  982. }
  983. }
  984. /**
  985. * Creates a selection listener for the list of files and directories.
  986. *
  987. * @param fc a <code>JFileChooser</code>
  988. * @return a <code>ListSelectionListener</code>
  989. */
  990. public ListSelectionListener createListSelectionListener(JFileChooser fc) {
  991. return new SelectionListener() {
  992. public void valueChanged(ListSelectionEvent e) {
  993. if (!e.getValueIsAdjusting()) {
  994. JFileChooser chooser = getFileChooser();
  995. FileSystemView fsv = chooser.getFileSystemView();
  996. JList list = (JList) e.getSource();
  997. if (chooser.isMultiSelectionEnabled()) {
  998. File[] files = null;
  999. Object[] objects = list.getSelectedValues();
  1000. if (objects != null) {
  1001. if (objects.length == 1
  1002. && ((File)objects[0]).isDirectory()
  1003. && chooser.isTraversable(((File)objects[0]))
  1004. && (chooser.getFileSelectionMode() == chooser.FILES_ONLY
  1005. || !fsv.isFileSystem(((File)objects[0])))) {
  1006. setDirectorySelected(true);
  1007. setDirectory(((File)objects[0]));
  1008. } else {
  1009. files = new File[objects.length];
  1010. int j = 0;
  1011. for (int i = 0; i < objects.length; i++) {
  1012. File f = (File)objects[i];
  1013. boolean isDir = f.isDirectory();
  1014. boolean isFile = ShellFolder.disableFileChooserSpeedFix() ? f.isFile() : !isDir;
  1015. if ((chooser.isFileSelectionEnabled() && isFile)
  1016. || (chooser.isDirectorySelectionEnabled()
  1017. && fsv.isFileSystem(f)
  1018. && isDir)) {
  1019. files[j++] = f;
  1020. }
  1021. }
  1022. if (j == 0) {
  1023. files = null;
  1024. } else if (j < objects.length) {
  1025. File[] tmpFiles = new File[j];
  1026. System.arraycopy(files, 0, tmpFiles, 0, j);
  1027. files = tmpFiles;
  1028. }
  1029. setDirectorySelected(false);
  1030. }
  1031. }
  1032. chooser.setSelectedFiles(files);
  1033. } else {
  1034. File file = (File)list.getSelectedValue();
  1035. if (file != null
  1036. && file.isDirectory()
  1037. && chooser.isTraversable(file)
  1038. && (chooser.getFileSelectionMode() == chooser.FILES_ONLY
  1039. || !fsv.isFileSystem(file))) {
  1040. setDirectorySelected(true);
  1041. setDirectory(file);
  1042. chooser.setSelectedFile(null);
  1043. } else {
  1044. setDirectorySelected(false);
  1045. if (file != null) {
  1046. chooser.setSelectedFile(file);
  1047. }
  1048. }
  1049. }
  1050. }
  1051. }
  1052. };
  1053. }
  1054. private MouseListener createSingleClickListener(JFileChooser fc, JList list) {
  1055. return new SingleClickListener(list);
  1056. }
  1057. int lastIndex = -1;
  1058. File editFile = null;
  1059. int editX = 20;
  1060. private int getEditIndex() {
  1061. return lastIndex;
  1062. }
  1063. private void setEditIndex(int i) {
  1064. lastIndex = i;
  1065. }
  1066. private void resetEditIndex() {
  1067. lastIndex = -1;
  1068. }
  1069. private void cancelEdit() {
  1070. if (editFile != null) {
  1071. editFile = null;
  1072. list.remove(editCell);
  1073. centerPanel.repaint();
  1074. } else if (detailsTable != null && detailsTable.isEditing()) {
  1075. detailsTable.getCellEditor().cancelCellEditing();
  1076. }
  1077. }
  1078. JTextField editCell = null;
  1079. private void editFileName(int index) {
  1080. ensureIndexIsVisible(index);
  1081. if (listViewPanel.isVisible()) {
  1082. editFile = (File)getModel().getElementAt(index);
  1083. Rectangle r = list.getCellBounds(index, index);
  1084. if (editCell == null) {
  1085. editCell = new JTextField();
  1086. editCell.addActionListener(new EditActionListener());
  1087. editCell.addFocusListener(editorFocusListener);
  1088. editCell.setNextFocusableComponent(list);
  1089. }
  1090. list.add(editCell);
  1091. editCell.setText(getFileChooser().getName(editFile));
  1092. if (list.getComponentOrientation().isLeftToRight()) {
  1093. editCell.setBounds(editX + r.x, r.y, r.width - editX, r.height);
  1094. } else {
  1095. editCell.setBounds(r.x, r.y, r.width - editX, r.height);
  1096. }
  1097. editCell.requestFocus();
  1098. editCell.selectAll();
  1099. } else if (detailsViewPanel.isVisible()) {
  1100. detailsTable.editCellAt(index, COLUMN_FILENAME);
  1101. }
  1102. }
  1103. protected class SingleClickListener extends MouseAdapter {
  1104. JList list;
  1105. public SingleClickListener(JList list) {
  1106. this.list = list;
  1107. }
  1108. public void mouseClicked(MouseEvent e) {
  1109. if (SwingUtilities.isLeftMouseButton(e)) {
  1110. if (e.getClickCount() == 1) {
  1111. JFileChooser fc = getFileChooser();
  1112. int index = list.locationToIndex(e.getPoint());
  1113. if ((!fc.isMultiSelectionEnabled() || fc.getSelectedFiles().length <= 1)
  1114. && index >= 0 && list.isSelectedIndex(index)
  1115. && getEditIndex() == index && editFile == null) {
  1116. editFileName(index);
  1117. } else {
  1118. if (index >= 0) {
  1119. setEditIndex(index);
  1120. } else {
  1121. resetEditIndex();
  1122. }
  1123. }
  1124. } else {
  1125. // on double click (open or drill down one directory) be
  1126. // sure to clear the edit index
  1127. resetEditIndex();
  1128. }
  1129. }
  1130. }
  1131. }
  1132. public Action getNewFolderAction() {
  1133. return newFolderAction;
  1134. }
  1135. /**
  1136. * Creates a new folder.
  1137. */
  1138. protected class WindowsNewFolderAction extends NewFolderAction {
  1139. public void actionPerformed(ActionEvent e) {
  1140. JFileChooser fc = getFileChooser();
  1141. File oldFile = fc.getSelectedFile();
  1142. super.actionPerformed(e);
  1143. File newFile = fc.getSelectedFile();
  1144. if (newFile != null && !newFile.equals(oldFile) && newFile.isDirectory()) {
  1145. newFolderFile = newFile;
  1146. }
  1147. }
  1148. }
  1149. class EditActionListener implements ActionListener {
  1150. public void actionPerformed(ActionEvent e) {
  1151. applyEdit();
  1152. }
  1153. }
  1154. private void applyEdit() {
  1155. if (editFile != null && editFile.exists()) {
  1156. JFileChooser chooser = getFileChooser();
  1157. String oldDisplayName = chooser.getName(editFile);
  1158. String oldFileName = editFile.getName();
  1159. String newDisplayName = editCell.getText().trim();
  1160. String newFileName;
  1161. if (!newDisplayName.equals(oldDisplayName)) {
  1162. newFileName = newDisplayName;
  1163. //Check if extension is hidden from user
  1164. int i1 = oldFileName.length();
  1165. int i2 = oldDisplayName.length();
  1166. if (i1 > i2 && oldFileName.charAt(i2) == '.') {
  1167. newFileName = newDisplayName + oldFileName.substring(i2);
  1168. }
  1169. // rename
  1170. FileSystemView fsv = chooser.getFileSystemView();
  1171. File f2 = fsv.createFileObject(editFile.getParentFile(), newFileName);
  1172. if (!f2.exists() && getModel().renameFile(editFile, f2)) {
  1173. if (fsv.isParent(chooser.getCurrentDirectory(), f2)) {
  1174. if (chooser.isMultiSelectionEnabled()) {
  1175. chooser.setSelectedFiles(new File[] { f2 });
  1176. } else {
  1177. chooser.setSelectedFile(f2);
  1178. }
  1179. } else {
  1180. //Could be because of delay in updating Desktop folder
  1181. //chooser.setSelectedFile(null);
  1182. }
  1183. } else {
  1184. // PENDING(jeff) - show a dialog indicating failure
  1185. }
  1186. }
  1187. }
  1188. if (detailsTable != null && detailsTable.isEditing()) {
  1189. detailsTable.getCellEditor().stopCellEditing();
  1190. }
  1191. cancelEdit();
  1192. }
  1193. protected class FileRenderer extends DefaultListCellRenderer {
  1194. public void setBounds(int x, int y, int width, int height) {
  1195. super.setBounds(x, y, Math.min(width, this.getPreferredSize().width+4), height);
  1196. }
  1197. public Component getListCellRendererComponent(JList list, Object value,
  1198. int index, boolean isSelected,
  1199. boolean cellHasFocus) {
  1200. super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
  1201. File file = (File) value;
  1202. String fileName = getFileChooser().getName(file);
  1203. setText(fileName);
  1204. Icon icon = getFileChooser().getIcon(file);
  1205. setIcon(icon);
  1206. if(isSelected) {
  1207. // PENDING(jeff) - grab padding (4) below from defaults table.
  1208. editX = icon.getIconWidth() + 4;
  1209. }
  1210. return this;
  1211. }
  1212. }
  1213. public void uninstallUI(JComponent c) {
  1214. // Remove listeners
  1215. c.removePropertyChangeListener(filterComboBoxModel);
  1216. cancelButton.removeActionListener(getCancelSelectionAction());
  1217. approveButton.removeActionListener(getApproveSelectionAction());
  1218. filenameTextField.removeActionListener(getApproveSelectionAction());
  1219. super.uninstallUI(c);
  1220. }
  1221. /**
  1222. * Returns the preferred size of the specified
  1223. * <code>JFileChooser</code>.
  1224. * The preferred size is at least as large,
  1225. * in both height and width,
  1226. * as the preferred size recommended
  1227. * by the file chooser's layout manager.
  1228. *
  1229. * @param c a <code>JFileChooser</code>
  1230. * @return a <code>Dimension</code> specifying the preferred
  1231. * width and height of the file chooser
  1232. */
  1233. public Dimension getPreferredSize(JComponent c) {
  1234. int prefWidth = PREF_SIZE.width;
  1235. Dimension d = c.getLayout().preferredLayoutSize(c);
  1236. if (d != null) {
  1237. return new Dimension(d.width < prefWidth ? prefWidth : d.width,
  1238. d.height < PREF_SIZE.height ? PREF_SIZE.height : d.height);
  1239. } else {
  1240. return new Dimension(prefWidth, PREF_SIZE.height);
  1241. }
  1242. }
  1243. /**
  1244. * Returns the minimum size of the <code>JFileChooser</code>.
  1245. *
  1246. * @param c a <code>JFileChooser</code>
  1247. * @return a <code>Dimension</code> specifying the minimum
  1248. * width and height of the file chooser
  1249. */
  1250. public Dimension getMinimumSize(JComponent c) {
  1251. return MIN_SIZE;
  1252. }
  1253. /**
  1254. * Returns the maximum size of the <code>JFileChooser</code>.
  1255. *
  1256. * @param c a <code>JFileChooser</code>
  1257. * @return a <code>Dimension</code> specifying the maximum
  1258. * width and height of the file chooser
  1259. */
  1260. public Dimension getMaximumSize(JComponent c) {
  1261. return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
  1262. }
  1263. void setFileSelected() {
  1264. if (getFileChooser().isMultiSelectionEnabled() && !isDirectorySelected()) {
  1265. File[] files = getFileChooser().getSelectedFiles(); // Should be selected
  1266. Object[] selectedObjects = list.getSelectedValues(); // Are actually selected
  1267. if (ShellFolder.disableFileChooserSpeedFix()) {
  1268. // Remove files that shouldn't be selected
  1269. for (int j = 0; j < selectedObjects.length; j++) {
  1270. boolean found = false;
  1271. for (int i = 0; i < files.length; i++) {
  1272. if (files[i].equals(selectedObjects[j])) {
  1273. found = true;
  1274. break;
  1275. }
  1276. }
  1277. if (!found) {
  1278. int index = getModel().indexOf(selectedObjects[j]);
  1279. if (index >= 0) {
  1280. listSelectionModel.removeSelectionInterval(index, index);
  1281. }
  1282. }
  1283. }
  1284. // Add files that should be selected
  1285. for (int i = 0; i < files.length; i++) {
  1286. boolean found = false;
  1287. for (int j = 0; j < selectedObjects.length; j++) {
  1288. if (files[i].equals(selectedObjects[j])) {
  1289. found = true;
  1290. break;
  1291. }
  1292. }
  1293. if (!found) {
  1294. int index = getModel().indexOf(files[i]);
  1295. if (index >= 0) {
  1296. listSelectionModel.addSelectionInterval(index, index);
  1297. }
  1298. }
  1299. }
  1300. } else {
  1301. listSelectionModel.setValueIsAdjusting(true);
  1302. try {
  1303. Arrays.sort(files);
  1304. Arrays.sort(selectedObjects);
  1305. int shouldIndex = 0;
  1306. int actuallyIndex = 0;
  1307. // Remove files that shouldn't be selected and add files which should be selected
  1308. // Note: Assume files are already sorted in compareTo order.
  1309. while (shouldIndex < files.length &&
  1310. actuallyIndex < selectedObjects.length) {
  1311. int comparison = files[shouldIndex].compareTo(selectedObjects[actuallyIndex]);
  1312. if (comparison < 0) {
  1313. int index = getModel().indexOf(files[shouldIndex]);
  1314. listSelectionModel.addSelectionInterval(index, index);
  1315. shouldIndex++;
  1316. } else if (comparison > 0) {
  1317. int index = getModel().indexOf(selectedObjects[actuallyIndex]);
  1318. listSelectionModel.removeSelectionInterval(index, index);
  1319. actuallyIndex++;
  1320. } else {
  1321. // Do nothing
  1322. shouldIndex++;
  1323. actuallyIndex++;
  1324. }
  1325. }
  1326. while (shouldIndex < files.length) {
  1327. int index = getModel().indexOf(files[shouldIndex]);
  1328. listSelectionModel.addSelectionInterval(index, index);
  1329. shouldIndex++;
  1330. }
  1331. while (actuallyIndex < selectedObjects.length) {
  1332. int index = getModel().indexOf(selectedObjects[actuallyIndex]);
  1333. listSelectionModel.removeSelectionInterval(index, index);
  1334. actuallyIndex++;
  1335. }
  1336. } finally {
  1337. listSelectionModel.setValueIsAdjusting(false);
  1338. }
  1339. }
  1340. } else {
  1341. JFileChooser chooser = getFileChooser();
  1342. File f = null;
  1343. if (isDirectorySelected()) {
  1344. f = getDirectory();
  1345. } else {
  1346. f = chooser.getSelectedFile();
  1347. }
  1348. int i;
  1349. if (f != null && (i = getModel().indexOf(f)) >= 0) {
  1350. listSelectionModel.setSelectionInterval(i, i);
  1351. ensureIndexIsVisible(i);
  1352. } else {
  1353. listSelectionModel.clearSelection();
  1354. }
  1355. }
  1356. }
  1357. private String fileNameString(File file) {
  1358. if (file == null) {
  1359. return null;
  1360. } else {
  1361. JFileChooser fc = getFileChooser();
  1362. if (fc.isDirectorySelectionEnabled() && !fc.isFileSelectionEnabled()) {
  1363. return file.getPath();
  1364. } else {
  1365. return file.getName();
  1366. }
  1367. }
  1368. }
  1369. private String fileNameString(File[] files) {
  1370. StringBuffer buf = new StringBuffer();
  1371. for (int i = 0; files != null && i < files.length; i++) {
  1372. if (i > 0) {
  1373. buf.append(" ");
  1374. }
  1375. if (files.length > 1) {
  1376. buf.append("\"");
  1377. }
  1378. buf.append(fileNameString(files[i]));
  1379. if (files.length > 1) {
  1380. buf.append("\"");
  1381. }
  1382. }
  1383. return buf.toString();
  1384. }
  1385. /* The following methods are used by the PropertyChange Listener */
  1386. private void doSelectedFileChanged(PropertyChangeEvent e) {
  1387. applyEdit();
  1388. File f = (File) e.getNewValue();
  1389. JFileChooser fc = getFileChooser();
  1390. if (f != null
  1391. && ((fc.isFileSelectionEnabled() && !f.isDirectory())
  1392. || (f.isDirectory() && fc.isDirectorySelectionEnabled()))) {
  1393. setFileName(fileNameString(f));
  1394. setFileSelected();
  1395. }
  1396. }
  1397. private void doSelectedFilesChanged(PropertyChangeEvent e) {
  1398. applyEdit();
  1399. File[] files = (File[]) e.getNewValue();
  1400. JFileChooser fc = getFileChooser();
  1401. if (files != null
  1402. && files.length > 0
  1403. && (files.length > 1 || fc.isDirectorySelectionEnabled() || !files[0].isDirectory())) {
  1404. setFileName(fileNameString(files));
  1405. setFileSelected();
  1406. }
  1407. }
  1408. private void doDirectoryChanged(PropertyChangeEvent e) {
  1409. JFileChooser fc = getFileChooser();
  1410. FileSystemView fsv = fc.getFileSystemView();
  1411. applyEdit();
  1412. resetEditIndex();
  1413. clearIconCache();
  1414. listSelectionModel.clearSelection();
  1415. ensureIndexIsVisible(0);
  1416. File currentDirectory = fc.getCurrentDirectory();
  1417. if (shortCutPanel != null) {
  1418. shortCutPanel.doDirectoryChanged(currentDirectory);
  1419. }
  1420. if(currentDirectory != null) {
  1421. directoryComboBoxModel.addItem(currentDirectory);
  1422. getNewFolderAction().setEnabled(currentDirectory.canWrite());
  1423. getChangeToParentDirectoryAction().setEnabled(!fsv.isRoot(currentDirectory));
  1424. if (fc.isDirectorySelectionEnabled() && !fc.isFileSelectionEnabled()) {
  1425. if (fsv.isFileSystem(currentDirectory)) {
  1426. setFileName(currentDirectory.getPath());
  1427. } else {
  1428. setFileName(null);
  1429. }
  1430. }
  1431. }
  1432. }
  1433. private void doFilterChanged(PropertyChangeEvent e) {
  1434. applyEdit();
  1435. resetEditIndex();
  1436. clearIconCache();
  1437. listSelectionModel.clearSelection();
  1438. }
  1439. private void doFileSelectionModeChanged(PropertyChangeEvent e) {
  1440. applyEdit();
  1441. resetEditIndex();
  1442. clearIconCache();
  1443. listSelectionModel.clearSelection();
  1444. JFileChooser fc = getFileChooser();
  1445. File currentDirectory = fc.getCurrentDirectory();
  1446. if (currentDirectory != null
  1447. && fc.isDirectorySelectionEnabled()
  1448. && !fc.isFileSelectionEnabled()
  1449. && fc.getFileSystemView().isFileSystem(currentDirectory)) {
  1450. setFileName(currentDirectory.getPath());
  1451. } else {
  1452. setFileName(null);
  1453. }
  1454. }
  1455. private void doMultiSelectionChanged(PropertyChangeEvent e) {
  1456. if (getFileChooser().isMultiSelectionEnabled()) {
  1457. listSelectionModel.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
  1458. } else {
  1459. listSelectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
  1460. listSelectionModel.clearSelection();
  1461. getFileChooser().setSelectedFiles(null);
  1462. }
  1463. }
  1464. private void doAccessoryChanged(PropertyChangeEvent e) {
  1465. if(getAccessoryPanel() != null) {
  1466. if(e.getOldValue() != null) {
  1467. getAccessoryPanel().remove((JComponent) e.getOldValue());
  1468. }
  1469. JComponent accessory = (JComponent) e.getNewValue();
  1470. if(accessory != null) {
  1471. getAccessoryPanel().add(accessory, BorderLayout.CENTER);
  1472. }
  1473. }
  1474. }
  1475. private void doApproveButtonTextChanged(PropertyChangeEvent e) {
  1476. JFileChooser chooser = getFileChooser();
  1477. approveButton.setText(getApproveButtonText(chooser));
  1478. approveButton.setToolTipText(getApproveButtonToolTipText(chooser));
  1479. approveButton.setMnemonic(getApproveButtonMnemonic(chooser));
  1480. }
  1481. private void doDialogTypeChanged(PropertyChangeEvent e) {
  1482. JFileChooser chooser = getFileChooser();
  1483. approveButton.setText(getApproveButtonText(chooser));
  1484. approveButton.setToolTipText(getApproveButtonToolTipText(chooser));
  1485. approveButton.setMnemonic(getApproveButtonMnemonic(chooser));
  1486. if (chooser.getDialogType() == JFileChooser.SAVE_DIALOG) {
  1487. lookInLabel.setText(saveInLabelText);
  1488. } else {
  1489. lookInLabel.setText(lookInLabelText);
  1490. }
  1491. }
  1492. private void doApproveButtonMnemonicChanged(PropertyChangeEvent e) {
  1493. approveButton.setMnemonic(getApproveButtonMnemonic(getFileChooser()));
  1494. }
  1495. private void doControlButtonsChanged(PropertyChangeEvent e) {
  1496. if(getFileChooser().getControlButtonsAreShown()) {
  1497. addControlButtons();
  1498. } else {
  1499. removeControlButtons();
  1500. }
  1501. }
  1502. /*
  1503. * Listen for filechooser property changes, such as
  1504. * the selected file changing, or the type of the dialog changing.
  1505. */
  1506. public PropertyChangeListener createPropertyChangeListener(JFileChooser fc) {
  1507. return new PropertyChangeListener() {
  1508. public void propertyChange(PropertyChangeEvent e) {
  1509. String s = e.getPropertyName();
  1510. if(s.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) {
  1511. doSelectedFileChanged(e);
  1512. } else if (s.equals(JFileChooser.SELECTED_FILES_CHANGED_PROPERTY)) {
  1513. doSelectedFilesChanged(e);
  1514. } else if(s.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)) {
  1515. doDirectoryChanged(e);
  1516. } else if(s.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)) {
  1517. doFilterChanged(e);
  1518. } else if(s.equals(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY)) {
  1519. doFileSelectionModeChanged(e);
  1520. } else if(s.equals(JFileChooser.MULTI_SELECTION_ENABLED_CHANGED_PROPERTY)) {
  1521. doMultiSelectionChanged(e);
  1522. } else if(s.equals(JFileChooser.ACCESSORY_CHANGED_PROPERTY)) {
  1523. doAccessoryChanged(e);
  1524. } else if (s.equals(JFileChooser.APPROVE_BUTTON_TEXT_CHANGED_PROPERTY) ||
  1525. s.equals(JFileChooser.APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY)) {
  1526. doApproveButtonTextChanged(e);
  1527. } else if(s.equals(JFileChooser.DIALOG_TYPE_CHANGED_PROPERTY)) {
  1528. doDialogTypeChanged(e);
  1529. } else if(s.equals(JFileChooser.APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY)) {
  1530. doApproveButtonMnemonicChanged(e);
  1531. } else if(s.equals(JFileChooser.CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY)) {
  1532. doControlButtonsChanged(e);
  1533. } else if (s.equals("componentOrientation")) {
  1534. ComponentOrientation o = (ComponentOrientation)e.getNewValue();
  1535. JFileChooser cc = (JFileChooser)e.getSource();
  1536. if (o != (ComponentOrientation)e.getOldValue()) {
  1537. cc.applyComponentOrientation(o);
  1538. }
  1539. if (detailsTable != null) {
  1540. detailsTable.setComponentOrientation(o);
  1541. detailsTable.getParent().getParent().setComponentOrientation(o);
  1542. }
  1543. } else if (s == "FileChooser.useShellFolder") {
  1544. updateUseShellFolder();
  1545. doDirectoryChanged(e);
  1546. } else if (s.equals("ancestor")) {
  1547. if (e.getOldValue() == null && e.getNewValue() != null) {
  1548. // Ancestor was added, set initial focus
  1549. filenameTextField.selectAll();
  1550. filenameTextField.requestFocus();
  1551. }
  1552. }
  1553. }
  1554. };
  1555. }
  1556. protected void removeControlButtons() {
  1557. getBottomPanel().remove(getButtonPanel());
  1558. }
  1559. protected void addControlButtons() {
  1560. getBottomPanel().add(getButtonPanel());
  1561. }
  1562. private void ensureIndexIsVisible(int i) {
  1563. if (i >= 0) {
  1564. list.ensureIndexIsVisible(i);
  1565. if (detailsTable != null) {
  1566. detailsTable.scrollRectToVisible(detailsTable.getCellRect(i, COLUMN_FILENAME, true));
  1567. }
  1568. }
  1569. }
  1570. public void ensureFileIsVisible(JFileChooser fc, File f) {
  1571. ensureIndexIsVisible(getModel().indexOf(f));
  1572. }
  1573. public void rescanCurrentDirectory(JFileChooser fc) {
  1574. getModel().validateFileCache();
  1575. }
  1576. public String getFileName() {
  1577. if(filenameTextField != null) {
  1578. return filenameTextField.getText();
  1579. } else {
  1580. return null;
  1581. }
  1582. }
  1583. public void setFileName(String filename) {
  1584. if(filenameTextField != null) {
  1585. filenameTextField.setText(filename);
  1586. }
  1587. }
  1588. /**
  1589. * Property to remember whether a directory is currently selected in the UI.
  1590. * This is normally called by the UI on a selection event.
  1591. *
  1592. * @param directorySelected if a directory is currently selected.
  1593. * @since 1.4
  1594. */
  1595. protected void setDirectorySelected(boolean directorySelected) {
  1596. super.setDirectorySelected(directorySelected);
  1597. JFileChooser chooser = getFileChooser();
  1598. if(directorySelected) {
  1599. approveButton.setText(directoryOpenButtonText);
  1600. approveButton.setToolTipText(directoryOpenButtonToolTipText);
  1601. approveButton.setMnemonic(directoryOpenButtonMnemonic);
  1602. } else {
  1603. approveButton.setText(getApproveButtonText(chooser));
  1604. approveButton.setToolTipText(getApproveButtonToolTipText(chooser));
  1605. approveButton.setMnemonic(getApproveButtonMnemonic(chooser));
  1606. }
  1607. }
  1608. public String getDirectoryName() {
  1609. // PENDING(jeff) - get the name from the directory combobox
  1610. return null;
  1611. }
  1612. public void setDirectoryName(String dirname) {
  1613. // PENDING(jeff) - set the name in the directory combobox
  1614. }
  1615. protected DirectoryComboBoxRenderer createDirectoryComboBoxRenderer(JFileChooser fc) {
  1616. return new DirectoryComboBoxRenderer();
  1617. }
  1618. //
  1619. // Renderer for DirectoryComboBox
  1620. //
  1621. class DirectoryComboBoxRenderer extends DefaultListCellRenderer {
  1622. IndentIcon ii = new IndentIcon();
  1623. public Component getListCellRendererComponent(JList list, Object value,
  1624. int index, boolean isSelected,
  1625. boolean cellHasFocus) {
  1626. super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
  1627. if (value == null) {
  1628. setText("");
  1629. return this;
  1630. }
  1631. File directory = (File)value;
  1632. setText(getFileChooser().getName(directory));
  1633. Icon icon = getFileChooser().getIcon(directory);
  1634. ii.icon = icon;
  1635. ii.depth = directoryComboBoxModel.getDepth(index);
  1636. setIcon(ii);
  1637. return this;
  1638. }
  1639. }
  1640. final static int space = 10;
  1641. class IndentIcon implements Icon {
  1642. Icon icon = null;
  1643. int depth = 0;
  1644. public void paintIcon(Component c, Graphics g, int x, int y) {
  1645. if (c.getComponentOrientation().isLeftToRight()) {
  1646. icon.paintIcon(c, g, x+depth*space, y);
  1647. } else {
  1648. icon.paintIcon(c, g, x, y);
  1649. }
  1650. }
  1651. public int getIconWidth() {
  1652. return icon.getIconWidth() + depth*space;
  1653. }
  1654. public int getIconHeight() {
  1655. return icon.getIconHeight();
  1656. }
  1657. }
  1658. //
  1659. // DataModel for DirectoryComboxbox
  1660. //
  1661. protected DirectoryComboBoxModel createDirectoryComboBoxModel(JFileChooser fc) {
  1662. return new DirectoryComboBoxModel();
  1663. }
  1664. /**
  1665. * Data model for a type-face selection combo-box.
  1666. */
  1667. protected class DirectoryComboBoxModel extends AbstractListModel implements ComboBoxModel {
  1668. Vector directories = new Vector();
  1669. int[] depths = null;
  1670. File selectedDirectory = null;
  1671. JFileChooser chooser = getFileChooser();
  1672. FileSystemView fsv = chooser.getFileSystemView();
  1673. public DirectoryComboBoxModel() {
  1674. // Add the current directory to the model, and make it the
  1675. // selectedDirectory
  1676. File dir = getFileChooser().getCurrentDirectory();
  1677. if(dir != null) {
  1678. addItem(dir);
  1679. }
  1680. }
  1681. /**
  1682. * Adds the directory to the model and sets it to be selected,
  1683. * additionally clears out the previous selected directory and
  1684. * the paths leading up to it, if any.
  1685. */
  1686. private void addItem(File directory) {
  1687. if(directory == null) {
  1688. return;
  1689. }
  1690. directories.clear();
  1691. File[] baseFolders;
  1692. if (useShellFolder) {
  1693. baseFolders = (File[])ShellFolder.get("fileChooserComboBoxFolders");
  1694. } else {
  1695. baseFolders = fsv.getRoots();
  1696. }
  1697. directories.addAll(Arrays.asList(baseFolders));
  1698. // Get the canonical (full) path. This has the side
  1699. // benefit of removing extraneous chars from the path,
  1700. // for example /foo/bar/ becomes /foo/bar
  1701. File canonical = null;
  1702. try {
  1703. canonical = directory.getCanonicalFile();
  1704. } catch (IOException e) {
  1705. // Maybe drive is not ready. Can't abort here.
  1706. canonical = directory;
  1707. }
  1708. // create File instances of each directory leading up to the top
  1709. try {
  1710. File sf = useShellFolder ? ShellFolder.getShellFolder(canonical)
  1711. : canonical;
  1712. File f = sf;
  1713. Vector path = new Vector(10);
  1714. do {
  1715. path.addElement(f);
  1716. } while ((f = f.getParentFile()) != null);
  1717. int pathCount = path.size();
  1718. // Insert chain at appropriate place in vector
  1719. for (int i = 0; i < pathCount; i++) {
  1720. f = (File)path.get(i);
  1721. if (directories.contains(f)) {
  1722. int topIndex = directories.indexOf(f);
  1723. for (int j = i-1; j >= 0; j--) {
  1724. directories.insertElementAt(path.get(j), topIndex+i-j);
  1725. }
  1726. break;
  1727. }
  1728. }
  1729. calculateDepths();
  1730. setSelectedItem(sf);
  1731. } catch (FileNotFoundException ex) {
  1732. calculateDepths();
  1733. }
  1734. }
  1735. private void calculateDepths() {
  1736. depths = new int[directories.size()];
  1737. for (int i = 0; i < depths.length; i++) {
  1738. File dir = (File)directories.get(i);
  1739. File parent = dir.getParentFile();
  1740. depths[i] = 0;
  1741. if (parent != null) {
  1742. for (int j = i-1; j >= 0; j--) {
  1743. if (parent.equals((File)directories.get(j))) {
  1744. depths[i] = depths[j] + 1;
  1745. break;
  1746. }
  1747. }
  1748. }
  1749. }
  1750. }
  1751. public int getDepth(int i) {
  1752. return (depths != null && i >= 0 && i < depths.length) ? depths[i] : 0;
  1753. }
  1754. public void setSelectedItem(Object selectedDirectory) {
  1755. this.selectedDirectory = (File)selectedDirectory;
  1756. fireContentsChanged(this, -1, -1);
  1757. }
  1758. public Object getSelectedItem() {
  1759. return selectedDirectory;
  1760. }
  1761. public int getSize() {
  1762. return directories.size();
  1763. }
  1764. public Object getElementAt(int index) {
  1765. return directories.elementAt(index);
  1766. }
  1767. }
  1768. //
  1769. // Renderer for Types ComboBox
  1770. //
  1771. protected FilterComboBoxRenderer createFilterComboBoxRenderer() {
  1772. return new FilterComboBoxRenderer();
  1773. }
  1774. /**
  1775. * Render different type sizes and styles.
  1776. */
  1777. public class FilterComboBoxRenderer extends DefaultListCellRenderer {
  1778. public Component getListCellRendererComponent(JList list,
  1779. Object value, int index, boolean isSelected,
  1780. boolean cellHasFocus) {
  1781. super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
  1782. if (value != null && value instanceof FileFilter) {
  1783. setText(((FileFilter)value).getDescription());
  1784. }
  1785. return this;
  1786. }
  1787. }
  1788. //
  1789. // DataModel for Types Comboxbox
  1790. //
  1791. protected FilterComboBoxModel createFilterComboBoxModel() {
  1792. return new FilterComboBoxModel();
  1793. }
  1794. /**
  1795. * Data model for a type-face selection combo-box.
  1796. */
  1797. protected class FilterComboBoxModel extends AbstractListModel implements ComboBoxModel, PropertyChangeListener {
  1798. protected FileFilter[] filters;
  1799. protected FilterComboBoxModel() {
  1800. super();
  1801. filters = getFileChooser().getChoosableFileFilters();
  1802. }
  1803. public void propertyChange(PropertyChangeEvent e) {
  1804. String prop = e.getPropertyName();
  1805. if(prop == JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY) {
  1806. filters = (FileFilter[]) e.getNewValue();
  1807. fireContentsChanged(this, -1, -1);
  1808. } else if (prop == JFileChooser.FILE_FILTER_CHANGED_PROPERTY) {
  1809. fireContentsChanged(this, -1, -1);
  1810. }
  1811. }
  1812. public void setSelectedItem(Object filter) {
  1813. if(filter != null) {
  1814. getFileChooser().setFileFilter((FileFilter) filter);
  1815. setFileName(null);
  1816. fireContentsChanged(this, -1, -1);
  1817. }
  1818. }
  1819. public Object getSelectedItem() {
  1820. // Ensure that the current filter is in the list.
  1821. // NOTE: we shouldnt' have to do this, since JFileChooser adds
  1822. // the filter to the choosable filters list when the filter
  1823. // is set. Lets be paranoid just in case someone overrides
  1824. // setFileFilter in JFileChooser.
  1825. FileFilter currentFilter = getFileChooser().getFileFilter();
  1826. boolean found = false;
  1827. if(currentFilter != null) {
  1828. for(int i=0; i < filters.length; i++) {
  1829. if(filters[i] == currentFilter) {
  1830. found = true;
  1831. }
  1832. }
  1833. if(found == false) {
  1834. getFileChooser().addChoosableFileFilter(currentFilter);
  1835. }
  1836. }
  1837. return getFileChooser().getFileFilter();
  1838. }
  1839. public int getSize() {
  1840. if(filters != null) {
  1841. return filters.length;
  1842. } else {
  1843. return 0;
  1844. }
  1845. }
  1846. public Object getElementAt(int index) {
  1847. if(index > getSize() - 1) {
  1848. // This shouldn't happen. Try to recover gracefully.
  1849. return getFileChooser().getFileFilter();
  1850. }
  1851. if(filters != null) {
  1852. return filters[index];
  1853. } else {
  1854. return null;
  1855. }
  1856. }
  1857. }
  1858. public void valueChanged(ListSelectionEvent e) {
  1859. JFileChooser fc = getFileChooser();
  1860. File f = fc.getSelectedFile();
  1861. if (!e.getValueIsAdjusting() && f != null && !getFileChooser().isTraversable(f)) {
  1862. setFileName(fileNameString(f));
  1863. }
  1864. }
  1865. /**
  1866. * Acts when DirectoryComboBox has changed the selected item.
  1867. */
  1868. protected class DirectoryComboBoxAction implements ActionListener {
  1869. public void actionPerformed(ActionEvent e) {
  1870. File f = (File)directoryComboBox.getSelectedItem();
  1871. getFileChooser().setCurrentDirectory(f);
  1872. }
  1873. }
  1874. protected JButton getApproveButton(JFileChooser fc) {
  1875. return approveButton;
  1876. }
  1877. public FileView getFileView(JFileChooser fc) {
  1878. return fileView;
  1879. }
  1880. // ***********************
  1881. // * FileView operations *
  1882. // ***********************
  1883. protected class WindowsFileView extends BasicFileView {
  1884. /* FileView type descriptions */
  1885. public Icon getIcon(File f) {
  1886. Icon icon = getCachedIcon(f);
  1887. if (icon != null) {
  1888. return icon;
  1889. }
  1890. if (f != null) {
  1891. icon = getFileChooser().getFileSystemView().getSystemIcon(f);
  1892. }
  1893. if (icon == null) {
  1894. icon = super.getIcon(f);
  1895. }
  1896. cacheIcon(f, icon);
  1897. return icon;
  1898. }
  1899. }
  1900. }