1 /* 2 * Copyright (c) 2002, 2014, 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 com.sun.java.swing.plaf.gtk; 26 27 import java.awt.*; 28 import java.awt.event.*; 29 import java.beans.*; 30 import java.io.File; 31 import java.io.IOException; 32 import java.text.MessageFormat; 33 import java.util.*; 34 35 import javax.swing.*; 36 import javax.swing.border.*; 37 import javax.swing.filechooser.*; 38 import javax.swing.event.*; 39 import javax.swing.plaf.*; 40 import javax.swing.plaf.basic.BasicDirectoryModel; 41 import javax.swing.table.*; 42 import javax.accessibility.*; 43 44 import sun.swing.SwingUtilities2; 45 46 import sun.swing.plaf.synth.*; 47 import sun.swing.FilePane; 48 import sun.awt.shell.ShellFolder; 49 50 /** 51 * GTK FileChooserUI. 52 * 53 * @author Leif Samuelsson 54 * @author Jeff Dinkins 55 */ 56 class GTKFileChooserUI extends SynthFileChooserUI { 57 58 // The accessoryPanel is a container to place the JFileChooser accessory component 59 private JPanel accessoryPanel = null; 60 61 private String newFolderButtonText = null; 62 private String newFolderErrorSeparator = null; 63 private String newFolderErrorText = null; 64 private String newFolderDialogText = null; 65 private String newFolderNoDirectoryErrorTitleText = null; 66 private String newFolderNoDirectoryErrorText = null; 67 68 private String deleteFileButtonText = null; 69 private String renameFileButtonText = null; 70 71 private String newFolderButtonToolTipText = null; 72 private String deleteFileButtonToolTipText = null; 73 private String renameFileButtonToolTipText = null; 74 75 private int newFolderButtonMnemonic = 0; 76 private int deleteFileButtonMnemonic = 0; 77 private int renameFileButtonMnemonic = 0; 78 private int foldersLabelMnemonic = 0; 79 private int filesLabelMnemonic = 0; 80 81 private String renameFileDialogText = null; 82 private String renameFileErrorTitle = null; 83 private String renameFileErrorText = null; 84 85 private JComboBox filterComboBox; 86 private FilterComboBoxModel filterComboBoxModel; 87 88 // From Motif 89 90 private JPanel rightPanel; 91 private JList directoryList; 92 private JList fileList; 93 94 private JLabel pathField; 95 private JTextField fileNameTextField; 96 97 private static final Dimension hstrut3 = new Dimension(3, 1); 98 private static final Dimension vstrut10 = new Dimension(1, 10); 99 100 private static Dimension prefListSize = new Dimension(75, 150); 101 102 private static Dimension PREF_SIZE = new Dimension(435, 360); 103 private static Dimension MIN_SIZE = new Dimension(200, 300); 104 105 private static Dimension ZERO_ACC_SIZE = new Dimension(1, 1); 106 107 private static Dimension MAX_SIZE = new Dimension(Short.MAX_VALUE, Short.MAX_VALUE); 108 109 private static final Insets buttonMargin = new Insets(3, 3, 3, 3); 110 111 private String filesLabelText = null; 112 private String foldersLabelText = null; 113 private String pathLabelText = null; 114 private String filterLabelText = null; 115 116 private int pathLabelMnemonic = 0; 117 private int filterLabelMnemonic = 0; 118 119 private JComboBox directoryComboBox; 120 private DirectoryComboBoxModel directoryComboBoxModel; 121 private Action directoryComboBoxAction = new DirectoryComboBoxAction(); 122 private JPanel bottomButtonPanel; 123 private GTKDirectoryModel model = null; 124 private Action newFolderAction; 125 private boolean readOnly; 126 private boolean showDirectoryIcons; 127 private boolean showFileIcons; 128 private GTKFileView fileView = new GTKFileView(); 129 private PropertyChangeListener gtkFCPropertyChangeListener; 130 private Action approveSelectionAction = new GTKApproveSelectionAction(); 131 private GTKDirectoryListModel directoryListModel; 132 133 public GTKFileChooserUI(JFileChooser filechooser) { 134 super(filechooser); 135 } 136 137 protected ActionMap createActionMap() { 138 ActionMap map = new ActionMapUIResource(); 139 map.put("approveSelection", getApproveSelectionAction()); 140 map.put("cancelSelection", getCancelSelectionAction()); 141 map.put("Go Up", getChangeToParentDirectoryAction()); 142 map.put("fileNameCompletion", getFileNameCompletionAction()); 143 return map; 144 } 145 146 public String getFileName() { 147 JFileChooser fc = getFileChooser(); 148 String typedInName = fileNameTextField != null ? 149 fileNameTextField.getText() : null; 150 151 if (!fc.isMultiSelectionEnabled()) { 152 return typedInName; 153 } 154 155 int mode = fc.getFileSelectionMode(); 156 JList list = mode == JFileChooser.DIRECTORIES_ONLY ? 157 directoryList : fileList; 158 Object[] files = list.getSelectedValues(); 159 int len = files.length; 160 Vector<String> result = new Vector<String>(len + 1); 161 162 // we return all selected file names 163 for (int i = 0; i < len; i++) { 164 File file = (File)files[i]; 165 result.add(file.getName()); 166 } 167 // plus the file name typed into the text field, if not already there 168 if (typedInName != null && !result.contains(typedInName)) { 169 result.add(typedInName); 170 } 171 172 StringBuffer buf = new StringBuffer(); 173 len = result.size(); 174 175 // construct the resulting string 176 for (int i=0; i<len; i++) { 177 if (i > 0) { 178 buf.append(" "); 179 } 180 if (len > 1) { 181 buf.append("\""); 182 } 183 buf.append(result.get(i)); 184 if (len > 1) { 185 buf.append("\""); 186 } 187 } 188 return buf.toString(); 189 } 190 191 public void setFileName(String fileName) { 192 if (fileNameTextField != null) { 193 fileNameTextField.setText(fileName); 194 } 195 } 196 197 // public String getDirectoryName() { 198 // return pathField.getText(); 199 // } 200 201 public void setDirectoryName(String dirname) { 202 pathField.setText(dirname); 203 } 204 205 public void ensureFileIsVisible(JFileChooser fc, File f) { 206 // PENDING 207 } 208 209 public void rescanCurrentDirectory(JFileChooser fc) { 210 getModel().validateFileCache(); 211 } 212 213 public JPanel getAccessoryPanel() { 214 return accessoryPanel; 215 } 216 217 // *********************** 218 // * FileView operations * 219 // *********************** 220 221 public FileView getFileView(JFileChooser fc) { 222 return fileView; 223 } 224 225 private class GTKFileView extends BasicFileView { 226 public GTKFileView() { 227 iconCache = null; 228 } 229 230 public void clearIconCache() { 231 } 232 233 public Icon getCachedIcon(File f) { 234 return null; 235 } 236 237 public void cacheIcon(File f, Icon i) { 238 } 239 240 public Icon getIcon(File f) { 241 return (f != null && f.isDirectory()) ? directoryIcon : fileIcon; 242 } 243 } 244 245 246 private void updateDefaultButton() { 247 JFileChooser filechooser = getFileChooser(); 248 JRootPane root = SwingUtilities.getRootPane(filechooser); 249 if (root == null) { 250 return; 251 } 252 253 if (filechooser.getControlButtonsAreShown()) { 254 if (root.getDefaultButton() == null) { 255 root.setDefaultButton(getApproveButton(filechooser)); 256 getCancelButton(filechooser).setDefaultCapable(false); 257 } 258 } else { 259 if (root.getDefaultButton() == getApproveButton(filechooser)) { 260 root.setDefaultButton(null); 261 } 262 } 263 } 264 265 protected void doSelectedFileChanged(PropertyChangeEvent e) { 266 super.doSelectedFileChanged(e); 267 File f = (File) e.getNewValue(); 268 if (f != null) { 269 setFileName(getFileChooser().getName(f)); 270 } 271 } 272 273 protected void doDirectoryChanged(PropertyChangeEvent e) { 274 directoryList.clearSelection(); 275 ListSelectionModel sm = directoryList.getSelectionModel(); 276 if (sm instanceof DefaultListSelectionModel) { 277 ((DefaultListSelectionModel)sm).moveLeadSelectionIndex(0); 278 sm.setAnchorSelectionIndex(0); 279 } 280 fileList.clearSelection(); 281 sm = fileList.getSelectionModel(); 282 if (sm instanceof DefaultListSelectionModel) { 283 ((DefaultListSelectionModel)sm).moveLeadSelectionIndex(0); 284 sm.setAnchorSelectionIndex(0); 285 } 286 287 File currentDirectory = getFileChooser().getCurrentDirectory(); 288 if (currentDirectory != null) { 289 try { 290 setDirectoryName(ShellFolder.getNormalizedFile((File)e.getNewValue()).getPath()); 291 } catch (IOException ioe) { 292 setDirectoryName(((File)e.getNewValue()).getAbsolutePath()); 293 } 294 if ((getFileChooser().getFileSelectionMode() == JFileChooser.DIRECTORIES_ONLY) && !getFileChooser().isMultiSelectionEnabled()) { 295 setFileName(pathField.getText()); 296 } 297 directoryComboBoxModel.addItem(currentDirectory); 298 directoryListModel.directoryChanged(); 299 } 300 super.doDirectoryChanged(e); 301 } 302 303 protected void doAccessoryChanged(PropertyChangeEvent e) { 304 if (getAccessoryPanel() != null) { 305 if (e.getOldValue() != null) { 306 getAccessoryPanel().remove((JComponent)e.getOldValue()); 307 } 308 JComponent accessory = (JComponent)e.getNewValue(); 309 if (accessory != null) { 310 getAccessoryPanel().add(accessory, BorderLayout.CENTER); 311 getAccessoryPanel().setPreferredSize(accessory.getPreferredSize()); 312 getAccessoryPanel().setMaximumSize(MAX_SIZE); 313 } else { 314 getAccessoryPanel().setPreferredSize(ZERO_ACC_SIZE); 315 getAccessoryPanel().setMaximumSize(ZERO_ACC_SIZE); 316 } 317 } 318 } 319 320 protected void doFileSelectionModeChanged(PropertyChangeEvent e) { 321 directoryList.clearSelection(); 322 rightPanel.setVisible(((Integer)e.getNewValue()).intValue() != JFileChooser.DIRECTORIES_ONLY); 323 324 super.doFileSelectionModeChanged(e); 325 } 326 327 protected void doMultiSelectionChanged(PropertyChangeEvent e) { 328 if (getFileChooser().isMultiSelectionEnabled()) { 329 fileList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 330 } else { 331 fileList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 332 fileList.clearSelection(); 333 } 334 335 super.doMultiSelectionChanged(e); 336 } 337 338 protected void doControlButtonsChanged(PropertyChangeEvent e) { 339 super.doControlButtonsChanged(e); 340 341 JFileChooser filechooser = getFileChooser(); 342 if (filechooser.getControlButtonsAreShown()) { 343 filechooser.add(bottomButtonPanel, BorderLayout.SOUTH); 344 } else { 345 filechooser.remove(bottomButtonPanel); 346 } 347 updateDefaultButton(); 348 } 349 350 protected void doAncestorChanged(PropertyChangeEvent e) { 351 if (e.getOldValue() == null && e.getNewValue() != null) { 352 // Ancestor was added, set initial focus 353 fileNameTextField.selectAll(); 354 fileNameTextField.requestFocus(); 355 updateDefaultButton(); 356 } 357 358 super.doAncestorChanged(e); 359 } 360 361 362 363 // ******************************************** 364 // ************ Create Listeners ************** 365 // ******************************************** 366 367 public ListSelectionListener createListSelectionListener(JFileChooser fc) { 368 return new SelectionListener(); 369 } 370 371 class DoubleClickListener extends MouseAdapter { 372 JList list; 373 public DoubleClickListener(JList list) { 374 this.list = list; 375 } 376 377 public void mouseClicked(MouseEvent e) { 378 if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2) { 379 int index = list.locationToIndex(e.getPoint()); 380 if (index >= 0) { 381 File f = (File) list.getModel().getElementAt(index); 382 try { 383 // Strip trailing ".." 384 f = ShellFolder.getNormalizedFile(f); 385 } catch (IOException ex) { 386 // That's ok, we'll use f as is 387 } 388 if (getFileChooser().isTraversable(f)) { 389 list.clearSelection(); 390 if (getFileChooser().getCurrentDirectory().equals(f)){ 391 rescanCurrentDirectory(getFileChooser()); 392 } else { 393 getFileChooser().setCurrentDirectory(f); 394 } 395 } else { 396 getFileChooser().approveSelection(); 397 } 398 } 399 } 400 } 401 402 public void mouseEntered(MouseEvent evt) { 403 if (list != null) { 404 TransferHandler th1 = getFileChooser().getTransferHandler(); 405 TransferHandler th2 = list.getTransferHandler(); 406 if (th1 != th2) { 407 list.setTransferHandler(th1); 408 } 409 if (getFileChooser().getDragEnabled() != list.getDragEnabled()) { 410 list.setDragEnabled(getFileChooser().getDragEnabled()); 411 } 412 } 413 } 414 } 415 416 protected MouseListener createDoubleClickListener(JFileChooser fc, JList list) { 417 return new DoubleClickListener(list); 418 } 419 420 421 422 protected class SelectionListener implements ListSelectionListener { 423 public void valueChanged(ListSelectionEvent e) { 424 if (!e.getValueIsAdjusting()) { 425 JFileChooser chooser = getFileChooser(); 426 JList list = (JList) e.getSource(); 427 428 if (chooser.isMultiSelectionEnabled()) { 429 File[] files = null; 430 Object[] objects = list.getSelectedValues(); 431 if (objects != null) { 432 if (objects.length == 1 433 && ((File)objects[0]).isDirectory() 434 && chooser.isTraversable(((File)objects[0])) 435 && (chooser.getFileSelectionMode() != JFileChooser.DIRECTORIES_ONLY 436 || !chooser.getFileSystemView().isFileSystem(((File)objects[0])))) { 437 setDirectorySelected(true); 438 setDirectory(((File)objects[0])); 439 } else { 440 ArrayList<File> fList = new ArrayList<File>(objects.length); 441 for (Object object : objects) { 442 File f = (File) object; 443 if ((chooser.isFileSelectionEnabled() && f.isFile()) 444 || (chooser.isDirectorySelectionEnabled() && f.isDirectory())) { 445 fList.add(f); 446 } 447 } 448 if (fList.size() > 0) { 449 files = fList.toArray(new File[fList.size()]); 450 } 451 setDirectorySelected(false); 452 } 453 } 454 chooser.setSelectedFiles(files); 455 } else { 456 File file = (File)list.getSelectedValue(); 457 if (file != null 458 && file.isDirectory() 459 && chooser.isTraversable(file) 460 && (chooser.getFileSelectionMode() == JFileChooser.FILES_ONLY 461 || !chooser.getFileSystemView().isFileSystem(file))) { 462 463 setDirectorySelected(true); 464 setDirectory(file); 465 } else { 466 setDirectorySelected(false); 467 if (file != null) { 468 chooser.setSelectedFile(file); 469 } 470 } 471 } 472 } 473 } 474 } 475 476 477 // 478 // ComponentUI Interface Implementation methods 479 // 480 public static ComponentUI createUI(JComponent c) { 481 return new GTKFileChooserUI((JFileChooser)c); 482 } 483 484 public void installUI(JComponent c) { 485 accessoryPanel = new JPanel(new BorderLayout(10, 10)); 486 accessoryPanel.setName("GTKFileChooser.accessoryPanel"); 487 488 super.installUI(c); 489 } 490 491 public void uninstallUI(JComponent c) { 492 c.removePropertyChangeListener(filterComboBoxModel); 493 super.uninstallUI(c); 494 495 if (accessoryPanel != null) { 496 accessoryPanel.removeAll(); 497 } 498 accessoryPanel = null; 499 getFileChooser().removeAll(); 500 } 501 502 public void installComponents(JFileChooser fc) { 503 super.installComponents(fc); 504 505 boolean leftToRight = fc.getComponentOrientation().isLeftToRight(); 506 507 fc.setLayout(new BorderLayout()); 508 fc.setAlignmentX(JComponent.CENTER_ALIGNMENT); 509 510 // Top row of buttons 511 JPanel topButtonPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0)); 512 topButtonPanel.setBorder(new EmptyBorder(10, 10, 0, 10)); 513 topButtonPanel.setName("GTKFileChooser.topButtonPanel"); 514 515 if (!UIManager.getBoolean("FileChooser.readOnly")) { 516 JButton newFolderButton = new JButton(getNewFolderAction()); 517 newFolderButton.setName("GTKFileChooser.newFolderButton"); 518 newFolderButton.setMnemonic(newFolderButtonMnemonic); 519 newFolderButton.setToolTipText(newFolderButtonToolTipText); 520 newFolderButton.setText(newFolderButtonText); 521 topButtonPanel.add(newFolderButton); 522 } 523 JButton deleteFileButton = new JButton(deleteFileButtonText); 524 deleteFileButton.setName("GTKFileChooser.deleteFileButton"); 525 deleteFileButton.setMnemonic(deleteFileButtonMnemonic); 526 deleteFileButton.setToolTipText(deleteFileButtonToolTipText); 527 deleteFileButton.setEnabled(false); 528 topButtonPanel.add(deleteFileButton); 529 530 RenameFileAction rfa = new RenameFileAction(); 531 JButton renameFileButton = new JButton(rfa); 532 if (readOnly) { 533 rfa.setEnabled(false); 534 } 535 renameFileButton.setText(renameFileButtonText); 536 renameFileButton.setName("GTKFileChooser.renameFileButton"); 537 renameFileButton.setMnemonic(renameFileButtonMnemonic); 538 renameFileButton.setToolTipText(renameFileButtonToolTipText); 539 topButtonPanel.add(renameFileButton); 540 541 fc.add(topButtonPanel, BorderLayout.NORTH); 542 543 544 JPanel interior = new JPanel(); 545 interior.setBorder(new EmptyBorder(0, 10, 10, 10)); 546 interior.setName("GTKFileChooser.interiorPanel"); 547 align(interior); 548 interior.setLayout(new BoxLayout(interior, BoxLayout.PAGE_AXIS)); 549 550 fc.add(interior, BorderLayout.CENTER); 551 552 @SuppressWarnings("serial") // anonymous class 553 JPanel comboBoxPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 554 0, 0) { 555 public void layoutContainer(Container target) { 556 super.layoutContainer(target); 557 JComboBox comboBox = directoryComboBox; 558 if (comboBox.getWidth() > target.getWidth()) { 559 comboBox.setBounds(0, comboBox.getY(), target.getWidth(), 560 comboBox.getHeight()); 561 } 562 } 563 }); 564 comboBoxPanel.setBorder(new EmptyBorder(0, 0, 4, 0)); 565 comboBoxPanel.setName("GTKFileChooser.directoryComboBoxPanel"); 566 // CurrentDir ComboBox 567 directoryComboBoxModel = createDirectoryComboBoxModel(fc); 568 directoryComboBox = new JComboBox(directoryComboBoxModel); 569 directoryComboBox.setName("GTKFileChooser.directoryComboBox"); 570 directoryComboBox.putClientProperty( "JComboBox.lightweightKeyboardNavigation", "Lightweight" ); 571 directoryComboBox.addActionListener(directoryComboBoxAction); 572 directoryComboBox.setMaximumRowCount(8); 573 comboBoxPanel.add(directoryComboBox); 574 interior.add(comboBoxPanel); 575 576 577 // CENTER: left, right, accessory 578 JPanel centerPanel = new JPanel(new BorderLayout()); 579 centerPanel.setName("GTKFileChooser.centerPanel"); 580 581 // SPLIT PANEL: left, right 582 JSplitPane splitPanel = new JSplitPane(); 583 splitPanel.setName("GTKFileChooser.splitPanel"); 584 splitPanel.setDividerLocation((PREF_SIZE.width-8)/2); 585 586 // left panel - Filter & directoryList 587 JPanel leftPanel = new JPanel(new GridBagLayout()); 588 leftPanel.setName("GTKFileChooser.directoryListPanel"); 589 590 // Add the Directory List 591 // Create a label that looks like button (should be a table header) 592 TableCellRenderer headerRenderer = new JTableHeader().getDefaultRenderer(); 593 JLabel directoryListLabel = 594 (JLabel)headerRenderer.getTableCellRendererComponent(null, foldersLabelText, 595 false, false, 0, 0); 596 directoryListLabel.setName("GTKFileChooser.directoryListLabel"); 597 leftPanel.add(directoryListLabel, new GridBagConstraints( 598 0, 0, 1, 1, 1, 0, GridBagConstraints.WEST, 599 GridBagConstraints.HORIZONTAL, 600 new Insets(0, 0, 0, 0), 0, 0)); 601 leftPanel.add(createDirectoryList(), new GridBagConstraints( 602 0, 1, 1, 1, 1, 1, GridBagConstraints.EAST, 603 GridBagConstraints.BOTH, 604 new Insets(0, 0, 0, 0), 0, 0)); 605 directoryListLabel.setDisplayedMnemonic(foldersLabelMnemonic); 606 directoryListLabel.setLabelFor(directoryList); 607 608 // create files list 609 rightPanel = new JPanel(new GridBagLayout()); 610 rightPanel.setName("GTKFileChooser.fileListPanel"); 611 612 headerRenderer = new JTableHeader().getDefaultRenderer(); 613 JLabel fileListLabel = 614 (JLabel)headerRenderer.getTableCellRendererComponent(null, filesLabelText, 615 false, false, 0, 0); 616 fileListLabel.setName("GTKFileChooser.fileListLabel"); 617 rightPanel.add(fileListLabel, new GridBagConstraints( 618 0, 0, 1, 1, 1, 0, GridBagConstraints.WEST, 619 GridBagConstraints.HORIZONTAL, 620 new Insets(0, 0, 0, 0), 0, 0)); 621 rightPanel.add(createFilesList(), new GridBagConstraints( 622 0, 1, 1, 1, 1, 1, GridBagConstraints.EAST, 623 GridBagConstraints.BOTH, 624 new Insets(0, 0, 0, 0), 0, 0)); 625 fileListLabel.setDisplayedMnemonic(filesLabelMnemonic); 626 fileListLabel.setLabelFor(fileList); 627 628 splitPanel.add(leftPanel, leftToRight ? JSplitPane.LEFT : JSplitPane.RIGHT); 629 splitPanel.add(rightPanel, leftToRight ? JSplitPane.RIGHT : JSplitPane.LEFT); 630 centerPanel.add(splitPanel, BorderLayout.CENTER); 631 632 JComponent accessoryPanel = getAccessoryPanel(); 633 JComponent accessory = fc.getAccessory(); 634 if (accessoryPanel != null) { 635 if (accessory == null) { 636 accessoryPanel.setPreferredSize(ZERO_ACC_SIZE); 637 accessoryPanel.setMaximumSize(ZERO_ACC_SIZE); 638 } else { 639 getAccessoryPanel().add(accessory, BorderLayout.CENTER); 640 accessoryPanel.setPreferredSize(accessory.getPreferredSize()); 641 accessoryPanel.setMaximumSize(MAX_SIZE); 642 } 643 align(accessoryPanel); 644 centerPanel.add(accessoryPanel, BorderLayout.AFTER_LINE_ENDS); 645 } 646 interior.add(centerPanel); 647 interior.add(Box.createRigidArea(vstrut10)); 648 649 JPanel pathFieldPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 650 0, 0)); 651 pathFieldPanel.setBorder(new EmptyBorder(0, 0, 4, 0)); 652 JLabel pathFieldLabel = new JLabel(pathLabelText); 653 pathFieldLabel.setName("GTKFileChooser.pathFieldLabel"); 654 pathFieldLabel.setDisplayedMnemonic(pathLabelMnemonic); 655 align(pathFieldLabel); 656 pathFieldPanel.add(pathFieldLabel); 657 pathFieldPanel.add(Box.createRigidArea(hstrut3)); 658 659 File currentDirectory = fc.getCurrentDirectory(); 660 String curDirName = null; 661 if (currentDirectory != null) { 662 curDirName = currentDirectory.getPath(); 663 } 664 @SuppressWarnings("serial") // anonymous class 665 JLabel tmp = new JLabel(curDirName) { 666 public Dimension getMaximumSize() { 667 Dimension d = super.getMaximumSize(); 668 d.height = getPreferredSize().height; 669 return d; 670 } 671 }; 672 pathField = tmp; 673 pathField.setName("GTKFileChooser.pathField"); 674 align(pathField); 675 pathFieldPanel.add(pathField); 676 interior.add(pathFieldPanel); 677 678 // add the fileName field 679 @SuppressWarnings("serial") // anonymous class 680 JTextField tmp2 = new JTextField() { 681 public Dimension getMaximumSize() { 682 Dimension d = super.getMaximumSize(); 683 d.height = getPreferredSize().height; 684 return d; 685 } 686 }; 687 fileNameTextField = tmp2; 688 689 pathFieldLabel.setLabelFor(fileNameTextField); 690 691 Set<AWTKeyStroke> forwardTraversalKeys = fileNameTextField.getFocusTraversalKeys( 692 KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS); 693 forwardTraversalKeys = new HashSet<AWTKeyStroke>(forwardTraversalKeys); 694 forwardTraversalKeys.remove(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0)); 695 fileNameTextField.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forwardTraversalKeys); 696 697 fileNameTextField.setName("GTKFileChooser.fileNameTextField"); 698 fileNameTextField.getActionMap().put("fileNameCompletionAction", getFileNameCompletionAction()); 699 fileNameTextField.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), "fileNameCompletionAction"); 700 interior.add(fileNameTextField); 701 702 // Add the filter combo box 703 JPanel panel = new JPanel(); 704 panel.setLayout(new FlowLayout(FlowLayout.LEADING, 0, 0)); 705 panel.setBorder(new EmptyBorder(0, 0, 4, 0)); 706 JLabel filterLabel = new JLabel(filterLabelText); 707 filterLabel.setName("GTKFileChooser.filterLabel"); 708 filterLabel.setDisplayedMnemonic(filterLabelMnemonic); 709 panel.add(filterLabel); 710 711 filterComboBoxModel = createFilterComboBoxModel(); 712 fc.addPropertyChangeListener(filterComboBoxModel); 713 filterComboBox = new JComboBox(filterComboBoxModel); 714 filterComboBox.setRenderer(createFilterComboBoxRenderer()); 715 filterLabel.setLabelFor(filterComboBox); 716 717 interior.add(Box.createRigidArea(vstrut10)); 718 interior.add(panel); 719 interior.add(filterComboBox); 720 721 // Add buttons 722 bottomButtonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING)); 723 bottomButtonPanel.setName("GTKFileChooser.bottomButtonPanel"); 724 align(bottomButtonPanel); 725 726 JPanel pnButtons = new JPanel(new GridLayout(1, 2, 5, 0)); 727 728 JButton cancelButton = getCancelButton(fc); 729 align(cancelButton); 730 cancelButton.setMargin(buttonMargin); 731 pnButtons.add(cancelButton); 732 733 JButton approveButton = getApproveButton(fc); 734 align(approveButton); 735 approveButton.setMargin(buttonMargin); 736 pnButtons.add(approveButton); 737 738 bottomButtonPanel.add(pnButtons); 739 740 if (fc.getControlButtonsAreShown()) { 741 fc.add(bottomButtonPanel, BorderLayout.SOUTH); 742 } 743 } 744 745 protected void installListeners(JFileChooser fc) { 746 super.installListeners(fc); 747 748 gtkFCPropertyChangeListener = new GTKFCPropertyChangeListener(); 749 fc.addPropertyChangeListener(gtkFCPropertyChangeListener); 750 } 751 752 private int getMnemonic(String key, Locale l) { 753 return SwingUtilities2.getUIDefaultsInt(key, l); 754 } 755 756 protected void uninstallListeners(JFileChooser fc) { 757 super.uninstallListeners(fc); 758 759 if (gtkFCPropertyChangeListener != null) { 760 fc.removePropertyChangeListener(gtkFCPropertyChangeListener); 761 } 762 } 763 764 private class GTKFCPropertyChangeListener implements PropertyChangeListener { 765 public void propertyChange(PropertyChangeEvent e) { 766 String prop = e.getPropertyName(); 767 if (prop.equals("GTKFileChooser.showDirectoryIcons")) { 768 showDirectoryIcons = Boolean.TRUE.equals(e.getNewValue()); 769 } else if (prop.equals("GTKFileChooser.showFileIcons")) { 770 showFileIcons = Boolean.TRUE.equals(e.getNewValue()); 771 } 772 } 773 } 774 775 protected void installDefaults(JFileChooser fc) { 776 super.installDefaults(fc); 777 readOnly = UIManager.getBoolean("FileChooser.readOnly"); 778 showDirectoryIcons = 779 Boolean.TRUE.equals(fc.getClientProperty("GTKFileChooser.showDirectoryIcons")); 780 showFileIcons = 781 Boolean.TRUE.equals(fc.getClientProperty("GTKFileChooser.showFileIcons")); 782 } 783 784 protected void installIcons(JFileChooser fc) { 785 directoryIcon = UIManager.getIcon("FileView.directoryIcon"); 786 fileIcon = UIManager.getIcon("FileView.fileIcon"); 787 } 788 789 protected void installStrings(JFileChooser fc) { 790 super.installStrings(fc); 791 792 Locale l = fc.getLocale(); 793 794 newFolderDialogText = UIManager.getString("FileChooser.newFolderDialogText", l); 795 newFolderErrorText = UIManager.getString("FileChooser.newFolderErrorText",l); 796 newFolderErrorSeparator = UIManager.getString("FileChooser.newFolderErrorSeparator",l); 797 newFolderButtonText = UIManager.getString("FileChooser.newFolderButtonText", l); 798 newFolderNoDirectoryErrorTitleText = UIManager.getString("FileChooser.newFolderNoDirectoryErrorTitleText", l); 799 newFolderNoDirectoryErrorText = UIManager.getString("FileChooser.newFolderNoDirectoryErrorText", l); 800 deleteFileButtonText = UIManager.getString("FileChooser.deleteFileButtonText", l); 801 renameFileButtonText = UIManager.getString("FileChooser.renameFileButtonText", l); 802 803 newFolderButtonMnemonic = getMnemonic("FileChooser.newFolderButtonMnemonic", l); 804 deleteFileButtonMnemonic = getMnemonic("FileChooser.deleteFileButtonMnemonic", l); 805 renameFileButtonMnemonic = getMnemonic("FileChooser.renameFileButtonMnemonic", l); 806 807 newFolderButtonToolTipText = UIManager.getString("FileChooser.newFolderButtonToolTipText", l); 808 deleteFileButtonToolTipText = UIManager.getString("FileChooser.deleteFileButtonToolTipText", l); 809 renameFileButtonToolTipText = UIManager.getString("FileChooser.renameFileButtonToolTipText", l); 810 811 renameFileDialogText = UIManager.getString("FileChooser.renameFileDialogText", l); 812 renameFileErrorTitle = UIManager.getString("FileChooser.renameFileErrorTitle", l); 813 renameFileErrorText = UIManager.getString("FileChooser.renameFileErrorText", l); 814 815 foldersLabelText = UIManager.getString("FileChooser.foldersLabelText",l); 816 foldersLabelMnemonic = getMnemonic("FileChooser.foldersLabelMnemonic", l); 817 818 filesLabelText = UIManager.getString("FileChooser.filesLabelText",l); 819 filesLabelMnemonic = getMnemonic("FileChooser.filesLabelMnemonic", l); 820 821 pathLabelText = UIManager.getString("FileChooser.pathLabelText",l); 822 pathLabelMnemonic = getMnemonic("FileChooser.pathLabelMnemonic", l); 823 824 filterLabelText = UIManager.getString("FileChooser.filterLabelText", l); 825 filterLabelMnemonic = UIManager.getInt("FileChooser.filterLabelMnemonic"); 826 } 827 828 protected void uninstallStrings(JFileChooser fc) { 829 super.uninstallStrings(fc); 830 831 newFolderButtonText = null; 832 deleteFileButtonText = null; 833 renameFileButtonText = null; 834 835 newFolderButtonToolTipText = null; 836 deleteFileButtonToolTipText = null; 837 renameFileButtonToolTipText = null; 838 839 renameFileDialogText = null; 840 renameFileErrorTitle = null; 841 renameFileErrorText = null; 842 843 foldersLabelText = null; 844 filesLabelText = null; 845 846 pathLabelText = null; 847 848 newFolderDialogText = null; 849 newFolderErrorText = null; 850 newFolderErrorSeparator = null; 851 } 852 853 protected JScrollPane createFilesList() { 854 fileList = new JList(); 855 fileList.setName("GTKFileChooser.fileList"); 856 fileList.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, filesLabelText); 857 858 if (getFileChooser().isMultiSelectionEnabled()) { 859 fileList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 860 } else { 861 fileList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 862 } 863 864 fileList.setModel(new GTKFileListModel()); 865 fileList.getSelectionModel().removeSelectionInterval(0, 0); 866 fileList.setCellRenderer(new FileCellRenderer()); 867 fileList.addListSelectionListener(createListSelectionListener(getFileChooser())); 868 fileList.addMouseListener(createDoubleClickListener(getFileChooser(), fileList)); 869 align(fileList); 870 JScrollPane scrollpane = new JScrollPane(fileList); 871 scrollpane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 872 scrollpane.setName("GTKFileChooser.fileListScrollPane"); 873 scrollpane.setPreferredSize(prefListSize); 874 scrollpane.setMaximumSize(MAX_SIZE); 875 align(scrollpane); 876 return scrollpane; 877 } 878 879 protected JScrollPane createDirectoryList() { 880 directoryList = new JList(); 881 directoryList.setName("GTKFileChooser.directoryList"); 882 directoryList.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, foldersLabelText); 883 align(directoryList); 884 885 directoryList.setCellRenderer(new DirectoryCellRenderer()); 886 directoryListModel = new GTKDirectoryListModel(); 887 directoryList.getSelectionModel().removeSelectionInterval(0, 0); 888 directoryList.setModel(directoryListModel); 889 directoryList.addMouseListener(createDoubleClickListener(getFileChooser(), directoryList)); 890 directoryList.addListSelectionListener(createListSelectionListener(getFileChooser())); 891 892 JScrollPane scrollpane = new JScrollPane(directoryList); 893 scrollpane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 894 scrollpane.setName("GTKFileChooser.directoryListScrollPane"); 895 scrollpane.setMaximumSize(MAX_SIZE); 896 scrollpane.setPreferredSize(prefListSize); 897 align(scrollpane); 898 return scrollpane; 899 } 900 901 protected void createModel() { 902 model = new GTKDirectoryModel(); 903 } 904 905 public BasicDirectoryModel getModel() { 906 return model; 907 } 908 909 public Action getApproveSelectionAction() { 910 return approveSelectionAction; 911 } 912 913 @SuppressWarnings("serial") // Superclass is not serializable across versions 914 private class GTKDirectoryModel extends BasicDirectoryModel { 915 FileSystemView fsv; 916 private Comparator<File> fileComparator = new Comparator<File>() { 917 public int compare(File o, File o1) { 918 return fsv.getSystemDisplayName(o).compareTo(fsv.getSystemDisplayName(o1)); 919 } 920 }; 921 922 public GTKDirectoryModel() { 923 super(getFileChooser()); 924 } 925 926 protected void sort(Vector<? extends File> v) { 927 fsv = getFileChooser().getFileSystemView(); 928 Collections.sort(v, fileComparator); 929 } 930 } 931 932 @SuppressWarnings("serial") // Superclass is not serializable across versions 933 protected class GTKDirectoryListModel extends AbstractListModel implements ListDataListener { 934 File curDir; 935 public GTKDirectoryListModel() { 936 getModel().addListDataListener(this); 937 directoryChanged(); 938 } 939 940 public int getSize() { 941 return getModel().getDirectories().size() + 1; 942 } 943 944 public Object getElementAt(int index) { 945 return index > 0 ? getModel().getDirectories().elementAt(index - 1): 946 curDir; 947 } 948 949 public void intervalAdded(ListDataEvent e) { 950 fireIntervalAdded(this, e.getIndex0(), e.getIndex1()); 951 } 952 953 public void intervalRemoved(ListDataEvent e) { 954 fireIntervalRemoved(this, e.getIndex0(), e.getIndex1()); 955 } 956 957 // PENDING - this is inefficient - should sent out 958 // incremental adjustment values instead of saying that the 959 // whole list has changed. 960 public void fireContentsChanged() { 961 fireContentsChanged(this, 0, getModel().getDirectories().size()-1); 962 } 963 964 // PENDING - fire the correct interval changed - currently sending 965 // out that everything has changed 966 public void contentsChanged(ListDataEvent e) { 967 fireContentsChanged(); 968 } 969 970 private void directoryChanged() { 971 curDir = getFileChooser().getFileSystemView().createFileObject( 972 getFileChooser().getCurrentDirectory(), "."); 973 } 974 } 975 976 @SuppressWarnings("serial") // Superclass is not serializable across versions 977 protected class GTKFileListModel extends AbstractListModel implements ListDataListener { 978 public GTKFileListModel() { 979 getModel().addListDataListener(this); 980 } 981 982 public int getSize() { 983 return getModel().getFiles().size(); 984 } 985 986 public boolean contains(Object o) { 987 return getModel().getFiles().contains(o); 988 } 989 990 public int indexOf(Object o) { 991 return getModel().getFiles().indexOf(o); 992 } 993 994 public Object getElementAt(int index) { 995 return getModel().getFiles().elementAt(index); 996 } 997 998 public void intervalAdded(ListDataEvent e) { 999 fireIntervalAdded(this, e.getIndex0(), e.getIndex1()); 1000 } 1001 1002 public void intervalRemoved(ListDataEvent e) { 1003 fireIntervalRemoved(this, e.getIndex0(), e.getIndex1()); 1004 } 1005 1006 // PENDING - this is inefficient - should sent out 1007 // incremental adjustment values instead of saying that the 1008 // whole list has changed. 1009 public void fireContentsChanged() { 1010 fireContentsChanged(this, 0, getModel().getFiles().size()-1); 1011 } 1012 1013 // PENDING - fire the interval changed 1014 public void contentsChanged(ListDataEvent e) { 1015 fireContentsChanged(); 1016 } 1017 } 1018 1019 1020 @SuppressWarnings("serial") // Superclass is not serializable across versions 1021 protected class FileCellRenderer extends DefaultListCellRenderer { 1022 public Component getListCellRendererComponent(JList list, Object value, int index, 1023 boolean isSelected, boolean cellHasFocus) { 1024 1025 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 1026 setText(getFileChooser().getName((File) value)); 1027 if (showFileIcons) { 1028 setIcon(getFileChooser().getIcon((File)value)); 1029 } 1030 return this; 1031 } 1032 } 1033 1034 @SuppressWarnings("serial") // Superclass is not serializable across versions 1035 protected class DirectoryCellRenderer extends DefaultListCellRenderer { 1036 public Component getListCellRendererComponent(JList list, Object value, int index, 1037 boolean isSelected, boolean cellHasFocus) { 1038 1039 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 1040 1041 if (showDirectoryIcons) { 1042 setIcon(getFileChooser().getIcon((File)value)); 1043 setText(getFileChooser().getName((File)value)); 1044 } else { 1045 setText(getFileChooser().getName((File)value) + "/"); 1046 } 1047 return this; 1048 } 1049 } 1050 1051 public Dimension getPreferredSize(JComponent c) { 1052 Dimension prefSize = new Dimension(PREF_SIZE); 1053 JComponent accessory = getFileChooser().getAccessory(); 1054 if (accessory != null) { 1055 prefSize.width += accessory.getPreferredSize().width + 20; 1056 } 1057 Dimension d = c.getLayout().preferredLayoutSize(c); 1058 if (d != null) { 1059 return new Dimension(d.width < prefSize.width ? prefSize.width : d.width, 1060 d.height < prefSize.height ? prefSize.height : d.height); 1061 } else { 1062 return prefSize; 1063 } 1064 } 1065 1066 public Dimension getMinimumSize(JComponent x) { 1067 return new Dimension(MIN_SIZE); 1068 } 1069 1070 public Dimension getMaximumSize(JComponent x) { 1071 return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); 1072 } 1073 1074 protected void align(JComponent c) { 1075 c.setAlignmentX(JComponent.LEFT_ALIGNMENT); 1076 c.setAlignmentY(JComponent.TOP_ALIGNMENT); 1077 } 1078 1079 public Action getNewFolderAction() { 1080 if (newFolderAction == null) { 1081 newFolderAction = new NewFolderAction(); 1082 newFolderAction.setEnabled(!readOnly); 1083 } 1084 return newFolderAction; 1085 } 1086 1087 // 1088 // DataModel for DirectoryComboxbox 1089 // 1090 protected DirectoryComboBoxModel createDirectoryComboBoxModel(JFileChooser fc) { 1091 return new DirectoryComboBoxModel(); 1092 } 1093 1094 /** 1095 * Data model for a type-face selection combo-box. 1096 */ 1097 @SuppressWarnings("serial") // Superclass is not serializable across versions 1098 protected class DirectoryComboBoxModel extends AbstractListModel implements ComboBoxModel { 1099 Vector<File> directories = new Vector<File>(); 1100 File selectedDirectory = null; 1101 JFileChooser chooser = getFileChooser(); 1102 FileSystemView fsv = chooser.getFileSystemView(); 1103 1104 public DirectoryComboBoxModel() { 1105 // Add the current directory to the model, and make it the 1106 // selectedDirectory 1107 File dir = getFileChooser().getCurrentDirectory(); 1108 if (dir != null) { 1109 addItem(dir); 1110 } 1111 } 1112 1113 /** 1114 * Adds the directory to the model and sets it to be selected, 1115 * additionally clears out the previous selected directory and 1116 * the paths leading up to it, if any. 1117 */ 1118 private void addItem(File directory) { 1119 1120 if (directory == null) { 1121 return; 1122 } 1123 1124 int oldSize = directories.size(); 1125 directories.clear(); 1126 if (oldSize > 0) { 1127 fireIntervalRemoved(this, 0, oldSize); 1128 } 1129 1130 // Get the canonical (full) path. This has the side 1131 // benefit of removing extraneous chars from the path, 1132 // for example /foo/bar/ becomes /foo/bar 1133 File canonical; 1134 try { 1135 canonical = fsv.createFileObject(ShellFolder.getNormalizedFile(directory).getPath()); 1136 } catch (IOException e) { 1137 // Maybe drive is not ready. Can't abort here. 1138 canonical = directory; 1139 } 1140 1141 // create File instances of each directory leading up to the top 1142 File f = canonical; 1143 do { 1144 directories.add(f); 1145 } while ((f = f.getParentFile()) != null); 1146 int newSize = directories.size(); 1147 if (newSize > 0) { 1148 fireIntervalAdded(this, 0, newSize); 1149 } 1150 setSelectedItem(canonical); 1151 } 1152 1153 public void setSelectedItem(Object selectedDirectory) { 1154 this.selectedDirectory = (File)selectedDirectory; 1155 fireContentsChanged(this, -1, -1); 1156 } 1157 1158 public Object getSelectedItem() { 1159 return selectedDirectory; 1160 } 1161 1162 public int getSize() { 1163 return directories.size(); 1164 } 1165 1166 public Object getElementAt(int index) { 1167 return directories.elementAt(index); 1168 } 1169 } 1170 1171 /** 1172 * Acts when DirectoryComboBox has changed the selected item. 1173 */ 1174 @SuppressWarnings("serial") // Superclass is not serializable across versions 1175 protected class DirectoryComboBoxAction extends AbstractAction { 1176 protected DirectoryComboBoxAction() { 1177 super("DirectoryComboBoxAction"); 1178 } 1179 1180 public void actionPerformed(ActionEvent e) { 1181 File f = (File)directoryComboBox.getSelectedItem(); 1182 getFileChooser().setCurrentDirectory(f); 1183 } 1184 } 1185 1186 /** 1187 * Creates a new folder. 1188 */ 1189 @SuppressWarnings("serial") // Superclass is not serializable across versions 1190 private class NewFolderAction extends AbstractAction { 1191 protected NewFolderAction() { 1192 super(FilePane.ACTION_NEW_FOLDER); 1193 } 1194 public void actionPerformed(ActionEvent e) { 1195 if (readOnly) { 1196 return; 1197 } 1198 JFileChooser fc = getFileChooser(); 1199 File currentDirectory = fc.getCurrentDirectory(); 1200 String dirName = JOptionPane.showInputDialog(fc, 1201 newFolderDialogText, newFolderButtonText, 1202 JOptionPane.PLAIN_MESSAGE); 1203 1204 if (dirName != null) { 1205 if (!currentDirectory.exists()) { 1206 JOptionPane.showMessageDialog(fc, 1207 MessageFormat.format(newFolderNoDirectoryErrorText, dirName), 1208 newFolderNoDirectoryErrorTitleText, JOptionPane.ERROR_MESSAGE); 1209 return; 1210 } 1211 1212 File newDir = fc.getFileSystemView().createFileObject 1213 (currentDirectory, dirName); 1214 if (newDir == null || !newDir.mkdir()) { 1215 JOptionPane.showMessageDialog(fc, 1216 newFolderErrorText + newFolderErrorSeparator + " \"" + 1217 dirName + "\"", 1218 newFolderErrorText, JOptionPane.ERROR_MESSAGE); 1219 } 1220 fc.rescanCurrentDirectory(); 1221 } 1222 } 1223 } 1224 1225 @SuppressWarnings("serial") // Superclass is not serializable across versions 1226 private class GTKApproveSelectionAction extends ApproveSelectionAction { 1227 public void actionPerformed(ActionEvent e) { 1228 if (isDirectorySelected()) { 1229 File dir = getDirectory(); 1230 try { 1231 // Strip trailing ".." 1232 if (dir != null) { 1233 dir = ShellFolder.getNormalizedFile(dir); 1234 } 1235 } catch (IOException ex) { 1236 // Ok, use f as is 1237 } 1238 if (getFileChooser().getCurrentDirectory().equals(dir)) { 1239 directoryList.clearSelection(); 1240 fileList.clearSelection(); 1241 ListSelectionModel sm = fileList.getSelectionModel(); 1242 if (sm instanceof DefaultListSelectionModel) { 1243 ((DefaultListSelectionModel)sm).moveLeadSelectionIndex(0); 1244 sm.setAnchorSelectionIndex(0); 1245 } 1246 rescanCurrentDirectory(getFileChooser()); 1247 return; 1248 } 1249 } 1250 super.actionPerformed(e); 1251 } 1252 } 1253 1254 /** 1255 * Renames file 1256 */ 1257 @SuppressWarnings("serial") // Superclass is not serializable across versions 1258 private class RenameFileAction extends AbstractAction { 1259 protected RenameFileAction() { 1260 super(FilePane.ACTION_EDIT_FILE_NAME); 1261 } 1262 public void actionPerformed(ActionEvent e) { 1263 if (getFileName().equals("")) { 1264 return; 1265 } 1266 JFileChooser fc = getFileChooser(); 1267 File currentDirectory = fc.getCurrentDirectory(); 1268 String newFileName = (String) JOptionPane.showInputDialog 1269 (fc, new MessageFormat(renameFileDialogText).format 1270 (new Object[] { getFileName() }), 1271 renameFileButtonText, JOptionPane.PLAIN_MESSAGE, null, null, 1272 getFileName()); 1273 1274 if (newFileName != null) { 1275 File oldFile = fc.getFileSystemView().createFileObject 1276 (currentDirectory, getFileName()); 1277 File newFile = fc.getFileSystemView().createFileObject 1278 (currentDirectory, newFileName); 1279 if (oldFile == null || newFile == null || 1280 !getModel().renameFile(oldFile, newFile)) { 1281 JOptionPane.showMessageDialog(fc, 1282 new MessageFormat(renameFileErrorText). 1283 format(new Object[] { getFileName(), newFileName}), 1284 renameFileErrorTitle, JOptionPane.ERROR_MESSAGE); 1285 } else { 1286 setFileName(getFileChooser().getName(newFile)); 1287 fc.rescanCurrentDirectory(); 1288 } 1289 } 1290 } 1291 } 1292 1293 // 1294 // Renderer for Filter ComboBox 1295 // 1296 protected FilterComboBoxRenderer createFilterComboBoxRenderer() { 1297 return new FilterComboBoxRenderer(); 1298 } 1299 1300 /** 1301 * Render different filters 1302 */ 1303 @SuppressWarnings("serial") // Superclass is not serializable across versions 1304 public class FilterComboBoxRenderer extends DefaultListCellRenderer implements UIResource { 1305 public String getName() { 1306 // As SynthComboBoxRenderer's are asked for a size BEFORE they 1307 // are parented getName is overriden to force the name to be 1308 // ComboBox.renderer if it isn't set. If we didn't do this the 1309 // wrong style could be used for size calculations. 1310 String name = super.getName(); 1311 if (name == null) { 1312 return "ComboBox.renderer"; 1313 } 1314 return name; 1315 } 1316 1317 public Component getListCellRendererComponent(JList list, Object value, 1318 int index, boolean isSelected, 1319 boolean cellHasFocus) { 1320 1321 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 1322 1323 setName("ComboBox.listRenderer"); 1324 1325 if (value != null) { 1326 if (value instanceof FileFilter) { 1327 setText(((FileFilter) value).getDescription()); 1328 } 1329 } else { 1330 setText(""); 1331 } 1332 1333 return this; 1334 } 1335 } 1336 1337 // 1338 // DataModel for Filter Combobox 1339 // 1340 protected FilterComboBoxModel createFilterComboBoxModel() { 1341 return new FilterComboBoxModel(); 1342 } 1343 1344 /** 1345 * Data model for filter combo-box. 1346 */ 1347 @SuppressWarnings("serial") // JDK implementation class 1348 protected class FilterComboBoxModel extends AbstractListModel 1349 implements ComboBoxModel, PropertyChangeListener { 1350 protected FileFilter[] filters; 1351 1352 protected FilterComboBoxModel() { 1353 super(); 1354 filters = getFileChooser().getChoosableFileFilters(); 1355 } 1356 1357 public void propertyChange(PropertyChangeEvent e) { 1358 String prop = e.getPropertyName(); 1359 if (prop == JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY) { 1360 filters = (FileFilter[]) e.getNewValue(); 1361 fireContentsChanged(this, -1, -1); 1362 } else if (prop == JFileChooser.FILE_FILTER_CHANGED_PROPERTY) { 1363 fireContentsChanged(this, -1, -1); 1364 } 1365 } 1366 1367 public void setSelectedItem(Object filter) { 1368 if (filter != null) { 1369 getFileChooser().setFileFilter((FileFilter) filter); 1370 fireContentsChanged(this, -1, -1); 1371 } 1372 } 1373 1374 public Object getSelectedItem() { 1375 // Ensure that the current filter is in the list. 1376 // NOTE: we shouldnt' have to do this, since JFileChooser adds 1377 // the filter to the choosable filters list when the filter 1378 // is set. Lets be paranoid just in case someone overrides 1379 // setFileFilter in JFileChooser. 1380 FileFilter currentFilter = getFileChooser().getFileFilter(); 1381 boolean found = false; 1382 if (currentFilter != null) { 1383 for (FileFilter filter : filters) { 1384 if (filter == currentFilter) { 1385 found = true; 1386 } 1387 } 1388 if (found == false) { 1389 getFileChooser().addChoosableFileFilter(currentFilter); 1390 } 1391 } 1392 return getFileChooser().getFileFilter(); 1393 } 1394 1395 public int getSize() { 1396 if (filters != null) { 1397 return filters.length; 1398 } else { 1399 return 0; 1400 } 1401 } 1402 1403 public Object getElementAt(int index) { 1404 if (index > getSize() - 1) { 1405 // This shouldn't happen. Try to recover gracefully. 1406 return getFileChooser().getFileFilter(); 1407 } 1408 if (filters != null) { 1409 return filters[index]; 1410 } else { 1411 return null; 1412 } 1413 } 1414 } 1415 }