blob: abd99439ed0b8df9f8764b11bc97d8b9026fcb91 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25package sun.swing.plaf.synth;
26
27import java.awt.*;
28import java.awt.event.*;
29import java.beans.*;
30import java.io.*;
31import java.util.*;
32
33import javax.swing.*;
34import javax.swing.event.*;
35import javax.swing.filechooser.*;
36import javax.swing.filechooser.FileFilter;
37import javax.swing.plaf.basic.*;
38import javax.swing.plaf.synth.*;
39
40import sun.swing.SwingUtilities2;
41
42import sun.awt.shell.ShellFolder;
43import sun.swing.*;
44
45/**
46 * Synth FileChooserUI implementation.
47 * <p>
48 * Note that the classes in the com.sun.java.swing.plaf.synth
49 * package are not
50 * part of the core Java APIs. They are a part of Sun's JDK and JRE
51 * distributions. Although other licensees may choose to distribute
52 * these classes, developers cannot depend on their availability in
53 * non-Sun implementations. Additionally this API may change in
54 * incompatible ways between releases. While this class is public, it
55 * shoud be considered an implementation detail, and subject to change.
56 *
57 * @author Leif Samuelsson
58 * @author Jeff Dinkins
59 */
60public class SynthFileChooserUIImpl extends SynthFileChooserUI {
61 private JLabel lookInLabel;
62 private JComboBox directoryComboBox;
63 private DirectoryComboBoxModel directoryComboBoxModel;
64 private Action directoryComboBoxAction = new DirectoryComboBoxAction();
65
66 private FilterComboBoxModel filterComboBoxModel;
67
68 private JTextField fileNameTextField;
69
70 private FilePane filePane;
71 private JToggleButton listViewButton;
72 private JToggleButton detailsViewButton;
73
74 private boolean useShellFolder;
75
76 private boolean readOnly;
77
78 private JPanel buttonPanel;
79 private JPanel bottomPanel;
80
81 private JComboBox filterComboBox;
82
83 private static final Dimension hstrut5 = new Dimension(5, 1);
84 private static final Dimension vstrut5 = new Dimension(1, 5);
85
86 private static final Insets shrinkwrap = new Insets(0,0,0,0);
87
88 // Preferred and Minimum sizes for the dialog box
89 private static Dimension LIST_PREF_SIZE = new Dimension(405, 135);
90
91 // Labels, mnemonics, and tooltips (oh my!)
92 private int lookInLabelMnemonic = 0;
93 private String lookInLabelText = null;
94 private String saveInLabelText = null;
95
96 private int fileNameLabelMnemonic = 0;
97 private String fileNameLabelText = null;
98 private int folderNameLabelMnemonic = 0;
99 private String folderNameLabelText = null;
100
101 private int filesOfTypeLabelMnemonic = 0;
102 private String filesOfTypeLabelText = null;
103
104 private String upFolderToolTipText = null;
105 private String upFolderAccessibleName = null;
106
107 private String homeFolderToolTipText = null;
108 private String homeFolderAccessibleName = null;
109
110 private String newFolderToolTipText = null;
111 private String newFolderAccessibleName = null;
112
113 private String listViewButtonToolTipText = null;
114 private String listViewButtonAccessibleName = null;
115
116 private String detailsViewButtonToolTipText = null;
117 private String detailsViewButtonAccessibleName = null;
118
119 private AlignedLabel fileNameLabel;
120 private final PropertyChangeListener modeListener = new PropertyChangeListener() {
121 public void propertyChange(PropertyChangeEvent event) {
122 if (fileNameLabel != null) {
123 populateFileNameLabel();
124 }
125 }
126 };
127
128 private void populateFileNameLabel() {
129 if (getFileChooser().getFileSelectionMode() == JFileChooser.DIRECTORIES_ONLY) {
130 fileNameLabel.setText(folderNameLabelText);
131 fileNameLabel.setDisplayedMnemonic(folderNameLabelMnemonic);
132 } else {
133 fileNameLabel.setText(fileNameLabelText);
134 fileNameLabel.setDisplayedMnemonic(fileNameLabelMnemonic);
135 }
136 }
137
138 public SynthFileChooserUIImpl(JFileChooser b) {
139 super(b);
140 }
141
142
143 private class SynthFileChooserUIAccessor implements FilePane.FileChooserUIAccessor {
144 public JFileChooser getFileChooser() {
145 return SynthFileChooserUIImpl.this.getFileChooser();
146 }
147
148 public BasicDirectoryModel getModel() {
149 return SynthFileChooserUIImpl.this.getModel();
150 }
151
152 public JPanel createList() {
153 return null;
154 }
155
156 public JPanel createDetailsView() {
157 return null;
158 }
159
160 public boolean isDirectorySelected() {
161 return SynthFileChooserUIImpl.this.isDirectorySelected();
162 }
163
164 public File getDirectory() {
165 return SynthFileChooserUIImpl.this.getDirectory();
166 }
167
168 public Action getChangeToParentDirectoryAction() {
169 return SynthFileChooserUIImpl.this.getChangeToParentDirectoryAction();
170 }
171
172 public Action getApproveSelectionAction() {
173 return SynthFileChooserUIImpl.this.getApproveSelectionAction();
174 }
175
176 public Action getNewFolderAction() {
177 return SynthFileChooserUIImpl.this.getNewFolderAction();
178 }
179
180 public MouseListener createDoubleClickListener(JList list) {
181 return SynthFileChooserUIImpl.this.createDoubleClickListener(getFileChooser(),
182 list);
183 }
184
185 public ListSelectionListener createListSelectionListener() {
186 return SynthFileChooserUIImpl.this.createListSelectionListener(getFileChooser());
187 }
188
189 public boolean usesShellFolder() {
190 return useShellFolder;
191 }
192 }
193
194 protected void installDefaults(JFileChooser fc) {
195 super.installDefaults(fc);
196 readOnly = UIManager.getBoolean("FileChooser.readOnly");
197 }
198
199 public void installComponents(JFileChooser fc) {
200 super.installComponents(fc);
201
202 SynthContext context = getContext(fc, ENABLED);
203
204 updateUseShellFolder();
205
206 fc.setLayout(new BorderLayout(0, 11));
207
208 // ********************************* //
209 // **** Construct the top panel **** //
210 // ********************************* //
211
212 // Directory manipulation buttons
213 JPanel topPanel = new JPanel(new BorderLayout(11, 0));
214 JPanel topButtonPanel = new JPanel();
215 topButtonPanel.setLayout(new BoxLayout(topButtonPanel, BoxLayout.LINE_AXIS));
216 topPanel.add(topButtonPanel, BorderLayout.AFTER_LINE_ENDS);
217
218 // Add the top panel to the fileChooser
219 fc.add(topPanel, BorderLayout.NORTH);
220
221 // ComboBox Label
222 lookInLabel = new JLabel(lookInLabelText);
223 lookInLabel.setDisplayedMnemonic(lookInLabelMnemonic);
224 topPanel.add(lookInLabel, BorderLayout.BEFORE_LINE_BEGINS);
225
226 // CurrentDir ComboBox
227 directoryComboBox = new JComboBox();
228 directoryComboBox.getAccessibleContext().setAccessibleDescription(lookInLabelText);
229 directoryComboBox.putClientProperty( "JComboBox.isTableCellEditor", Boolean.TRUE );
230 lookInLabel.setLabelFor(directoryComboBox);
231 directoryComboBoxModel = createDirectoryComboBoxModel(fc);
232 directoryComboBox.setModel(directoryComboBoxModel);
233 directoryComboBox.addActionListener(directoryComboBoxAction);
234 directoryComboBox.setRenderer(createDirectoryComboBoxRenderer(fc));
235 directoryComboBox.setAlignmentX(JComponent.LEFT_ALIGNMENT);
236 directoryComboBox.setAlignmentY(JComponent.TOP_ALIGNMENT);
237 directoryComboBox.setMaximumRowCount(8);
238 topPanel.add(directoryComboBox, BorderLayout.CENTER);
239
240 filePane = new FilePane(new SynthFileChooserUIAccessor());
241 fc.addPropertyChangeListener(filePane);
242
243 // Add 'Go Up' to context menu, plus 'Go Home' if on Unix
244 JPopupMenu contextMenu = filePane.getComponentPopupMenu();
245 if (contextMenu != null) {
246 contextMenu.insert(getChangeToParentDirectoryAction(), 0);
247 if (File.separatorChar == '/') {
248 contextMenu.insert(getGoHomeAction(), 1);
249 }
250 }
251
252 FileSystemView fsv = fc.getFileSystemView();
253
254 // Up Button
255 JButton upFolderButton = new JButton(getChangeToParentDirectoryAction());
256 upFolderButton.setText(null);
257 upFolderButton.setIcon(upFolderIcon);
258 upFolderButton.setToolTipText(upFolderToolTipText);
259 upFolderButton.getAccessibleContext().setAccessibleName(upFolderAccessibleName);
260 upFolderButton.setAlignmentX(JComponent.LEFT_ALIGNMENT);
261 upFolderButton.setAlignmentY(JComponent.CENTER_ALIGNMENT);
262 upFolderButton.setMargin(shrinkwrap);
263
264 topButtonPanel.add(upFolderButton);
265 topButtonPanel.add(Box.createRigidArea(hstrut5));
266
267 // Home Button
268 File homeDir = fsv.getHomeDirectory();
269 String toolTipText = homeFolderToolTipText;
270 if (fsv.isRoot(homeDir)) {
271 toolTipText = getFileView(fc).getName(homeDir); // Probably "Desktop".
272 }
273
274 JButton b = new JButton(homeFolderIcon);
275 b.setToolTipText(toolTipText);
276 b.getAccessibleContext().setAccessibleName(homeFolderAccessibleName);
277 b.setAlignmentX(JComponent.LEFT_ALIGNMENT);
278 b.setAlignmentY(JComponent.CENTER_ALIGNMENT);
279 b.setMargin(shrinkwrap);
280
281 b.addActionListener(getGoHomeAction());
282 topButtonPanel.add(b);
283 topButtonPanel.add(Box.createRigidArea(hstrut5));
284
285 // New Directory Button
286 if (!readOnly) {
287 b = new JButton(filePane.getNewFolderAction());
288 b.setText(null);
289 b.setIcon(newFolderIcon);
290 b.setToolTipText(newFolderToolTipText);
291 b.getAccessibleContext().setAccessibleName(newFolderAccessibleName);
292 b.setAlignmentX(JComponent.LEFT_ALIGNMENT);
293 b.setAlignmentY(JComponent.CENTER_ALIGNMENT);
294 b.setMargin(shrinkwrap);
295 }
296 topButtonPanel.add(b);
297 topButtonPanel.add(Box.createRigidArea(hstrut5));
298
299 // View button group
300 ButtonGroup viewButtonGroup = new ButtonGroup();
301
302 // List Button
303 listViewButton = new JToggleButton(listViewIcon);
304 listViewButton.setToolTipText(listViewButtonToolTipText);
305 listViewButton.getAccessibleContext().setAccessibleName(listViewButtonAccessibleName);
306 listViewButton.setSelected(true);
307 listViewButton.setAlignmentX(JComponent.LEFT_ALIGNMENT);
308 listViewButton.setAlignmentY(JComponent.CENTER_ALIGNMENT);
309 listViewButton.setMargin(shrinkwrap);
310 listViewButton.addActionListener(filePane.getViewTypeAction(FilePane.VIEWTYPE_LIST));
311 topButtonPanel.add(listViewButton);
312 viewButtonGroup.add(listViewButton);
313
314 // Details Button
315 detailsViewButton = new JToggleButton(detailsViewIcon);
316 detailsViewButton.setToolTipText(detailsViewButtonToolTipText);
317 detailsViewButton.getAccessibleContext().setAccessibleName(detailsViewButtonAccessibleName);
318 detailsViewButton.setAlignmentX(JComponent.LEFT_ALIGNMENT);
319 detailsViewButton.setAlignmentY(JComponent.CENTER_ALIGNMENT);
320 detailsViewButton.setMargin(shrinkwrap);
321 detailsViewButton.addActionListener(filePane.getViewTypeAction(FilePane.VIEWTYPE_DETAILS));
322 topButtonPanel.add(detailsViewButton);
323 viewButtonGroup.add(detailsViewButton);
324
325 filePane.addPropertyChangeListener(new PropertyChangeListener() {
326 public void propertyChange(PropertyChangeEvent e) {
327 if ("viewType".equals(e.getPropertyName())) {
328 int viewType = filePane.getViewType();
329 switch (viewType) {
330 case FilePane.VIEWTYPE_LIST:
331 listViewButton.setSelected(true);
332 break;
333 case FilePane.VIEWTYPE_DETAILS:
334 detailsViewButton.setSelected(true);
335 break;
336 }
337 }
338 }
339 });
340
341 // ************************************** //
342 // ******* Add the directory pane ******* //
343 // ************************************** //
344 fc.add(getAccessoryPanel(), BorderLayout.AFTER_LINE_ENDS);
345 JComponent accessory = fc.getAccessory();
346 if (accessory != null) {
347 getAccessoryPanel().add(accessory);
348 }
349 filePane.setPreferredSize(LIST_PREF_SIZE);
350 fc.add(filePane, BorderLayout.CENTER);
351
352
353 // ********************************** //
354 // **** Construct the bottom panel ** //
355 // ********************************** //
356 bottomPanel = new JPanel();
357 bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.Y_AXIS));
358 fc.add(bottomPanel, BorderLayout.SOUTH);
359
360 // FileName label and textfield
361 JPanel fileNamePanel = new JPanel();
362 fileNamePanel.setLayout(new BoxLayout(fileNamePanel, BoxLayout.LINE_AXIS));
363 bottomPanel.add(fileNamePanel);
364 bottomPanel.add(Box.createRigidArea(new Dimension(1, 5)));
365
366 fileNameLabel = new AlignedLabel();
367 populateFileNameLabel();
368 fileNamePanel.add(fileNameLabel);
369
370 fileNameTextField = new JTextField(35) {
371 public Dimension getMaximumSize() {
372 return new Dimension(Short.MAX_VALUE, super.getPreferredSize().height);
373 }
374 };
375 fileNamePanel.add(fileNameTextField);
376 fileNameLabel.setLabelFor(fileNameTextField);
377 fileNameTextField.addFocusListener(
378 new FocusAdapter() {
379 public void focusGained(FocusEvent e) {
380 if (!getFileChooser().isMultiSelectionEnabled()) {
381 filePane.clearSelection();
382 }
383 }
384 }
385 );
386 if (fc.isMultiSelectionEnabled()) {
387 setFileName(fileNameString(fc.getSelectedFiles()));
388 } else {
389 setFileName(fileNameString(fc.getSelectedFile()));
390 }
391
392
393 // Filetype label and combobox
394 JPanel filesOfTypePanel = new JPanel();
395 filesOfTypePanel.setLayout(new BoxLayout(filesOfTypePanel, BoxLayout.LINE_AXIS));
396 bottomPanel.add(filesOfTypePanel);
397
398 AlignedLabel filesOfTypeLabel = new AlignedLabel(filesOfTypeLabelText);
399 filesOfTypeLabel.setDisplayedMnemonic(filesOfTypeLabelMnemonic);
400 filesOfTypePanel.add(filesOfTypeLabel);
401
402 filterComboBoxModel = createFilterComboBoxModel();
403 fc.addPropertyChangeListener(filterComboBoxModel);
404 filterComboBox = new JComboBox(filterComboBoxModel);
405 filterComboBox.getAccessibleContext().setAccessibleDescription(filesOfTypeLabelText);
406 filesOfTypeLabel.setLabelFor(filterComboBox);
407 filterComboBox.setRenderer(createFilterComboBoxRenderer());
408 filesOfTypePanel.add(filterComboBox);
409
410
411 // buttons
412 buttonPanel = new JPanel();
413 buttonPanel.setLayout(new ButtonAreaLayout());
414
415 buttonPanel.add(getApproveButton(fc));
416 buttonPanel.add(getCancelButton(fc));
417
418 if (fc.getControlButtonsAreShown()) {
419 addControlButtons();
420 }
421
422 groupLabels(new AlignedLabel[] { fileNameLabel, filesOfTypeLabel });
423 }
424
425 protected void installListeners(JFileChooser fc) {
426 super.installListeners(fc);
427 fc.addPropertyChangeListener(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY, modeListener);
428 }
429
430 protected void uninstallListeners(JFileChooser fc) {
431 fc.removePropertyChangeListener(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY, modeListener);
432 super.uninstallListeners(fc);
433 }
434
435 private void updateUseShellFolder() {
436 // Decide whether to use the ShellFolder class to populate shortcut
437 // panel and combobox.
438 JFileChooser fc = getFileChooser();
439 Boolean prop =
440 (Boolean)fc.getClientProperty("FileChooser.useShellFolder");
441 if (prop != null) {
442 useShellFolder = prop.booleanValue();
443 } else {
444 useShellFolder = fc.getFileSystemView().equals(FileSystemView.getFileSystemView());
445 }
446 }
447
448
449 private String fileNameString(File file) {
450 if (file == null) {
451 return null;
452 } else {
453 JFileChooser fc = getFileChooser();
454 if (fc.isDirectorySelectionEnabled() && !fc.isFileSelectionEnabled()) {
455 return file.getPath();
456 } else {
457 return file.getName();
458 }
459 }
460 }
461
462 private String fileNameString(File[] files) {
463 StringBuffer buf = new StringBuffer();
464 for (int i = 0; files != null && i < files.length; i++) {
465 if (i > 0) {
466 buf.append(" ");
467 }
468 if (files.length > 1) {
469 buf.append("\"");
470 }
471 buf.append(fileNameString(files[i]));
472 if (files.length > 1) {
473 buf.append("\"");
474 }
475 }
476 return buf.toString();
477 }
478
479 public void uninstallUI(JComponent c) {
480 // Remove listeners
481 c.removePropertyChangeListener(filterComboBoxModel);
482 c.removePropertyChangeListener(filePane);
483
484 if (filePane != null) {
485 filePane.uninstallUI();
486 filePane = null;
487 }
488
489 super.uninstallUI(c);
490 }
491
492 protected void installStrings(JFileChooser fc) {
493 super.installStrings(fc);
494
495 Locale l = fc.getLocale();
496
497 lookInLabelMnemonic = getMnemonic("FileChooser.lookInLabelMnemonic", l);
498 lookInLabelText = UIManager.getString("FileChooser.lookInLabelText", l);
499 saveInLabelText = UIManager.getString("FileChooser.saveInLabelText", l);
500
501 fileNameLabelMnemonic = getMnemonic("FileChooser.fileNameLabelMnemonic", l);
502 fileNameLabelText = UIManager.getString("FileChooser.fileNameLabelText", l);
503 folderNameLabelMnemonic = getMnemonic("FileChooser.folderNameLabelMnemonic", l);
504 folderNameLabelText = UIManager.getString("FileChooser.folderNameLabelText", l);
505
506 filesOfTypeLabelMnemonic = getMnemonic("FileChooser.filesOfTypeLabelMnemonic", l);
507 filesOfTypeLabelText = UIManager.getString("FileChooser.filesOfTypeLabelText", l);
508
509 upFolderToolTipText = UIManager.getString("FileChooser.upFolderToolTipText",l);
510 upFolderAccessibleName = UIManager.getString("FileChooser.upFolderAccessibleName",l);
511
512 homeFolderToolTipText = UIManager.getString("FileChooser.homeFolderToolTipText",l);
513 homeFolderAccessibleName = UIManager.getString("FileChooser.homeFolderAccessibleName",l);
514
515 newFolderToolTipText = UIManager.getString("FileChooser.newFolderToolTipText",l);
516 newFolderAccessibleName = UIManager.getString("FileChooser.newFolderAccessibleName",l);
517
518 listViewButtonToolTipText = UIManager.getString("FileChooser.listViewButtonToolTipText",l);
519 listViewButtonAccessibleName = UIManager.getString("FileChooser.listViewButtonAccessibleName",l);
520
521 detailsViewButtonToolTipText = UIManager.getString("FileChooser.detailsViewButtonToolTipText",l);
522 detailsViewButtonAccessibleName = UIManager.getString("FileChooser.detailsViewButtonAccessibleName",l);
523 }
524
525 private int getMnemonic(String key, Locale l) {
526 return SwingUtilities2.getUIDefaultsInt(key, l);
527 }
528
529
530 public String getFileName() {
531 if (fileNameTextField != null) {
532 return fileNameTextField.getText();
533 } else {
534 return null;
535 }
536 }
537
538 public void setFileName(String fileName) {
539 if (fileNameTextField != null) {
540 fileNameTextField.setText(fileName);
541 }
542 }
543
544
545 protected void doSelectedFileChanged(PropertyChangeEvent e) {
546 super.doSelectedFileChanged(e);
547
548 File f = (File) e.getNewValue();
549 JFileChooser fc = getFileChooser();
550 if (f != null
551 && ((fc.isFileSelectionEnabled() && !f.isDirectory())
552 || (f.isDirectory() && fc.isDirectorySelectionEnabled()))) {
553
554 setFileName(fileNameString(f));
555 }
556 }
557
558 protected void doSelectedFilesChanged(PropertyChangeEvent e) {
559 super.doSelectedFilesChanged(e);
560
561 File[] files = (File[]) e.getNewValue();
562 JFileChooser fc = getFileChooser();
563 if (files != null
564 && files.length > 0
565 && (files.length > 1 || fc.isDirectorySelectionEnabled() || !files[0].isDirectory())) {
566 setFileName(fileNameString(files));
567 }
568 }
569
570 protected void doDirectoryChanged(PropertyChangeEvent e) {
571 super.doDirectoryChanged(e);
572
573 JFileChooser fc = getFileChooser();
574 FileSystemView fsv = fc.getFileSystemView();
575 File currentDirectory = fc.getCurrentDirectory();
576
577 if (!readOnly && currentDirectory != null) {
578 getNewFolderAction().setEnabled(filePane.canWrite(currentDirectory));
579 }
580
581 if (currentDirectory != null) {
582 JComponent cb = getDirectoryComboBox();
583 if (cb instanceof JComboBox) {
584 ComboBoxModel model = ((JComboBox)cb).getModel();
585 if (model instanceof DirectoryComboBoxModel) {
586 ((DirectoryComboBoxModel)model).addItem(currentDirectory);
587 }
588 }
589
590 if (fc.isDirectorySelectionEnabled() && !fc.isFileSelectionEnabled()) {
591 if (fsv.isFileSystem(currentDirectory)) {
592 setFileName(currentDirectory.getPath());
593 } else {
594 setFileName(null);
595 }
596 }
597 }
598 }
599
600
601 protected void doFileSelectionModeChanged(PropertyChangeEvent e) {
602 super.doFileSelectionModeChanged(e);
603
604 JFileChooser fc = getFileChooser();
605 File currentDirectory = fc.getCurrentDirectory();
606 if (currentDirectory != null
607 && fc.isDirectorySelectionEnabled()
608 && !fc.isFileSelectionEnabled()
609 && fc.getFileSystemView().isFileSystem(currentDirectory)) {
610
611 setFileName(currentDirectory.getPath());
612 } else {
613 setFileName(null);
614 }
615 }
616
617 protected void doAccessoryChanged(PropertyChangeEvent e) {
618 if (getAccessoryPanel() != null) {
619 if (e.getOldValue() != null) {
620 getAccessoryPanel().remove((JComponent)e.getOldValue());
621 }
622 JComponent accessory = (JComponent)e.getNewValue();
623 if (accessory != null) {
624 getAccessoryPanel().add(accessory, BorderLayout.CENTER);
625 }
626 }
627 }
628
629 protected void doControlButtonsChanged(PropertyChangeEvent e) {
630 super.doControlButtonsChanged(e);
631
632 if (getFileChooser().getControlButtonsAreShown()) {
633 addControlButtons();
634 } else {
635 removeControlButtons();
636 }
637 }
638
639 protected void addControlButtons() {
640 if (bottomPanel != null) {
641 bottomPanel.add(buttonPanel);
642 }
643 }
644
645 protected void removeControlButtons() {
646 if (bottomPanel != null) {
647 bottomPanel.remove(buttonPanel);
648 }
649 }
650
651
652
653
654 // *******************************************************
655 // ************ FileChooser UI PLAF methods **************
656 // *******************************************************
657
658
659 // *****************************
660 // ***** Directory Actions *****
661 // *****************************
662
663 protected JComponent getDirectoryComboBox() {
664 return directoryComboBox;
665 }
666
667 protected Action getDirectoryComboBoxAction() {
668 return directoryComboBoxAction;
669 }
670
671 protected DirectoryComboBoxRenderer createDirectoryComboBoxRenderer(JFileChooser fc) {
672 return new DirectoryComboBoxRenderer();
673 }
674
675 //
676 // Renderer for DirectoryComboBox
677 //
678 class DirectoryComboBoxRenderer extends DefaultListCellRenderer {
679 IndentIcon ii = new IndentIcon();
680 public Component getListCellRendererComponent(JList list, Object value,
681 int index, boolean isSelected,
682 boolean cellHasFocus) {
683
684 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
685
686 if (value == null) {
687 setText("");
688 return this;
689 }
690 File directory = (File)value;
691 setText(getFileChooser().getName(directory));
692 Icon icon = getFileChooser().getIcon(directory);
693 ii.icon = icon;
694 ii.depth = directoryComboBoxModel.getDepth(index);
695 setIcon(ii);
696
697 return this;
698 }
699 }
700
701 final static int space = 10;
702 class IndentIcon implements Icon {
703
704 Icon icon = null;
705 int depth = 0;
706
707 public void paintIcon(Component c, Graphics g, int x, int y) {
708 if (icon != null) {
709 if (c.getComponentOrientation().isLeftToRight()) {
710 icon.paintIcon(c, g, x+depth*space, y);
711 } else {
712 icon.paintIcon(c, g, x, y);
713 }
714 }
715 }
716
717 public int getIconWidth() {
718 return ((icon != null) ? icon.getIconWidth() : 0) + depth*space;
719 }
720
721 public int getIconHeight() {
722 return (icon != null) ? icon.getIconHeight() : 0;
723 }
724
725 }
726
727 //
728 // DataModel for DirectoryComboxbox
729 //
730 protected DirectoryComboBoxModel createDirectoryComboBoxModel(JFileChooser fc) {
731 return new DirectoryComboBoxModel();
732 }
733
734 /**
735 * Data model for a type-face selection combo-box.
736 */
737 protected class DirectoryComboBoxModel extends AbstractListModel implements ComboBoxModel {
738 Vector directories = new Vector();
739 int[] depths = null;
740 File selectedDirectory = null;
741 JFileChooser chooser = getFileChooser();
742 FileSystemView fsv = chooser.getFileSystemView();
743
744 public DirectoryComboBoxModel() {
745 // Add the current directory to the model, and make it the
746 // selectedDirectory
747 File dir = getFileChooser().getCurrentDirectory();
748 if (dir != null) {
749 addItem(dir);
750 }
751 }
752
753 /**
754 * Adds the directory to the model and sets it to be selected,
755 * additionally clears out the previous selected directory and
756 * the paths leading up to it, if any.
757 */
758 public void addItem(File directory) {
759
760 if (directory == null) {
761 return;
762 }
763
764 int oldSize = directories.size();
765 directories.clear();
766 if (oldSize > 0) {
767 fireIntervalRemoved(this, 0, oldSize);
768 }
769
770 File[] baseFolders;
771 if (useShellFolder) {
772 baseFolders = (File[])ShellFolder.get("fileChooserComboBoxFolders");
773 } else {
774 baseFolders = fsv.getRoots();
775 }
776 directories.addAll(Arrays.asList(baseFolders));
777
778 // Get the canonical (full) path. This has the side
779 // benefit of removing extraneous chars from the path,
780 // for example /foo/bar/ becomes /foo/bar
781 File canonical = null;
782 try {
783 canonical = directory.getCanonicalFile();
784 } catch (IOException e) {
785 // Maybe drive is not ready. Can't abort here.
786 canonical = directory;
787 }
788
789 // create File instances of each directory leading up to the top
790 try {
791 File sf = useShellFolder ? ShellFolder.getShellFolder(canonical)
792 : canonical;
793 File f = sf;
794 Vector path = new Vector(10);
795 do {
796 path.addElement(f);
797 } while ((f = f.getParentFile()) != null);
798
799 int pathCount = path.size();
800 // Insert chain at appropriate place in vector
801 for (int i = 0; i < pathCount; i++) {
802 f = (File)path.get(i);
803 if (directories.contains(f)) {
804 int topIndex = directories.indexOf(f);
805 for (int j = i-1; j >= 0; j--) {
806 directories.insertElementAt(path.get(j), topIndex+i-j);
807 }
808 break;
809 }
810 }
811 calculateDepths();
812 setSelectedItem(sf);
813 } catch (FileNotFoundException ex) {
814 calculateDepths();
815 }
816 }
817
818 private void calculateDepths() {
819 depths = new int[directories.size()];
820 for (int i = 0; i < depths.length; i++) {
821 File dir = (File)directories.get(i);
822 File parent = dir.getParentFile();
823 depths[i] = 0;
824 if (parent != null) {
825 for (int j = i-1; j >= 0; j--) {
826 if (parent.equals((File)directories.get(j))) {
827 depths[i] = depths[j] + 1;
828 break;
829 }
830 }
831 }
832 }
833 }
834
835 public int getDepth(int i) {
836 return (depths != null && i >= 0 && i < depths.length) ? depths[i] : 0;
837 }
838
839 public void setSelectedItem(Object selectedDirectory) {
840 this.selectedDirectory = (File)selectedDirectory;
841 fireContentsChanged(this, -1, -1);
842 }
843
844 public Object getSelectedItem() {
845 return selectedDirectory;
846 }
847
848 public int getSize() {
849 return directories.size();
850 }
851
852 public Object getElementAt(int index) {
853 return directories.elementAt(index);
854 }
855 }
856
857 /**
858 * Acts when DirectoryComboBox has changed the selected item.
859 */
860 protected class DirectoryComboBoxAction extends AbstractAction {
861 protected DirectoryComboBoxAction() {
862 super("DirectoryComboBoxAction");
863 }
864
865 public void actionPerformed(ActionEvent e) {
866 directoryComboBox.hidePopup();
867 JComponent cb = getDirectoryComboBox();
868 if (cb instanceof JComboBox) {
869 File f = (File)((JComboBox)cb).getSelectedItem();
870 getFileChooser().setCurrentDirectory(f);
871 }
872 }
873 }
874
875 //
876 // Renderer for Types ComboBox
877 //
878 protected FilterComboBoxRenderer createFilterComboBoxRenderer() {
879 return new FilterComboBoxRenderer();
880 }
881
882 /**
883 * Render different type sizes and styles.
884 */
885 public class FilterComboBoxRenderer extends DefaultListCellRenderer {
886 public Component getListCellRendererComponent(JList list,
887 Object value, int index, boolean isSelected,
888 boolean cellHasFocus) {
889
890 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
891
892 if (value != null && value instanceof FileFilter) {
893 setText(((FileFilter)value).getDescription());
894 }
895
896 return this;
897 }
898 }
899
900 //
901 // DataModel for Types Comboxbox
902 //
903 protected FilterComboBoxModel createFilterComboBoxModel() {
904 return new FilterComboBoxModel();
905 }
906
907 /**
908 * Data model for a type-face selection combo-box.
909 */
910 protected class FilterComboBoxModel extends AbstractListModel implements ComboBoxModel, PropertyChangeListener {
911 protected FileFilter[] filters;
912 protected FilterComboBoxModel() {
913 super();
914 filters = getFileChooser().getChoosableFileFilters();
915 }
916
917 public void propertyChange(PropertyChangeEvent e) {
918 String prop = e.getPropertyName();
919 if(prop == JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY) {
920 filters = (FileFilter[]) e.getNewValue();
921 fireContentsChanged(this, -1, -1);
922 } else if (prop == JFileChooser.FILE_FILTER_CHANGED_PROPERTY) {
923 fireContentsChanged(this, -1, -1);
924 }
925 }
926
927 public void setSelectedItem(Object filter) {
928 if(filter != null) {
929 getFileChooser().setFileFilter((FileFilter) filter);
930 fireContentsChanged(this, -1, -1);
931 }
932 }
933
934 public Object getSelectedItem() {
935 // Ensure that the current filter is in the list.
936 // NOTE: we shouldnt' have to do this, since JFileChooser adds
937 // the filter to the choosable filters list when the filter
938 // is set. Lets be paranoid just in case someone overrides
939 // setFileFilter in JFileChooser.
940 FileFilter currentFilter = getFileChooser().getFileFilter();
941 boolean found = false;
942 if(currentFilter != null) {
943 for(int i=0; i < filters.length; i++) {
944 if(filters[i] == currentFilter) {
945 found = true;
946 }
947 }
948 if(found == false) {
949 getFileChooser().addChoosableFileFilter(currentFilter);
950 }
951 }
952 return getFileChooser().getFileFilter();
953 }
954
955 public int getSize() {
956 if(filters != null) {
957 return filters.length;
958 } else {
959 return 0;
960 }
961 }
962
963 public Object getElementAt(int index) {
964 if(index > getSize() - 1) {
965 // This shouldn't happen. Try to recover gracefully.
966 return getFileChooser().getFileFilter();
967 }
968 if(filters != null) {
969 return filters[index];
970 } else {
971 return null;
972 }
973 }
974 }
975
976
977
978 /**
979 * <code>ButtonAreaLayout</code> behaves in a similar manner to
980 * <code>FlowLayout</code>. It lays out all components from left to
981 * right, flushed right. The widths of all components will be set
982 * to the largest preferred size width.
983 */
984 private static class ButtonAreaLayout implements LayoutManager {
985 private int hGap = 5;
986 private int topMargin = 17;
987
988 public void addLayoutComponent(String string, Component comp) {
989 }
990
991 public void layoutContainer(Container container) {
992 Component[] children = container.getComponents();
993
994 if (children != null && children.length > 0) {
995 int numChildren = children.length;
996 Dimension[] sizes = new Dimension[numChildren];
997 Insets insets = container.getInsets();
998 int yLocation = insets.top + topMargin;
999 int maxWidth = 0;
1000
1001 for (int counter = 0; counter < numChildren; counter++) {
1002 sizes[counter] = children[counter].getPreferredSize();
1003 maxWidth = Math.max(maxWidth, sizes[counter].width);
1004 }
1005 int xLocation, xOffset;
1006 if (container.getComponentOrientation().isLeftToRight()) {
1007 xLocation = container.getSize().width - insets.left - maxWidth;
1008 xOffset = hGap + maxWidth;
1009 } else {
1010 xLocation = insets.left;
1011 xOffset = -(hGap + maxWidth);
1012 }
1013 for (int counter = numChildren - 1; counter >= 0; counter--) {
1014 children[counter].setBounds(xLocation, yLocation,
1015 maxWidth, sizes[counter].height);
1016 xLocation -= xOffset;
1017 }
1018 }
1019 }
1020
1021 public Dimension minimumLayoutSize(Container c) {
1022 if (c != null) {
1023 Component[] children = c.getComponents();
1024
1025 if (children != null && children.length > 0) {
1026 int numChildren = children.length;
1027 int height = 0;
1028 Insets cInsets = c.getInsets();
1029 int extraHeight = topMargin + cInsets.top + cInsets.bottom;
1030 int extraWidth = cInsets.left + cInsets.right;
1031 int maxWidth = 0;
1032
1033 for (int counter = 0; counter < numChildren; counter++) {
1034 Dimension aSize = children[counter].getPreferredSize();
1035 height = Math.max(height, aSize.height);
1036 maxWidth = Math.max(maxWidth, aSize.width);
1037 }
1038 return new Dimension(extraWidth + numChildren * maxWidth +
1039 (numChildren - 1) * hGap,
1040 extraHeight + height);
1041 }
1042 }
1043 return new Dimension(0, 0);
1044 }
1045
1046 public Dimension preferredLayoutSize(Container c) {
1047 return minimumLayoutSize(c);
1048 }
1049
1050 public void removeLayoutComponent(Component c) { }
1051 }
1052
1053 private static void groupLabels(AlignedLabel[] group) {
1054 for (int i = 0; i < group.length; i++) {
1055 group[i].group = group;
1056 }
1057 }
1058
1059 private class AlignedLabel extends JLabel {
1060 private AlignedLabel[] group;
1061 private int maxWidth = 0;
1062
1063 AlignedLabel() {
1064 super();
1065 setAlignmentX(JComponent.LEFT_ALIGNMENT);
1066 }
1067
1068 AlignedLabel(String text) {
1069 super(text);
1070 setAlignmentX(JComponent.LEFT_ALIGNMENT);
1071 }
1072
1073 public Dimension getPreferredSize() {
1074 Dimension d = super.getPreferredSize();
1075 // Align the width with all other labels in group.
1076 return new Dimension(getMaxWidth() + 11, d.height);
1077 }
1078
1079 private int getMaxWidth() {
1080 if (maxWidth == 0 && group != null) {
1081 int max = 0;
1082 for (int i = 0; i < group.length; i++) {
1083 max = Math.max(group[i].getSuperPreferredWidth(), max);
1084 }
1085 for (int i = 0; i < group.length; i++) {
1086 group[i].maxWidth = max;
1087 }
1088 }
1089 return maxWidth;
1090 }
1091
1092 private int getSuperPreferredWidth() {
1093 return super.getPreferredSize().width;
1094 }
1095 }
1096}