1. /*
  2. * @(#)MotifFileChooserUI.java 1.20 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.java.swing.plaf.motif;
  8. import javax.swing.*;
  9. import javax.swing.filechooser.*;
  10. import javax.swing.event.*;
  11. import javax.swing.plaf.*;
  12. import javax.swing.plaf.basic.*;
  13. import java.awt.*;
  14. import java.awt.event.*;
  15. import java.beans.*;
  16. import java.io.File;
  17. import java.io.IOException;
  18. import java.util.*;
  19. /**
  20. * Motif FileChooserUI.
  21. *
  22. * @version 1.20 11/29/01
  23. * @author Jeff Dinkins
  24. */
  25. public class MotifFileChooserUI extends BasicFileChooserUI {
  26. private FilterComboBoxModel filterComboBoxModel;
  27. protected JList directoryList = null;
  28. protected JList fileList = null;
  29. protected JTextField pathField = null;
  30. protected JComboBox filterComboBox = null;
  31. protected JTextField filenameTextField = null;
  32. private static final Dimension hstrut10 = new Dimension(10, 1);
  33. private static final Dimension vstrut10 = new Dimension(1, 10);
  34. private static final Insets insets = new Insets(10, 10, 10, 10);
  35. private static Dimension prefListSize = new Dimension(75, 150);
  36. private static Dimension WITH_ACCELERATOR_PREF_SIZE = new Dimension(650, 450);
  37. private static Dimension PREF_SIZE = new Dimension(350, 450);
  38. private static Dimension MIN_SIZE = new Dimension(200, 300);
  39. private static Dimension PREF_ACC_SIZE = new Dimension(10, 10);
  40. private static Dimension ZERO_ACC_SIZE = new Dimension(1, 1);
  41. private static Dimension MAX_SIZE = new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
  42. private static final Insets buttonMargin = new Insets(3, 3, 3, 3);
  43. private JPanel directoryPanel = new JPanel();
  44. protected JButton approveButton;
  45. private String enterFileNameLabelText = null;
  46. private int enterFileNameLabelMnemonic = 0;
  47. private String filesLabelText = null;
  48. private int filesLabelMnemonic = 0;
  49. private String foldersLabelText = null;
  50. private int foldersLabelMnemonic = 0;
  51. private String pathLabelText = null;
  52. private int pathLabelMnemonic = 0;
  53. private String filterLabelText = null;
  54. private int filterLabelMnemonic = 0;
  55. public MotifFileChooserUI(JFileChooser filechooser) {
  56. super(filechooser);
  57. }
  58. public String getFileName() {
  59. if(filenameTextField != null) {
  60. return filenameTextField.getText();
  61. } else {
  62. return null;
  63. }
  64. }
  65. public void setFileName(String filename) {
  66. if(filenameTextField != null) {
  67. filenameTextField.setText(filename);
  68. }
  69. }
  70. public String getDirectoryName() {
  71. return pathField.getText();
  72. }
  73. public void setDirectoryName(String dirname) {
  74. pathField.setText(dirname);
  75. }
  76. public void ensureFileIsVisible(JFileChooser fc, File f) {
  77. // PENDING(jeff)
  78. }
  79. public void rescanCurrentDirectory(JFileChooser fc) {
  80. // PENDING(jeff)
  81. }
  82. public PropertyChangeListener createPropertyChangeListener(JFileChooser fc) {
  83. return new PropertyChangeListener() {
  84. public void propertyChange(PropertyChangeEvent e) {
  85. String prop = e.getPropertyName();
  86. if(prop.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) {
  87. File f = (File) e.getNewValue();
  88. if(f != null) {
  89. setFileName(getFileChooser().getName(f));
  90. /*
  91. if(model.contains(f)) {
  92. list.setSelectedIndex(model.indexOf(e.getNewValue()));
  93. list.ensureIndexIsVisible(list.getSelectedIndex());
  94. }
  95. */
  96. }
  97. } else if(prop.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)) {
  98. directoryList.clearSelection();
  99. File currentDirectory = getFileChooser().getCurrentDirectory();
  100. if(currentDirectory != null) {
  101. try {
  102. setDirectoryName(((File)e.getNewValue()).getCanonicalPath());
  103. } catch (IOException ioe) {
  104. setDirectoryName(((File)e.getNewValue()).getAbsolutePath());
  105. }
  106. }
  107. } else if(prop.equals(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY)) {
  108. directoryList.clearSelection();
  109. } else if(prop == JFileChooser.ACCESSORY_CHANGED_PROPERTY) {
  110. if(getAccessoryPanel() != null) {
  111. if(e.getOldValue() != null) {
  112. getAccessoryPanel().remove((JComponent) e.getOldValue());
  113. }
  114. JComponent accessory = (JComponent) e.getNewValue();
  115. if(accessory != null) {
  116. getAccessoryPanel().add(accessory, BorderLayout.CENTER);
  117. getAccessoryPanel().setPreferredSize(PREF_ACC_SIZE);
  118. getAccessoryPanel().setMaximumSize(MAX_SIZE);
  119. } else {
  120. getAccessoryPanel().setPreferredSize(ZERO_ACC_SIZE);
  121. getAccessoryPanel().setMaximumSize(ZERO_ACC_SIZE);
  122. }
  123. }
  124. } else if(prop == JFileChooser.APPROVE_BUTTON_TEXT_CHANGED_PROPERTY ||
  125. prop == JFileChooser.DIALOG_TYPE_CHANGED_PROPERTY) {
  126. approveButton.setText(getApproveButtonText(getFileChooser()));
  127. approveButton.setToolTipText(getApproveButtonToolTipText(getFileChooser()));
  128. }
  129. }
  130. };
  131. }
  132. //
  133. // ComponentUI Interface Implementation methods
  134. //
  135. public static ComponentUI createUI(JComponent c) {
  136. return new MotifFileChooserUI((JFileChooser)c);
  137. }
  138. public void installUI(JComponent c) {
  139. super.installUI(c);
  140. }
  141. public void uninstallUI(JComponent c) {
  142. getFileChooser().removeAll();
  143. super.uninstallUI(c);
  144. }
  145. public void installComponents(JFileChooser fc) {
  146. fc.setLayout(new BoxLayout(fc, BoxLayout.Y_AXIS));
  147. fc.add(Box.createRigidArea(vstrut10));
  148. JPanel interior = new JPanel() {
  149. public Insets getInsets() {
  150. return insets;
  151. }
  152. };
  153. align(interior);
  154. interior.setLayout(new BoxLayout(interior, BoxLayout.Y_AXIS));
  155. fc.add(interior);
  156. // PENDING(jeff) - I18N
  157. JLabel l = new JLabel(pathLabelText);
  158. l.setDisplayedMnemonic(pathLabelMnemonic);
  159. align(l);
  160. interior.add(l);
  161. File currentDirectory = fc.getCurrentDirectory();
  162. String curDirName = null;
  163. if(currentDirectory != null) {
  164. curDirName = currentDirectory.getPath();
  165. }
  166. pathField = new JTextField(curDirName);
  167. l.setLabelFor(pathField);
  168. align(pathField);
  169. // Change to folder on return
  170. pathField.addActionListener(getUpdateAction());
  171. interior.add(pathField);
  172. interior.add(Box.createRigidArea(vstrut10));
  173. // CENTER: left, right accessory
  174. JPanel centerPanel = new JPanel();
  175. centerPanel.setPreferredSize(MAX_SIZE);
  176. centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.X_AXIS));
  177. align(centerPanel);
  178. // left panel - Filter & folderList
  179. JPanel leftPanel = new JPanel();
  180. leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.Y_AXIS));
  181. align(leftPanel);
  182. // add the filter PENDING(jeff) - I18N
  183. l = new JLabel(filterLabelText);
  184. l.setDisplayedMnemonic(filterLabelMnemonic);
  185. align(l);
  186. leftPanel.add(l);
  187. filterComboBox = new JComboBox();
  188. l.setLabelFor(filterComboBox);
  189. filterComboBoxModel = createFilterComboBoxModel();
  190. filterComboBox.setModel(filterComboBoxModel);
  191. filterComboBox.setRenderer(createFilterComboBoxRenderer());
  192. fc.addPropertyChangeListener(filterComboBoxModel);
  193. align(filterComboBox);
  194. leftPanel.add(filterComboBox);
  195. // leftPanel.add(Box.createRigidArea(vstrut10));
  196. // Add the Folder List PENDING(jeff) - I18N
  197. l = new JLabel(foldersLabelText);
  198. l.setDisplayedMnemonic(foldersLabelMnemonic);
  199. align(l);
  200. leftPanel.add(l);
  201. JScrollPane sp = createDirectoryList();
  202. l.setLabelFor(sp);
  203. leftPanel.add(sp);
  204. // create files list
  205. JPanel rightPanel = new JPanel();
  206. align(rightPanel);
  207. rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.Y_AXIS));
  208. l = new JLabel(filesLabelText);
  209. l.setDisplayedMnemonic(filesLabelMnemonic);
  210. align(l);
  211. rightPanel.add(l);
  212. sp = createFilesList();
  213. l.setLabelFor(sp);
  214. rightPanel.add(sp);
  215. centerPanel.add(leftPanel);
  216. centerPanel.add(Box.createRigidArea(hstrut10));
  217. centerPanel.add(rightPanel);
  218. JComponent accessoryPanel = getAccessoryPanel();
  219. JComponent accessory = fc.getAccessory();
  220. if(accessoryPanel != null) {
  221. if(accessory == null) {
  222. accessoryPanel.setPreferredSize(ZERO_ACC_SIZE);
  223. accessoryPanel.setMaximumSize(ZERO_ACC_SIZE);
  224. } else {
  225. getAccessoryPanel().add(accessory, BorderLayout.CENTER);
  226. accessoryPanel.setPreferredSize(PREF_ACC_SIZE);
  227. accessoryPanel.setMaximumSize(MAX_SIZE);
  228. }
  229. align(accessoryPanel);
  230. centerPanel.add(accessoryPanel);
  231. }
  232. interior.add(centerPanel);
  233. interior.add(Box.createRigidArea(vstrut10));
  234. // add the filename field PENDING(jeff) - I18N
  235. l = new JLabel(enterFileNameLabelText);
  236. l.setDisplayedMnemonic(enterFileNameLabelMnemonic);
  237. align(l);
  238. interior.add(l);
  239. filenameTextField = new JTextField();
  240. l.setLabelFor(filenameTextField);
  241. filenameTextField.addActionListener(getApproveSelectionAction());
  242. align(filenameTextField);
  243. filenameTextField.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  244. interior.add(filenameTextField);
  245. interior.add(Box.createRigidArea(vstrut10));
  246. fc.add(new JSeparator());
  247. fc.add(Box.createRigidArea(vstrut10));
  248. // Add buttons
  249. JPanel buttonPanel = new JPanel();
  250. align(buttonPanel);
  251. buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.X_AXIS));
  252. buttonPanel.add(Box.createGlue());
  253. approveButton = new JButton(getApproveButtonText(fc)) {
  254. public Dimension getMaximumSize() {
  255. return new Dimension(MAX_SIZE.width, this.getPreferredSize().height);
  256. }
  257. };
  258. approveButton.setMnemonic(getApproveButtonMnemonic(fc));
  259. approveButton.setToolTipText(getApproveButtonToolTipText(fc));
  260. align(approveButton);
  261. approveButton.setMargin(buttonMargin);
  262. approveButton.addActionListener(getApproveSelectionAction());
  263. buttonPanel.add(approveButton);
  264. buttonPanel.add(Box.createGlue());
  265. JButton updateButton = new JButton(updateButtonText) {
  266. public Dimension getMaximumSize() {
  267. return new Dimension(MAX_SIZE.width, this.getPreferredSize().height);
  268. }
  269. };
  270. updateButton.setMnemonic(updateButtonMnemonic);
  271. updateButton.setToolTipText(updateButtonToolTipText);
  272. align(updateButton);
  273. updateButton.setMargin(buttonMargin);
  274. updateButton.addActionListener(getUpdateAction());
  275. buttonPanel.add(updateButton);
  276. buttonPanel.add(Box.createGlue());
  277. JButton cancelButton = new JButton(cancelButtonText) {
  278. public Dimension getMaximumSize() {
  279. return new Dimension(MAX_SIZE.width, this.getPreferredSize().height);
  280. }
  281. };
  282. cancelButton.setMnemonic(cancelButtonMnemonic);
  283. cancelButton.setToolTipText(cancelButtonToolTipText);
  284. align(cancelButton);
  285. cancelButton.setMargin(buttonMargin);
  286. cancelButton.addActionListener(getCancelSelectionAction());
  287. buttonPanel.add(cancelButton);
  288. buttonPanel.add(Box.createGlue());
  289. JButton helpButton = new JButton(helpButtonText) {
  290. public Dimension getMaximumSize() {
  291. return new Dimension(MAX_SIZE.width, this.getPreferredSize().height);
  292. }
  293. };
  294. helpButton.setMnemonic(helpButtonMnemonic);
  295. helpButton.setToolTipText(helpButtonToolTipText);
  296. align(helpButton);
  297. helpButton.setMargin(buttonMargin);
  298. helpButton.setEnabled(false);
  299. buttonPanel.add(helpButton);
  300. buttonPanel.add(Box.createGlue());
  301. fc.add(buttonPanel);
  302. fc.add(Box.createRigidArea(vstrut10));
  303. fc.add(Box.createGlue());
  304. }
  305. public void uninstallComponents(JFileChooser fc) {
  306. fc.removeAll();
  307. }
  308. protected void installStrings(JFileChooser fc) {
  309. super.installStrings(fc);
  310. enterFileNameLabelText = UIManager.getString("FileChooser.enterFileNameLabelText");
  311. enterFileNameLabelMnemonic = UIManager.getInt("FileChooser.enterFileNameLabelMnemonic");
  312. filesLabelText = UIManager.getString("FileChooser.filesLabelText");
  313. filesLabelMnemonic = UIManager.getInt("FileChooser.filesLabelMnemonic");
  314. foldersLabelText = UIManager.getString("FileChooser.foldersLabelText");
  315. foldersLabelMnemonic = UIManager.getInt("FileChooser.foldersLabelMnemonic");
  316. pathLabelText = UIManager.getString("FileChooser.pathLabelText");
  317. pathLabelMnemonic = UIManager.getInt("FileChooser.pathLabelMnemonic");
  318. filterLabelText = UIManager.getString("FileChooser.filterLabelText");
  319. filterLabelMnemonic = UIManager.getInt("FileChooser.filterLabelMnemonic");
  320. }
  321. protected void installIcons(JFileChooser fc) {
  322. // Since motif doesn't have button icons, leave this empty
  323. // which overrides the supertype icon loading
  324. }
  325. protected void uninstallIcons(JFileChooser fc) {
  326. // Since motif doesn't have button icons, leave this empty
  327. // which overrides the supertype icon loading
  328. }
  329. protected JScrollPane createFilesList() {
  330. fileList = new JList();
  331. fileList.setModel(new MotifFileListModel());
  332. fileList.setCellRenderer(new FileCellRenderer());
  333. fileList.addListSelectionListener(createListSelectionListener(getFileChooser()));
  334. fileList.addMouseListener(createDoubleClickListener(getFileChooser(), fileList));
  335. align(fileList);
  336. JScrollPane scrollpane = new JScrollPane(fileList);
  337. scrollpane.setPreferredSize(prefListSize);
  338. scrollpane.setMaximumSize(MAX_SIZE);
  339. align(scrollpane);
  340. return scrollpane;
  341. }
  342. protected JScrollPane createDirectoryList() {
  343. directoryList = new JList();
  344. align(directoryList);
  345. directoryList.setCellRenderer(new DirectoryCellRenderer());
  346. directoryList.setModel(new MotifDirectoryListModel());
  347. directoryList.addMouseListener(createDoubleClickListener(getFileChooser(), directoryList));
  348. directoryList.addListSelectionListener(createListSelectionListener(getFileChooser()));
  349. JScrollPane scrollpane = new JScrollPane(directoryList);
  350. scrollpane.setMaximumSize(MAX_SIZE);
  351. scrollpane.setPreferredSize(prefListSize);
  352. align(scrollpane);
  353. return scrollpane;
  354. }
  355. public Dimension getPreferredSize(JComponent x) {
  356. if(getFileChooser().getAccessory() != null) {
  357. return WITH_ACCELERATOR_PREF_SIZE;
  358. } else {
  359. return PREF_SIZE;
  360. }
  361. }
  362. public Dimension getMinimumSize(JComponent x) {
  363. return MIN_SIZE;
  364. }
  365. public Dimension getMaximumSize(JComponent x) {
  366. return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
  367. }
  368. protected void align(JComponent c) {
  369. c.setAlignmentX(JComponent.LEFT_ALIGNMENT);
  370. c.setAlignmentY(JComponent.TOP_ALIGNMENT);
  371. }
  372. protected class FileCellRenderer extends DefaultListCellRenderer {
  373. public Component getListCellRendererComponent(JList list, Object value, int index,
  374. boolean isSelected, boolean cellHasFocus) {
  375. super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
  376. setText(getFileChooser().getName((File) value));
  377. return this;
  378. }
  379. }
  380. protected class DirectoryCellRenderer extends DefaultListCellRenderer {
  381. public Component getListCellRendererComponent(JList list, Object value, int index,
  382. boolean isSelected, boolean cellHasFocus) {
  383. super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
  384. setText(getFileChooser().getName((File) value));
  385. return this;
  386. }
  387. }
  388. protected class MotifDirectoryListModel extends AbstractListModel implements ListDataListener {
  389. public MotifDirectoryListModel() {
  390. getModel().addListDataListener(this);
  391. }
  392. public int getSize() {
  393. return getModel().getDirectories().size();
  394. }
  395. public Object getElementAt(int index) {
  396. return getModel().getDirectories().elementAt(index);
  397. }
  398. public void intervalAdded(ListDataEvent e) {
  399. }
  400. // PENDING(jeff) - implement
  401. public void intervalRemoved(ListDataEvent e) {
  402. }
  403. // PENDING(jeff) - this is inefficient - should sent out
  404. // incremental adjustment values instead of saying that the
  405. // whole list has changed.
  406. public void fireContentsChanged() {
  407. fireContentsChanged(this, 0, getModel().getDirectories().size()-1);
  408. }
  409. // PENDING(jeff) - fire the correct interval changed - currently sending
  410. // out that everything has changed
  411. public void contentsChanged(ListDataEvent e) {
  412. fireContentsChanged();
  413. }
  414. }
  415. protected class MotifFileListModel extends AbstractListModel implements ListDataListener {
  416. public MotifFileListModel() {
  417. getModel().addListDataListener(this);
  418. }
  419. public int getSize() {
  420. return getModel().getFiles().size();
  421. }
  422. public boolean contains(Object o) {
  423. return getModel().getFiles().contains(o);
  424. }
  425. public int indexOf(Object o) {
  426. return getModel().getFiles().indexOf(o);
  427. }
  428. public Object getElementAt(int index) {
  429. return getModel().getFiles().elementAt(index);
  430. }
  431. public void intervalAdded(ListDataEvent e) {
  432. }
  433. // PENDING(jeff) - implement
  434. public void intervalRemoved(ListDataEvent e) {
  435. }
  436. // PENDING(jeff) - this is inefficient - should sent out
  437. // incremental adjustment values instead of saying that the
  438. // whole list has changed.
  439. public void fireContentsChanged() {
  440. fireContentsChanged(this, 0, getModel().getFiles().size()-1);
  441. }
  442. // PENDING(jeff) - fire the interval changed
  443. public void contentsChanged(ListDataEvent e) {
  444. fireContentsChanged();
  445. }
  446. }
  447. //
  448. // DataModel for Types Comboxbox
  449. //
  450. protected FilterComboBoxModel createFilterComboBoxModel() {
  451. return new FilterComboBoxModel();
  452. }
  453. //
  454. // Renderer for Types ComboBox
  455. //
  456. protected FilterComboBoxRenderer createFilterComboBoxRenderer() {
  457. return new FilterComboBoxRenderer();
  458. }
  459. /**
  460. * Render different type sizes and styles.
  461. */
  462. public class FilterComboBoxRenderer extends DefaultListCellRenderer {
  463. public Component getListCellRendererComponent(JList list,
  464. Object value, int index, boolean isSelected,
  465. boolean cellHasFocus) {
  466. super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
  467. FileFilter filter = (FileFilter) value;
  468. if(filter != null) {
  469. setText(filter.getDescription());
  470. }
  471. return this;
  472. }
  473. }
  474. /**
  475. * Data model for a type-face selection combo-box.
  476. */
  477. protected class FilterComboBoxModel extends AbstractListModel implements ComboBoxModel, PropertyChangeListener {
  478. protected FileFilter[] filters;
  479. protected FilterComboBoxModel() {
  480. super();
  481. filters = getFileChooser().getChoosableFileFilters();
  482. }
  483. public void propertyChange(PropertyChangeEvent e) {
  484. String prop = e.getPropertyName();
  485. if(prop == JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY) {
  486. filters = (FileFilter[]) e.getNewValue();
  487. fireContentsChanged(this, -1, -1);
  488. }
  489. }
  490. public void setSelectedItem(Object filter) {
  491. if(filter != null) {
  492. getFileChooser().setFileFilter((FileFilter) filter);
  493. fireContentsChanged(this, -1, -1);
  494. }
  495. }
  496. public Object getSelectedItem() {
  497. // Ensure that the current filter is in the list.
  498. // NOTE: we shouldnt' have to do this, since JFileChooser adds
  499. // the filter to the choosable filters list when the filter
  500. // is set. Lets be paranoid just in case someone overrides
  501. // setFileFilter in JFileChooser.
  502. FileFilter currentFilter = getFileChooser().getFileFilter();
  503. boolean found = false;
  504. if(currentFilter != null) {
  505. for(int i=0; i < filters.length; i++) {
  506. if(filters[i] == currentFilter) {
  507. found = true;
  508. }
  509. }
  510. if(found == false) {
  511. getFileChooser().addChoosableFileFilter(currentFilter);
  512. }
  513. }
  514. return getFileChooser().getFileFilter();
  515. }
  516. public int getSize() {
  517. if(filters != null) {
  518. return filters.length;
  519. } else {
  520. return 0;
  521. }
  522. }
  523. public Object getElementAt(int index) {
  524. if(index > getSize() - 1) {
  525. // This shouldn't happen. Try to recover gracefully.
  526. return getFileChooser().getFileFilter();
  527. }
  528. if(filters != null) {
  529. return filters[index];
  530. } else {
  531. return null;
  532. }
  533. }
  534. }
  535. protected JButton getApproveButton(JFileChooser fc) {
  536. return approveButton;
  537. }
  538. }