1. /*
  2. * @(#)GTKFileChooserUI.java 1.19 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.gtk;
  8. import java.awt.*;
  9. import java.awt.event.*;
  10. import java.beans.*;
  11. import java.io.File;
  12. import java.io.FileNotFoundException;
  13. import java.io.IOException;
  14. import java.text.MessageFormat;
  15. import java.util.*;
  16. import javax.swing.*;
  17. import javax.swing.border.*;
  18. import javax.swing.filechooser.*;
  19. import javax.swing.event.*;
  20. import javax.swing.plaf.*;
  21. import javax.swing.plaf.basic.BasicDirectoryModel;
  22. import javax.swing.table.*;
  23. /**
  24. * GTK FileChooserUI.
  25. *
  26. * @version 1.36 08/21/02
  27. * @author Leif Samuelsson
  28. * @author Jeff Dinkins
  29. */
  30. class GTKFileChooserUI extends SynthFileChooserUI {
  31. // The accessoryPanel is a container to place the JFileChooser accessory component
  32. private JPanel accessoryPanel = null;
  33. private String newFolderButtonText = null;
  34. private String newFolderErrorSeparator = null;
  35. private String newFolderErrorText = null;
  36. private String newFolderDialogText = null;
  37. private String deleteFileButtonText = null;
  38. private String renameFileButtonText = null;
  39. private String newFolderButtonToolTipText = null;
  40. private String deleteFileButtonToolTipText = null;
  41. private String renameFileButtonToolTipText = null;
  42. private int newFolderButtonMnemonic = 0;
  43. private int deleteFileButtonMnemonic = 0;
  44. private int renameFileButtonMnemonic = 0;
  45. private String renameFileDialogText = null;
  46. private String renameFileErrorTitle = null;
  47. private String renameFileErrorText = null;
  48. // From Motif
  49. private JPanel rightPanel;
  50. private JList directoryList;
  51. private JList fileList;
  52. private JLabel pathField;
  53. private JTextField fileNameTextField;
  54. private static final Dimension hstrut10 = new Dimension(10, 1);
  55. private static final Dimension vstrut10 = new Dimension(1, 10);
  56. private static final Insets insets = new Insets(10, 10, 10, 10);
  57. private static Dimension prefListSize = new Dimension(75, 150);
  58. private static Dimension PREF_SIZE = new Dimension(435, 360);
  59. private static Dimension MIN_SIZE = new Dimension(200, 300);
  60. private static Dimension PREF_ACC_SIZE = new Dimension(10, 10);
  61. private static Dimension ZERO_ACC_SIZE = new Dimension(1, 1);
  62. private static Dimension MAX_SIZE = new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
  63. private static final Insets buttonMargin = new Insets(3, 3, 3, 3);
  64. private String filesLabelText = null;
  65. private String foldersLabelText = null;
  66. private String pathLabelText = null;
  67. private int pathLabelMnemonic = 0;
  68. private JComboBox directoryComboBox;
  69. private DirectoryComboBoxModel directoryComboBoxModel;
  70. private Action directoryComboBoxAction = new DirectoryComboBoxAction();
  71. private JPanel bottomButtonPanel;
  72. private GTKDirectoryModel model = null;
  73. private Action newFolderAction;
  74. private boolean readOnly;
  75. private Action approveSelectionAction = new GTKApproveSelectionAction();
  76. public String getFileName() {
  77. JFileChooser fc = getFileChooser();
  78. String typedInName = fileNameTextField != null ?
  79. fileNameTextField.getText() : null;
  80. if (!fc.isMultiSelectionEnabled()) {
  81. return typedInName;
  82. }
  83. int mode = fc.getFileSelectionMode();
  84. JList list = mode == JFileChooser.DIRECTORIES_ONLY ?
  85. directoryList : fileList;
  86. Object[] files = list.getSelectedValues();
  87. int len = files.length;
  88. Vector result = new Vector(len + 1);
  89. // we return all selected file names
  90. for (int i = 0; i < len; i++) {
  91. File file = (File)files[i];
  92. result.add(file.getName());
  93. }
  94. // plus the file name typed into the text field, if not already there
  95. if (typedInName != null && !result.contains(typedInName)) {
  96. result.add(typedInName);
  97. }
  98. StringBuffer buf = new StringBuffer();
  99. len = result.size();
  100. // construct the resulting string
  101. for (int i=0; i<len; i++) {
  102. if (len > 1) {
  103. buf.append(" \"");
  104. }
  105. buf.append(result.get(i));
  106. if (len > 1) {
  107. buf.append("\"");
  108. }
  109. }
  110. return buf.toString();
  111. }
  112. public void setFileName(String fileName) {
  113. if (fileNameTextField != null) {
  114. fileNameTextField.setText(fileName);
  115. }
  116. }
  117. // public String getDirectoryName() {
  118. // return pathField.getText();
  119. // }
  120. public void setDirectoryName(String dirname) {
  121. pathField.setText(dirname);
  122. }
  123. public void ensureFileIsVisible(JFileChooser fc, File f) {
  124. // PENDING
  125. }
  126. public void rescanCurrentDirectory(JFileChooser fc) {
  127. getModel().validateFileCache();
  128. }
  129. protected JPanel getAccessoryPanel() {
  130. return accessoryPanel;
  131. }
  132. private void updateDefaultButton() {
  133. JFileChooser filechooser = getFileChooser();
  134. JRootPane root = SwingUtilities.getRootPane(filechooser);
  135. if (root == null) {
  136. return;
  137. }
  138. if (filechooser.getControlButtonsAreShown()) {
  139. if (root.getDefaultButton() == null) {
  140. root.setDefaultButton(getApproveButton(filechooser));
  141. getCancelButton(filechooser).setDefaultCapable(false);
  142. }
  143. } else {
  144. if (root.getDefaultButton() == getApproveButton(filechooser)) {
  145. root.setDefaultButton(null);
  146. }
  147. }
  148. }
  149. protected void doSelectedFileChanged(PropertyChangeEvent e) {
  150. super.doSelectedFileChanged(e);
  151. File f = (File) e.getNewValue();
  152. if (f != null) {
  153. setFileName(getFileChooser().getName(f));
  154. }
  155. }
  156. protected void doDirectoryChanged(PropertyChangeEvent e) {
  157. directoryList.clearSelection();
  158. fileList.clearSelection();
  159. File currentDirectory = getFileChooser().getCurrentDirectory();
  160. if (currentDirectory != null) {
  161. try {
  162. setDirectoryName(((File)e.getNewValue()).getCanonicalPath());
  163. } catch (IOException ioe) {
  164. setDirectoryName(((File)e.getNewValue()).getAbsolutePath());
  165. }
  166. directoryComboBoxModel.addItem(currentDirectory);
  167. }
  168. super.doDirectoryChanged(e);
  169. }
  170. protected void doAccessoryChanged(PropertyChangeEvent e) {
  171. if (getAccessoryPanel() != null) {
  172. if (e.getOldValue() != null) {
  173. getAccessoryPanel().remove((JComponent)e.getOldValue());
  174. }
  175. JComponent accessory = (JComponent)e.getNewValue();
  176. if (accessory != null) {
  177. getAccessoryPanel().add(accessory, BorderLayout.CENTER);
  178. getAccessoryPanel().setPreferredSize(accessory.getPreferredSize());
  179. getAccessoryPanel().setMaximumSize(MAX_SIZE);
  180. } else {
  181. getAccessoryPanel().setPreferredSize(ZERO_ACC_SIZE);
  182. getAccessoryPanel().setMaximumSize(ZERO_ACC_SIZE);
  183. }
  184. }
  185. }
  186. protected void doFileSelectionModeChanged(PropertyChangeEvent e) {
  187. directoryList.clearSelection();
  188. rightPanel.setVisible(((Integer)e.getNewValue()).intValue() != JFileChooser.DIRECTORIES_ONLY);
  189. super.doFileSelectionModeChanged(e);
  190. }
  191. protected void doMultiSelectionChanged(PropertyChangeEvent e) {
  192. if (getFileChooser().isMultiSelectionEnabled()) {
  193. fileList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
  194. } else {
  195. fileList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
  196. fileList.clearSelection();
  197. }
  198. super.doMultiSelectionChanged(e);
  199. }
  200. protected void doControlButtonsChanged(PropertyChangeEvent e) {
  201. super.doControlButtonsChanged(e);
  202. JFileChooser filechooser = getFileChooser();
  203. if (filechooser.getControlButtonsAreShown()) {
  204. filechooser.add(bottomButtonPanel, BorderLayout.SOUTH);
  205. } else {
  206. filechooser.remove(bottomButtonPanel);
  207. }
  208. updateDefaultButton();
  209. }
  210. protected void doAncestorChanged(PropertyChangeEvent e) {
  211. if (e.getOldValue() == null && e.getNewValue() != null) {
  212. // Ancestor was added, set initial focus
  213. fileNameTextField.selectAll();
  214. fileNameTextField.requestFocus();
  215. updateDefaultButton();
  216. }
  217. super.doAncestorChanged(e);
  218. }
  219. // ********************************************
  220. // ************ Create Listeners **************
  221. // ********************************************
  222. public ListSelectionListener createListSelectionListener(JFileChooser fc) {
  223. return new SelectionListener();
  224. }
  225. class DoubleClickListener extends MouseAdapter {
  226. JList list;
  227. public DoubleClickListener(JList list) {
  228. this.list = list;
  229. }
  230. public void mouseClicked(MouseEvent e) {
  231. if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2) {
  232. int index = list.locationToIndex(e.getPoint());
  233. if (index >= 0) {
  234. File f = (File) list.getModel().getElementAt(index);
  235. try {
  236. // Strip trailing ".."
  237. f = f.getCanonicalFile();
  238. } catch (IOException ex) {
  239. // That's ok, we'll use f as is
  240. }
  241. if (getFileChooser().isTraversable(f)) {
  242. list.clearSelection();
  243. if (getFileChooser().getCurrentDirectory().equals(f)){
  244. rescanCurrentDirectory(getFileChooser());
  245. } else {
  246. getFileChooser().setCurrentDirectory(f);
  247. }
  248. } else {
  249. getFileChooser().approveSelection();
  250. }
  251. }
  252. }
  253. }
  254. }
  255. protected MouseListener createDoubleClickListener(JFileChooser fc, JList list) {
  256. return new DoubleClickListener(list);
  257. }
  258. protected class SelectionListener implements ListSelectionListener {
  259. public void valueChanged(ListSelectionEvent e) {
  260. if (!e.getValueIsAdjusting()) {
  261. JFileChooser chooser = getFileChooser();
  262. JList list = (JList) e.getSource();
  263. if (chooser.isMultiSelectionEnabled()) {
  264. File[] files = null;
  265. Object[] objects = list.getSelectedValues();
  266. if (objects != null) {
  267. if (objects.length == 1
  268. && ((File)objects[0]).isDirectory()
  269. && chooser.isTraversable(((File)objects[0]))
  270. && (chooser.getFileSelectionMode() != chooser.DIRECTORIES_ONLY
  271. || !chooser.getFileSystemView().isFileSystem(((File)objects[0])))) {
  272. setDirectorySelected(true);
  273. setDirectory(((File)objects[0]));
  274. } else {
  275. ArrayList fList = new ArrayList(objects.length);
  276. for (int i = 0; i < objects.length; i++) {
  277. File f = (File)objects[i];
  278. if ((chooser.isFileSelectionEnabled() && f.isFile())
  279. || (chooser.isDirectorySelectionEnabled() && f.isDirectory())) {
  280. fList.add(f);
  281. }
  282. }
  283. if (fList.size() > 0) {
  284. files = (File[])fList.toArray(new File[fList.size()]);
  285. }
  286. setDirectorySelected(false);
  287. }
  288. }
  289. chooser.setSelectedFiles(files);
  290. } else {
  291. File file = (File)list.getSelectedValue();
  292. if (file != null
  293. && file.isDirectory()
  294. && chooser.isTraversable(file)
  295. && (chooser.getFileSelectionMode() != chooser.DIRECTORIES_ONLY
  296. || !chooser.getFileSystemView().isFileSystem(file))) {
  297. setDirectorySelected(true);
  298. setDirectory(file);
  299. } else {
  300. setDirectorySelected(false);
  301. if (file != null) {
  302. chooser.setSelectedFile(file);
  303. }
  304. }
  305. }
  306. }
  307. }
  308. }
  309. //
  310. // ComponentUI Interface Implementation methods
  311. //
  312. public static ComponentUI createUI(JComponent c) {
  313. return new GTKFileChooserUI();
  314. }
  315. public void installUI(JComponent c) {
  316. accessoryPanel = new JPanel(new BorderLayout(10, 10));
  317. accessoryPanel.setName("GTKFileChooser.accessoryPanel");
  318. super.installUI(c);
  319. }
  320. public void uninstallUI(JComponent c) {
  321. super.uninstallUI(c);
  322. if (accessoryPanel != null) {
  323. accessoryPanel.removeAll();
  324. }
  325. accessoryPanel = null;
  326. getFileChooser().removeAll();
  327. }
  328. public void installComponents(JFileChooser fc) {
  329. super.installComponents(fc);
  330. boolean leftToRight = fc.getComponentOrientation().isLeftToRight();
  331. fc.setLayout(new BorderLayout());
  332. fc.setAlignmentX(JComponent.CENTER_ALIGNMENT);
  333. // Top row of buttons
  334. JPanel topButtonPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
  335. topButtonPanel.setBorder(new EmptyBorder(10, 10, 0, 10));
  336. topButtonPanel.setName("GTKFileChooser.topButtonPanel");
  337. JButton newFolderButton = new JButton(getNewFolderAction());
  338. newFolderButton.setName("GTKFileChooser.newFolderButton");
  339. newFolderButton.setMnemonic(newFolderButtonMnemonic);
  340. newFolderButton.setToolTipText(newFolderButtonToolTipText);
  341. newFolderButton.setText(newFolderButtonText);
  342. topButtonPanel.add(newFolderButton);
  343. JButton deleteFileButton = new JButton(deleteFileButtonText);
  344. deleteFileButton.setName("GTKFileChooser.deleteFileButton");
  345. deleteFileButton.setMnemonic(deleteFileButtonMnemonic);
  346. deleteFileButton.setToolTipText(deleteFileButtonToolTipText);
  347. deleteFileButton.setEnabled(false);
  348. topButtonPanel.add(deleteFileButton);
  349. RenameFileAction rfa = new RenameFileAction();
  350. JButton renameFileButton = new JButton(rfa);
  351. renameFileButton.setText(renameFileButtonText);
  352. renameFileButton.setName("GTKFileChooser.renameFileButton");
  353. renameFileButton.setMnemonic(renameFileButtonMnemonic);
  354. renameFileButton.setToolTipText(renameFileButtonToolTipText);
  355. topButtonPanel.add(renameFileButton);
  356. fc.add(topButtonPanel, BorderLayout.NORTH);
  357. JPanel interior = new JPanel();
  358. interior.setBorder(new EmptyBorder(0, 10, 10, 10));
  359. interior.setName("GTKFileChooser.interiorPanel");
  360. align(interior);
  361. interior.setLayout(new BoxLayout(interior, BoxLayout.PAGE_AXIS));
  362. fc.add(interior, BorderLayout.CENTER);
  363. JPanel comboBoxPanel = new JPanel(new FlowLayout(FlowLayout.CENTER,
  364. 0, 0) {
  365. public void layoutContainer(Container target) {
  366. super.layoutContainer(target);
  367. JComboBox comboBox = directoryComboBox;
  368. if (comboBox.getWidth() > target.getWidth()) {
  369. comboBox.setBounds(0, comboBox.getY(), target.getWidth(),
  370. comboBox.getHeight());
  371. }
  372. }
  373. });
  374. comboBoxPanel.setBorder(new EmptyBorder(0, 0, 4, 0));
  375. comboBoxPanel.setName("GTKFileChooser.directoryComboBoxPanel");
  376. // CurrentDir ComboBox
  377. directoryComboBoxModel = createDirectoryComboBoxModel(fc);
  378. directoryComboBox = new JComboBox(directoryComboBoxModel);
  379. directoryComboBox.setName("GTKFileChooser.directoryComboBox");
  380. directoryComboBox.putClientProperty( "JComboBox.lightweightKeyboardNavigation", "Lightweight" );
  381. directoryComboBox.addActionListener(directoryComboBoxAction);
  382. directoryComboBox.setRenderer(createDirectoryComboBoxRenderer(fc));
  383. directoryComboBox.setMaximumRowCount(8);
  384. comboBoxPanel.add(directoryComboBox);
  385. interior.add(comboBoxPanel);
  386. // interior.add(Box.createRigidArea(vstrut10));
  387. // CENTER: left, right, accessory
  388. JPanel centerPanel = new JPanel(new BorderLayout());
  389. centerPanel.setName("GTKFileChooser.centerPanel");
  390. // SPLIT PANEL: left, right
  391. JSplitPane splitPanel = new JSplitPane();
  392. splitPanel.setName("GTKFileChooser.splitPanel");
  393. splitPanel.setDividerLocation((PREF_SIZE.width-8)/2);
  394. // left panel - Filter & directoryList
  395. JPanel leftPanel = new JPanel(new GridBagLayout());
  396. leftPanel.setName("GTKFileChooser.directoryListPanel");
  397. // Add the Directory List
  398. // Create a label that looks like button (should be a table header)
  399. TableCellRenderer headerRenderer = new JTableHeader().getDefaultRenderer();
  400. JComponent directoryListLabel =
  401. (JComponent)headerRenderer.getTableCellRendererComponent(null, foldersLabelText,
  402. false, false, 0, 0);
  403. directoryListLabel.setName("GTKFileChooser.directoryListLabel");
  404. leftPanel.add(directoryListLabel, new GridBagConstraints(
  405. 0, 0, 1, 1, 1, 0, GridBagConstraints.WEST,
  406. GridBagConstraints.HORIZONTAL,
  407. SynthLookAndFeel.EMPTY_UIRESOURCE_INSETS, 0, 0));
  408. leftPanel.add(createDirectoryList(), new GridBagConstraints(
  409. 0, 1, 1, 1, 1, 1, GridBagConstraints.EAST,
  410. GridBagConstraints.BOTH,
  411. SynthLookAndFeel.EMPTY_UIRESOURCE_INSETS, 0, 0));
  412. // create files list
  413. rightPanel = new JPanel(new GridBagLayout());
  414. rightPanel.setName("GTKFileChooser.fileListPanel");
  415. headerRenderer = new JTableHeader().getDefaultRenderer();
  416. JComponent fileListLabel =
  417. (JComponent)headerRenderer.getTableCellRendererComponent(null, filesLabelText,
  418. false, false, 0, 0);
  419. fileListLabel.setName("GTKFileChooser.fileListLabel");
  420. rightPanel.add(fileListLabel, new GridBagConstraints(
  421. 0, 0, 1, 1, 1, 0, GridBagConstraints.WEST,
  422. GridBagConstraints.HORIZONTAL,
  423. SynthLookAndFeel.EMPTY_UIRESOURCE_INSETS,
  424. 0, 0));
  425. rightPanel.add(createFilesList(), new GridBagConstraints(
  426. 0, 1, 1, 1, 1, 1, GridBagConstraints.EAST,
  427. GridBagConstraints.BOTH,
  428. SynthLookAndFeel.EMPTY_UIRESOURCE_INSETS, 0, 0));
  429. splitPanel.add(leftPanel, leftToRight ? JSplitPane.LEFT : JSplitPane.RIGHT);
  430. splitPanel.add(rightPanel, leftToRight ? JSplitPane.RIGHT : JSplitPane.LEFT);
  431. centerPanel.add(splitPanel, BorderLayout.CENTER);
  432. JComponent accessoryPanel = getAccessoryPanel();
  433. JComponent accessory = fc.getAccessory();
  434. if (accessoryPanel != null) {
  435. if (accessory == null) {
  436. accessoryPanel.setPreferredSize(ZERO_ACC_SIZE);
  437. accessoryPanel.setMaximumSize(ZERO_ACC_SIZE);
  438. } else {
  439. getAccessoryPanel().add(accessory, BorderLayout.CENTER);
  440. accessoryPanel.setPreferredSize(accessory.getPreferredSize());
  441. accessoryPanel.setMaximumSize(MAX_SIZE);
  442. }
  443. align(accessoryPanel);
  444. centerPanel.add(accessoryPanel, BorderLayout.AFTER_LINE_ENDS);
  445. }
  446. interior.add(centerPanel);
  447. interior.add(Box.createRigidArea(vstrut10));
  448. JPanel pathFieldPanel = new JPanel(new FlowLayout(FlowLayout.LEADING,
  449. 0, 0));
  450. pathFieldPanel.setBorder(new EmptyBorder(0, 0, 4, 0));
  451. JLabel pathFieldLabel = new JLabel(pathLabelText);
  452. pathFieldLabel.setName("GTKFileChooser.pathFieldLabel");
  453. pathFieldLabel.setDisplayedMnemonic(pathLabelMnemonic);
  454. align(pathFieldLabel);
  455. pathFieldPanel.add(pathFieldLabel);
  456. File currentDirectory = fc.getCurrentDirectory();
  457. String curDirName = null;
  458. if (currentDirectory != null) {
  459. curDirName = currentDirectory.getPath();
  460. }
  461. pathField = new JLabel(curDirName) {
  462. public Dimension getMaximumSize() {
  463. Dimension d = super.getMaximumSize();
  464. d.height = getPreferredSize().height;
  465. return d;
  466. }
  467. };
  468. pathField.setName("GTKFileChooser.pathField");
  469. pathFieldLabel.setLabelFor(pathField);
  470. align(pathField);
  471. pathFieldPanel.add(pathField);
  472. interior.add(pathFieldPanel);
  473. // add the fileName field
  474. fileNameTextField = new JTextField() {
  475. public Dimension getMaximumSize() {
  476. Dimension d = super.getMaximumSize();
  477. d.height = getPreferredSize().height;
  478. return d;
  479. }
  480. };
  481. Set forwardTraversalKeys = fileNameTextField.getFocusTraversalKeys(
  482. KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
  483. forwardTraversalKeys = new HashSet(forwardTraversalKeys);
  484. forwardTraversalKeys.remove(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
  485. fileNameTextField.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forwardTraversalKeys);
  486. fileNameTextField.setName("GTKFileChooser.fileNameTextField");
  487. fileNameTextField.getActionMap().put("fileNameCompletionAction", getFileNameCompletionAction());
  488. fileNameTextField.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), "fileNameCompletionAction");
  489. interior.add(fileNameTextField);
  490. // Add buttons
  491. bottomButtonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
  492. bottomButtonPanel.setName("GTKFileChooser.bottomButtonPanel");
  493. align(bottomButtonPanel);
  494. JButton cancelButton = getCancelButton(fc);
  495. align(cancelButton);
  496. cancelButton.setMargin(buttonMargin);
  497. bottomButtonPanel.add(cancelButton);
  498. JButton approveButton = getApproveButton(fc);;
  499. align(approveButton);
  500. approveButton.setMargin(buttonMargin);
  501. bottomButtonPanel.add(approveButton);
  502. fc.add(bottomButtonPanel, BorderLayout.SOUTH);
  503. }
  504. protected void installDefaults(JFileChooser jFileChooser) {
  505. super.installDefaults(jFileChooser);
  506. readOnly = UIManager.getBoolean("FileChooser.readOnly");
  507. }
  508. protected void installStrings(JFileChooser fc) {
  509. super.installStrings(fc);
  510. Locale l = fc.getLocale();
  511. newFolderDialogText = UIManager.getString("FileChooser.newFolderDialogText", l);
  512. newFolderErrorText = UIManager.getString("FileChooser.newFolderErrorText",l);
  513. newFolderErrorSeparator = UIManager.getString("FileChooser.newFolderErrorSeparator",l);
  514. newFolderButtonText = UIManager.getString("FileChooser.newFolderButtonText", l);
  515. deleteFileButtonText = UIManager.getString("FileChooser.deleteFileButtonText", l);
  516. renameFileButtonText = UIManager.getString("FileChooser.renameFileButtonText", l);
  517. newFolderButtonMnemonic = UIManager.getInt("FileChooser.newFolderButtonMnemonic", l);
  518. deleteFileButtonMnemonic = UIManager.getInt("FileChooser.deleteFileButtonMnemonic", l);
  519. renameFileButtonMnemonic = UIManager.getInt("FileChooser.renameFileButtonMnemonic", l);
  520. newFolderButtonToolTipText = UIManager.getString("FileChooser.newFolderButtonToolTipText", l);
  521. deleteFileButtonToolTipText = UIManager.getString("FileChooser.deleteFileButtonToolTipText", l);
  522. renameFileButtonToolTipText = UIManager.getString("FileChooser.renameFileButtonToolTipText", l);
  523. renameFileDialogText = UIManager.getString("FileChooser.renameFileDialogText", l);
  524. renameFileErrorTitle = UIManager.getString("FileChooser.renameFileErrorTitle", l);
  525. renameFileErrorText = UIManager.getString("FileChooser.renameFileErrorText", l);
  526. foldersLabelText = UIManager.getString("FileChooser.foldersLabelText",l);
  527. filesLabelText = UIManager.getString("FileChooser.filesLabelText",l);
  528. pathLabelText = UIManager.getString("FileChooser.pathLabelText",l);
  529. pathLabelMnemonic = UIManager.getInt("FileChooser.pathLabelMnemonic");
  530. }
  531. protected void uninstallStrings(JFileChooser fc) {
  532. super.uninstallStrings(fc);
  533. newFolderButtonText = null;
  534. deleteFileButtonText = null;
  535. renameFileButtonText = null;
  536. newFolderButtonToolTipText = null;
  537. deleteFileButtonToolTipText = null;
  538. renameFileButtonToolTipText = null;
  539. renameFileDialogText = null;
  540. renameFileErrorTitle = null;
  541. renameFileErrorText = null;
  542. foldersLabelText = null;
  543. filesLabelText = null;
  544. pathLabelText = null;
  545. }
  546. protected JScrollPane createFilesList() {
  547. fileList = new JList();
  548. fileList.setName("GTKFileChooser.fileList");
  549. if (getFileChooser().isMultiSelectionEnabled()) {
  550. fileList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
  551. } else {
  552. fileList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
  553. }
  554. fileList.setModel(new GTKFileListModel());
  555. fileList.setCellRenderer(new FileCellRenderer());
  556. fileList.addListSelectionListener(createListSelectionListener(getFileChooser()));
  557. fileList.addMouseListener(createDoubleClickListener(getFileChooser(), fileList));
  558. align(fileList);
  559. JScrollPane scrollpane = new JScrollPane(fileList);
  560. scrollpane.setName("GTKFileChooser.fileListScrollPane");
  561. scrollpane.setPreferredSize(prefListSize);
  562. scrollpane.setMaximumSize(MAX_SIZE);
  563. align(scrollpane);
  564. return scrollpane;
  565. }
  566. protected JScrollPane createDirectoryList() {
  567. directoryList = new JList();
  568. directoryList.setName("GTKFileChooser.directoryList");
  569. align(directoryList);
  570. directoryList.setCellRenderer(new DirectoryCellRenderer());
  571. directoryList.setModel(new GTKDirectoryListModel());
  572. directoryList.addMouseListener(createDoubleClickListener(getFileChooser(), directoryList));
  573. directoryList.addListSelectionListener(createListSelectionListener(getFileChooser()));
  574. JScrollPane scrollpane = new JScrollPane(directoryList);
  575. scrollpane.setName("GTKFileChooser.directoryListScrollPane");
  576. scrollpane.setMaximumSize(MAX_SIZE);
  577. scrollpane.setPreferredSize(prefListSize);
  578. align(scrollpane);
  579. return scrollpane;
  580. }
  581. protected void createModel() {
  582. model = new GTKDirectoryModel();
  583. }
  584. public BasicDirectoryModel getModel() {
  585. return model;
  586. }
  587. public Action getApproveSelectionAction() {
  588. return approveSelectionAction;
  589. }
  590. private class GTKDirectoryModel extends BasicDirectoryModel {
  591. FileSystemView fsv;
  592. private Comparator fileComparator = new Comparator() {
  593. public int compare(Object o, Object o1) {
  594. return fsv.getSystemDisplayName((File) o).compareTo
  595. (fsv.getSystemDisplayName((File) o1));
  596. }
  597. };
  598. public GTKDirectoryModel() {
  599. super(getFileChooser());
  600. }
  601. protected void sort(Vector v) {
  602. fsv = getFileChooser().getFileSystemView();
  603. Collections.sort(v, fileComparator);
  604. }
  605. }
  606. protected class GTKDirectoryListModel extends AbstractListModel implements ListDataListener {
  607. File curDir;
  608. public GTKDirectoryListModel() {
  609. getModel().addListDataListener(this);
  610. }
  611. public int getSize() {
  612. return getModel().getDirectories().size() + 1;
  613. }
  614. public Object getElementAt(int index) {
  615. return index > 0 ? getModel().getDirectories().elementAt(index - 1):
  616. curDir;
  617. }
  618. public void intervalAdded(ListDataEvent e) {
  619. fireContentsChanged();
  620. }
  621. // PENDING - implement
  622. public void intervalRemoved(ListDataEvent e) {
  623. fireContentsChanged();
  624. }
  625. // PENDING - this is inefficient - should sent out
  626. // incremental adjustment values instead of saying that the
  627. // whole list has changed.
  628. public void fireContentsChanged() {
  629. curDir = getFileChooser().getFileSystemView().createFileObject(
  630. getFileChooser().getCurrentDirectory(), ".");
  631. fireContentsChanged(this, 0, getModel().getDirectories().size()-1);
  632. }
  633. // PENDING - fire the correct interval changed - currently sending
  634. // out that everything has changed
  635. public void contentsChanged(ListDataEvent e) {
  636. fireContentsChanged();
  637. }
  638. }
  639. protected class GTKFileListModel extends AbstractListModel implements ListDataListener {
  640. public GTKFileListModel() {
  641. getModel().addListDataListener(this);
  642. }
  643. public int getSize() {
  644. return getModel().getFiles().size();
  645. }
  646. public boolean contains(Object o) {
  647. return getModel().getFiles().contains(o);
  648. }
  649. public int indexOf(Object o) {
  650. return getModel().getFiles().indexOf(o);
  651. }
  652. public Object getElementAt(int index) {
  653. return getModel().getFiles().elementAt(index);
  654. }
  655. public void intervalAdded(ListDataEvent e) {
  656. fireContentsChanged();
  657. }
  658. public void intervalRemoved(ListDataEvent e) {
  659. fireContentsChanged();
  660. }
  661. // PENDING - this is inefficient - should sent out
  662. // incremental adjustment values instead of saying that the
  663. // whole list has changed.
  664. public void fireContentsChanged() {
  665. fireContentsChanged(this, 0, getModel().getFiles().size()-1);
  666. }
  667. // PENDING - fire the interval changed
  668. public void contentsChanged(ListDataEvent e) {
  669. fireContentsChanged();
  670. }
  671. }
  672. protected class FileCellRenderer extends DefaultListCellRenderer {
  673. public Component getListCellRendererComponent(JList list, Object value, int index,
  674. boolean isSelected, boolean cellHasFocus) {
  675. super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
  676. setText(getFileChooser().getName((File) value));
  677. return this;
  678. }
  679. public boolean isOpaque() {
  680. Color back = getBackground();
  681. Component p = getParent();
  682. if (p != null) {
  683. p = p.getParent();
  684. }
  685. // p should now be the JList.
  686. boolean colorMatch = (back != null) && (p != null) &&
  687. back.equals(p.getBackground()) &&
  688. p.isOpaque();
  689. return !colorMatch && super.isOpaque();
  690. }
  691. }
  692. protected class DirectoryCellRenderer extends DefaultListCellRenderer {
  693. public Component getListCellRendererComponent(JList list, Object value, int index,
  694. boolean isSelected, boolean cellHasFocus) {
  695. super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
  696. setText(getFileChooser().getName((File) value) + "/");
  697. return this;
  698. }
  699. public boolean isOpaque() {
  700. Color back = getBackground();
  701. Component p = getParent();
  702. if (p != null) {
  703. p = p.getParent();
  704. }
  705. // p should now be the JList.
  706. boolean colorMatch = (back != null) && (p != null) &&
  707. back.equals(p.getBackground()) &&
  708. p.isOpaque();
  709. return !colorMatch && super.isOpaque();
  710. }
  711. }
  712. public Dimension getPreferredSize(JComponent c) {
  713. Dimension prefSize = new Dimension(PREF_SIZE);
  714. JComponent accessory = getFileChooser().getAccessory();
  715. if (accessory != null) {
  716. prefSize.width += accessory.getPreferredSize().width + 20;
  717. }
  718. Dimension d = c.getLayout().preferredLayoutSize(c);
  719. if (d != null) {
  720. return new Dimension(d.width < prefSize.width ? prefSize.width : d.width,
  721. d.height < prefSize.height ? prefSize.height : d.height);
  722. } else {
  723. return prefSize;
  724. }
  725. }
  726. public Dimension getMinimumSize(JComponent x) {
  727. return new Dimension(MIN_SIZE);
  728. }
  729. public Dimension getMaximumSize(JComponent x) {
  730. return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
  731. }
  732. protected void align(JComponent c) {
  733. c.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  734. c.setAlignmentY(JComponent.TOP_ALIGNMENT);
  735. }
  736. protected DirectoryComboBoxRenderer createDirectoryComboBoxRenderer(JFileChooser fc) {
  737. return new DirectoryComboBoxRenderer();
  738. }
  739. public Action getNewFolderAction() {
  740. if (newFolderAction == null) {
  741. newFolderAction = new NewFolderAction();
  742. newFolderAction.setEnabled(!readOnly);
  743. }
  744. return newFolderAction;
  745. }
  746. //
  747. // Renderer for DirectoryComboBox
  748. //
  749. class DirectoryComboBoxRenderer extends SynthComboBoxUI.SynthComboBoxRenderer {
  750. public Component getListCellRendererComponent(JList list, Object value,
  751. int index, boolean isSelected,
  752. boolean cellHasFocus) {
  753. super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
  754. if (value == null) {
  755. setText("");
  756. return this;
  757. }
  758. setText(((File)value).getAbsolutePath());
  759. return this;
  760. }
  761. }
  762. //
  763. // DataModel for DirectoryComboxbox
  764. //
  765. protected DirectoryComboBoxModel createDirectoryComboBoxModel(JFileChooser fc) {
  766. return new DirectoryComboBoxModel();
  767. }
  768. /**
  769. * Data model for a type-face selection combo-box.
  770. */
  771. protected class DirectoryComboBoxModel extends AbstractListModel implements ComboBoxModel {
  772. Vector directories = new Vector();
  773. File selectedDirectory = null;
  774. JFileChooser chooser = getFileChooser();
  775. FileSystemView fsv = chooser.getFileSystemView();
  776. public DirectoryComboBoxModel() {
  777. // Add the current directory to the model, and make it the
  778. // selectedDirectory
  779. File dir = getFileChooser().getCurrentDirectory();
  780. if (dir != null) {
  781. addItem(dir);
  782. }
  783. }
  784. /**
  785. * Adds the directory to the model and sets it to be selected,
  786. * additionally clears out the previous selected directory and
  787. * the paths leading up to it, if any.
  788. */
  789. private void addItem(File directory) {
  790. if (directory == null) {
  791. return;
  792. }
  793. int oldSize = directories.size();
  794. directories.clear();
  795. if (oldSize > 0) {
  796. fireIntervalRemoved(this, 0, oldSize);
  797. }
  798. // Get the canonical (full) path. This has the side
  799. // benefit of removing extraneous chars from the path,
  800. // for example /foo/bar/ becomes /foo/bar
  801. File canonical = null;
  802. try {
  803. canonical = fsv.createFileObject(directory.getCanonicalPath());
  804. } catch (IOException e) {
  805. // Maybe drive is not ready. Can't abort here.
  806. canonical = directory;
  807. }
  808. // create File instances of each directory leading up to the top
  809. File f = canonical;
  810. do {
  811. directories.add(f);
  812. } while ((f = f.getParentFile()) != null);
  813. int newSize = directories.size();
  814. if (newSize > 0) {
  815. fireIntervalAdded(this, 0, newSize);
  816. }
  817. setSelectedItem(canonical);
  818. }
  819. public void setSelectedItem(Object selectedDirectory) {
  820. this.selectedDirectory = (File)selectedDirectory;
  821. fireContentsChanged(this, -1, -1);
  822. }
  823. public Object getSelectedItem() {
  824. return selectedDirectory;
  825. }
  826. public int getSize() {
  827. return directories.size();
  828. }
  829. public Object getElementAt(int index) {
  830. return directories.elementAt(index);
  831. }
  832. }
  833. /**
  834. * Acts when DirectoryComboBox has changed the selected item.
  835. */
  836. protected class DirectoryComboBoxAction extends AbstractAction {
  837. protected DirectoryComboBoxAction() {
  838. super("DirectoryComboBoxAction");
  839. }
  840. public void actionPerformed(ActionEvent e) {
  841. File f = (File)directoryComboBox.getSelectedItem();
  842. getFileChooser().setCurrentDirectory(f);
  843. }
  844. }
  845. /**
  846. * Creates a new folder.
  847. */
  848. private class NewFolderAction extends AbstractAction {
  849. protected NewFolderAction() {
  850. super("New Folder");
  851. }
  852. public void actionPerformed(ActionEvent e) {
  853. if (readOnly) {
  854. return;
  855. }
  856. JFileChooser fc = getFileChooser();
  857. File currentDirectory = fc.getCurrentDirectory();
  858. String dirName = (String) JOptionPane.showInputDialog(fc,
  859. newFolderDialogText, newFolderButtonText,
  860. JOptionPane.PLAIN_MESSAGE);
  861. if (dirName != null) {
  862. File newDir = fc.getFileSystemView().createFileObject
  863. (currentDirectory, dirName);
  864. if (newDir == null || !newDir.mkdir()) {
  865. JOptionPane.showMessageDialog(fc,
  866. newFolderErrorText + newFolderErrorSeparator + " \"" +
  867. dirName + "\"",
  868. newFolderErrorText, JOptionPane.ERROR_MESSAGE);
  869. }
  870. fc.rescanCurrentDirectory();
  871. }
  872. }
  873. }
  874. private class GTKApproveSelectionAction extends ApproveSelectionAction {
  875. public void actionPerformed(ActionEvent e) {
  876. if (isDirectorySelected()) {
  877. File dir = getDirectory();
  878. try {
  879. if (dir != null) {
  880. dir = dir.getCanonicalFile();
  881. }
  882. // Strip trailing ".."
  883. } catch (IOException ex) {
  884. // Ok, use f as is
  885. }
  886. if (getFileChooser().getCurrentDirectory().equals(dir)) {
  887. directoryList.clearSelection();
  888. rescanCurrentDirectory(getFileChooser());
  889. return;
  890. }
  891. }
  892. super.actionPerformed(e);
  893. }
  894. }
  895. /**
  896. * Renames file
  897. */
  898. private class RenameFileAction extends AbstractAction {
  899. protected RenameFileAction() {
  900. super("editFileName");
  901. }
  902. public void actionPerformed(ActionEvent e) {
  903. if (getFileName().equals("") || readOnly) {
  904. return;
  905. }
  906. JFileChooser fc = getFileChooser();
  907. File currentDirectory = fc.getCurrentDirectory();
  908. String newFileName = (String) JOptionPane.showInputDialog
  909. (fc, new MessageFormat(renameFileDialogText).format
  910. (new Object[] { getFileName() }),
  911. renameFileButtonText, JOptionPane.PLAIN_MESSAGE, null, null,
  912. getFileName());
  913. if (newFileName != null) {
  914. File oldFile = fc.getFileSystemView().createFileObject
  915. (currentDirectory, getFileName());
  916. File newFile = fc.getFileSystemView().createFileObject
  917. (currentDirectory, newFileName);
  918. if (oldFile == null || newFile == null ||
  919. !getModel().renameFile(oldFile, newFile)) {
  920. JOptionPane.showMessageDialog(fc,
  921. new MessageFormat(renameFileErrorText).
  922. format(new Object[] { getFileName(), newFileName}),
  923. renameFileErrorTitle, JOptionPane.ERROR_MESSAGE);
  924. } else {
  925. setFileName(getFileChooser().getName(newFile));
  926. fc.rescanCurrentDirectory();
  927. }
  928. }
  929. }
  930. }
  931. }