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<FileFilter> filterComboBox; 86 private FilterComboBoxModel filterComboBoxModel; 87 88 // From Motif 89 90 private JPanel rightPanel; 91 private JList<File> directoryList; 92 private JList<File> 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<File> 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<File> 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 StringBuilder sb = new StringBuilder(); 173 len = result.size(); 174 175 // construct the resulting string 176 for (int i=0; i<len; i++) { 177 if (i > 0) { 178 sb.append(" "); 179 } 180 if (len > 1) { 181 sb.append("\""); 182 } 183 sb.append(result.get(i)); 184 if (len > 1) { 185 sb.append("\""); 186 } 187 } 188 return sb.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<File> 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 @Override 945 public File getElementAt(int index) { 946 return index > 0 ? getModel().getDirectories().elementAt(index - 1): 947 curDir; 948 } 949 950 public void intervalAdded(ListDataEvent e) { 951 fireIntervalAdded(this, e.getIndex0(), e.getIndex1()); 952 } 953 954 public void intervalRemoved(ListDataEvent e) { 955 fireIntervalRemoved(this, e.getIndex0(), e.getIndex1()); 956 } 957 958 // PENDING - this is inefficient - should sent out 959 // incremental adjustment values instead of saying that the 960 // whole list has changed. 961 public void fireContentsChanged() { 962 fireContentsChanged(this, 0, getModel().getDirectories().size()-1); 963 } 964 965 // PENDING - fire the correct interval changed - currently sending 966 // out that everything has changed 967 public void contentsChanged(ListDataEvent e) { 968 fireContentsChanged(); 969 } 970 971 private void directoryChanged() { 972 curDir = getFileChooser().getFileSystemView().createFileObject( 973 getFileChooser().getCurrentDirectory(), "."); 974 } 975 } 976 977 @SuppressWarnings("serial") // Superclass is not serializable across versions 978 protected class GTKFileListModel extends AbstractListModel<File> implements ListDataListener { 979 public GTKFileListModel() { 980 getModel().addListDataListener(this); 981 } 982 983 public int getSize() { 984 return getModel().getFiles().size(); 985 } 986 987 public boolean contains(Object o) { 988 return getModel().getFiles().contains(o); 989 } 990 991 public int indexOf(Object o) { 992 return getModel().getFiles().indexOf(o); 993 } 994 995 @Override 996 public File getElementAt(int index) { 997 return getModel().getFiles().elementAt(index); 998 } 999 1000 public void intervalAdded(ListDataEvent e) { 1001 fireIntervalAdded(this, e.getIndex0(), e.getIndex1()); 1002 } 1003 1004 public void intervalRemoved(ListDataEvent e) { 1005 fireIntervalRemoved(this, e.getIndex0(), e.getIndex1()); 1006 } 1007 1008 // PENDING - this is inefficient - should sent out 1009 // incremental adjustment values instead of saying that the 1010 // whole list has changed. 1011 public void fireContentsChanged() { 1012 fireContentsChanged(this, 0, getModel().getFiles().size()-1); 1013 } 1014 1015 // PENDING - fire the interval changed 1016 public void contentsChanged(ListDataEvent e) { 1017 fireContentsChanged(); 1018 } 1019 } 1020 1021 1022 @SuppressWarnings("serial") // Superclass is not serializable across versions 1023 protected class FileCellRenderer extends DefaultListCellRenderer { 1024 public Component getListCellRendererComponent(JList<?> list, Object value, int index, 1025 boolean isSelected, boolean cellHasFocus) { 1026 1027 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 1028 setText(getFileChooser().getName((File) value)); 1029 if (showFileIcons) { 1030 setIcon(getFileChooser().getIcon((File)value)); 1031 } 1032 return this; 1033 } 1034 } 1035 1036 @SuppressWarnings("serial") // Superclass is not serializable across versions 1037 protected class DirectoryCellRenderer extends DefaultListCellRenderer { 1038 public Component getListCellRendererComponent(JList<?> list, Object value, int index, 1039 boolean isSelected, boolean cellHasFocus) { 1040 1041 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 1042 1043 if (showDirectoryIcons) { 1044 setIcon(getFileChooser().getIcon((File)value)); 1045 setText(getFileChooser().getName((File)value)); 1046 } else { 1047 setText(getFileChooser().getName((File)value) + "/"); 1048 } 1049 return this; 1050 } 1051 } 1052 1053 public Dimension getPreferredSize(JComponent c) { 1054 Dimension prefSize = new Dimension(PREF_SIZE); 1055 JComponent accessory = getFileChooser().getAccessory(); 1056 if (accessory != null) { 1057 prefSize.width += accessory.getPreferredSize().width + 20; 1058 } 1059 Dimension d = c.getLayout().preferredLayoutSize(c); 1060 if (d != null) { 1061 return new Dimension(d.width < prefSize.width ? prefSize.width : d.width, 1062 d.height < prefSize.height ? prefSize.height : d.height); 1063 } else { 1064 return prefSize; 1065 } 1066 } 1067 1068 public Dimension getMinimumSize(JComponent x) { 1069 return new Dimension(MIN_SIZE); 1070 } 1071 1072 public Dimension getMaximumSize(JComponent x) { 1073 return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE); 1074 } 1075 1076 protected void align(JComponent c) { 1077 c.setAlignmentX(JComponent.LEFT_ALIGNMENT); 1078 c.setAlignmentY(JComponent.TOP_ALIGNMENT); 1079 } 1080 1081 public Action getNewFolderAction() { 1082 if (newFolderAction == null) { 1083 newFolderAction = new NewFolderAction(); 1084 newFolderAction.setEnabled(!readOnly); 1085 } 1086 return newFolderAction; 1087 } 1088 1089 // 1090 // DataModel for DirectoryComboxbox 1091 // 1092 protected DirectoryComboBoxModel createDirectoryComboBoxModel(JFileChooser fc) { 1093 return new DirectoryComboBoxModel(); 1094 } 1095 1096 /** 1097 * Data model for a type-face selection combo-box. 1098 */ 1099 @SuppressWarnings("serial") // Superclass is not serializable across versions 1100 protected class DirectoryComboBoxModel extends AbstractListModel<File> implements ComboBoxModel<File> { 1101 Vector<File> directories = new Vector<File>(); 1102 File selectedDirectory = null; 1103 JFileChooser chooser = getFileChooser(); 1104 FileSystemView fsv = chooser.getFileSystemView(); 1105 1106 public DirectoryComboBoxModel() { 1107 // Add the current directory to the model, and make it the 1108 // selectedDirectory 1109 File dir = getFileChooser().getCurrentDirectory(); 1110 if (dir != null) { 1111 addItem(dir); 1112 } 1113 } 1114 1115 /** 1116 * Adds the directory to the model and sets it to be selected, 1117 * additionally clears out the previous selected directory and 1118 * the paths leading up to it, if any. 1119 */ 1120 private void addItem(File directory) { 1121 1122 if (directory == null) { 1123 return; 1124 } 1125 1126 int oldSize = directories.size(); 1127 directories.clear(); 1128 if (oldSize > 0) { 1129 fireIntervalRemoved(this, 0, oldSize); 1130 } 1131 1132 // Get the canonical (full) path. This has the side 1133 // benefit of removing extraneous chars from the path, 1134 // for example /foo/bar/ becomes /foo/bar 1135 File canonical; 1136 try { 1137 canonical = fsv.createFileObject(ShellFolder.getNormalizedFile(directory).getPath()); 1138 } catch (IOException e) { 1139 // Maybe drive is not ready. Can't abort here. 1140 canonical = directory; 1141 } 1142 1143 // create File instances of each directory leading up to the top 1144 File f = canonical; 1145 do { 1146 directories.add(f); 1147 } while ((f = f.getParentFile()) != null); 1148 int newSize = directories.size(); 1149 if (newSize > 0) { 1150 fireIntervalAdded(this, 0, newSize); 1151 } 1152 setSelectedItem(canonical); 1153 } 1154 1155 public void setSelectedItem(Object selectedDirectory) { 1156 this.selectedDirectory = (File)selectedDirectory; 1157 fireContentsChanged(this, -1, -1); 1158 } 1159 1160 public Object getSelectedItem() { 1161 return selectedDirectory; 1162 } 1163 1164 public int getSize() { 1165 return directories.size(); 1166 } 1167 1168 @Override 1169 public File getElementAt(int index) { 1170 return directories.elementAt(index); 1171 } 1172 } 1173 1174 /** 1175 * Acts when DirectoryComboBox has changed the selected item. 1176 */ 1177 @SuppressWarnings("serial") // Superclass is not serializable across versions 1178 protected class DirectoryComboBoxAction extends AbstractAction { 1179 protected DirectoryComboBoxAction() { 1180 super("DirectoryComboBoxAction"); 1181 } 1182 1183 public void actionPerformed(ActionEvent e) { 1184 File f = (File)directoryComboBox.getSelectedItem(); 1185 getFileChooser().setCurrentDirectory(f); 1186 } 1187 } 1188 1189 /** 1190 * Creates a new folder. 1191 */ 1192 @SuppressWarnings("serial") // Superclass is not serializable across versions 1193 private class NewFolderAction extends AbstractAction { 1194 protected NewFolderAction() { 1195 super(FilePane.ACTION_NEW_FOLDER); 1196 } 1197 public void actionPerformed(ActionEvent e) { 1198 if (readOnly) { 1199 return; 1200 } 1201 JFileChooser fc = getFileChooser(); 1202 File currentDirectory = fc.getCurrentDirectory(); 1203 String dirName = JOptionPane.showInputDialog(fc, 1204 newFolderDialogText, newFolderButtonText, 1205 JOptionPane.PLAIN_MESSAGE); 1206 1207 if (dirName != null) { 1208 if (!currentDirectory.exists()) { 1209 JOptionPane.showMessageDialog(fc, 1210 MessageFormat.format(newFolderNoDirectoryErrorText, dirName), 1211 newFolderNoDirectoryErrorTitleText, JOptionPane.ERROR_MESSAGE); 1212 return; 1213 } 1214 1215 File newDir = fc.getFileSystemView().createFileObject 1216 (currentDirectory, dirName); 1217 if (newDir == null || !newDir.mkdir()) { 1218 JOptionPane.showMessageDialog(fc, 1219 newFolderErrorText + newFolderErrorSeparator + " \"" + 1220 dirName + "\"", 1221 newFolderErrorText, JOptionPane.ERROR_MESSAGE); 1222 } 1223 fc.rescanCurrentDirectory(); 1224 } 1225 } 1226 } 1227 1228 @SuppressWarnings("serial") // Superclass is not serializable across versions 1229 private class GTKApproveSelectionAction extends ApproveSelectionAction { 1230 public void actionPerformed(ActionEvent e) { 1231 if (isDirectorySelected()) { 1232 File dir = getDirectory(); 1233 try { 1234 // Strip trailing ".." 1235 if (dir != null) { 1236 dir = ShellFolder.getNormalizedFile(dir); 1237 } 1238 } catch (IOException ex) { 1239 // Ok, use f as is 1240 } 1241 if (getFileChooser().getCurrentDirectory().equals(dir)) { 1242 directoryList.clearSelection(); 1243 fileList.clearSelection(); 1244 ListSelectionModel sm = fileList.getSelectionModel(); 1245 if (sm instanceof DefaultListSelectionModel) { 1246 ((DefaultListSelectionModel)sm).moveLeadSelectionIndex(0); 1247 sm.setAnchorSelectionIndex(0); 1248 } 1249 rescanCurrentDirectory(getFileChooser()); 1250 return; 1251 } 1252 } 1253 super.actionPerformed(e); 1254 } 1255 } 1256 1257 /** 1258 * Renames file 1259 */ 1260 @SuppressWarnings("serial") // Superclass is not serializable across versions 1261 private class RenameFileAction extends AbstractAction { 1262 protected RenameFileAction() { 1263 super(FilePane.ACTION_EDIT_FILE_NAME); 1264 } 1265 public void actionPerformed(ActionEvent e) { 1266 if (getFileName().equals("")) { 1267 return; 1268 } 1269 JFileChooser fc = getFileChooser(); 1270 File currentDirectory = fc.getCurrentDirectory(); 1271 String newFileName = (String) JOptionPane.showInputDialog 1272 (fc, new MessageFormat(renameFileDialogText).format 1273 (new Object[] { getFileName() }), 1274 renameFileButtonText, JOptionPane.PLAIN_MESSAGE, null, null, 1275 getFileName()); 1276 1277 if (newFileName != null) { 1278 File oldFile = fc.getFileSystemView().createFileObject 1279 (currentDirectory, getFileName()); 1280 File newFile = fc.getFileSystemView().createFileObject 1281 (currentDirectory, newFileName); 1282 if (oldFile == null || newFile == null || 1283 !getModel().renameFile(oldFile, newFile)) { 1284 JOptionPane.showMessageDialog(fc, 1285 new MessageFormat(renameFileErrorText). 1286 format(new Object[] { getFileName(), newFileName}), 1287 renameFileErrorTitle, JOptionPane.ERROR_MESSAGE); 1288 } else { 1289 setFileName(getFileChooser().getName(newFile)); 1290 fc.rescanCurrentDirectory(); 1291 } 1292 } 1293 } 1294 } 1295 1296 // 1297 // Renderer for Filter ComboBox 1298 // 1299 protected FilterComboBoxRenderer createFilterComboBoxRenderer() { 1300 return new FilterComboBoxRenderer(); 1301 } 1302 1303 /** 1304 * Render different filters 1305 */ 1306 @SuppressWarnings("serial") // Superclass is not serializable across versions 1307 public class FilterComboBoxRenderer extends DefaultListCellRenderer implements UIResource { 1308 public String getName() { 1309 // As SynthComboBoxRenderer's are asked for a size BEFORE they 1310 // are parented getName is overriden to force the name to be 1311 // ComboBox.renderer if it isn't set. If we didn't do this the 1312 // wrong style could be used for size calculations. 1313 String name = super.getName(); 1314 if (name == null) { 1315 return "ComboBox.renderer"; 1316 } 1317 return name; 1318 } 1319 1320 public Component getListCellRendererComponent(JList<?> list, Object value, 1321 int index, boolean isSelected, 1322 boolean cellHasFocus) { 1323 1324 super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); 1325 1326 setName("ComboBox.listRenderer"); 1327 1328 if (value != null) { 1329 if (value instanceof FileFilter) { 1330 setText(((FileFilter) value).getDescription()); 1331 } 1332 } else { 1333 setText(""); 1334 } 1335 1336 return this; 1337 } 1338 } 1339 1340 // 1341 // DataModel for Filter Combobox 1342 // 1343 protected FilterComboBoxModel createFilterComboBoxModel() { 1344 return new FilterComboBoxModel(); 1345 } 1346 1347 /** 1348 * Data model for filter combo-box. 1349 */ 1350 @SuppressWarnings("serial") // JDK implementation class 1351 protected class FilterComboBoxModel extends AbstractListModel<FileFilter> 1352 implements ComboBoxModel<FileFilter>, PropertyChangeListener { 1353 protected FileFilter[] filters; 1354 1355 protected FilterComboBoxModel() { 1356 super(); 1357 filters = getFileChooser().getChoosableFileFilters(); 1358 } 1359 1360 public void propertyChange(PropertyChangeEvent e) { 1361 String prop = e.getPropertyName(); 1362 if (prop == JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY) { 1363 filters = (FileFilter[]) e.getNewValue(); 1364 fireContentsChanged(this, -1, -1); 1365 } else if (prop == JFileChooser.FILE_FILTER_CHANGED_PROPERTY) { 1366 fireContentsChanged(this, -1, -1); 1367 } 1368 } 1369 1370 public void setSelectedItem(Object filter) { 1371 if (filter != null) { 1372 getFileChooser().setFileFilter((FileFilter) filter); 1373 fireContentsChanged(this, -1, -1); 1374 } 1375 } 1376 1377 public Object getSelectedItem() { 1378 // Ensure that the current filter is in the list. 1379 // NOTE: we shouldnt' have to do this, since JFileChooser adds 1380 // the filter to the choosable filters list when the filter 1381 // is set. Lets be paranoid just in case someone overrides 1382 // setFileFilter in JFileChooser. 1383 FileFilter currentFilter = getFileChooser().getFileFilter(); 1384 boolean found = false; 1385 if (currentFilter != null) { 1386 for (FileFilter filter : filters) { 1387 if (filter == currentFilter) { 1388 found = true; 1389 } 1390 } 1391 if (found == false) { 1392 getFileChooser().addChoosableFileFilter(currentFilter); 1393 } 1394 } 1395 return getFileChooser().getFileFilter(); 1396 } 1397 1398 public int getSize() { 1399 if (filters != null) { 1400 return filters.length; 1401 } else { 1402 return 0; 1403 } 1404 } 1405 1406 @Override 1407 public FileFilter getElementAt(int index) { 1408 if (index > getSize() - 1) { 1409 // This shouldn't happen. Try to recover gracefully. 1410 return getFileChooser().getFileFilter(); 1411 } 1412 if (filters != null) { 1413 return filters[index]; 1414 } else { 1415 return null; 1416 } 1417 } 1418 } 1419 }