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