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