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