1 /*
   2  * Copyright (c) 2002, 2008, 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.AbstractFilterComboBoxModel;
  45 import sun.swing.SwingUtilities2;
  46 
  47 import sun.swing.plaf.synth.*;
  48 import sun.swing.FilePane;
  49 import sun.awt.shell.ShellFolder;
  50 
  51 /**
  52  * GTK FileChooserUI.
  53  *
  54  * @author Leif Samuelsson
  55  * @author Jeff Dinkins
  56  */
  57 class GTKFileChooserUI extends SynthFileChooserUI {
  58 
  59     // The accessoryPanel is a container to place the JFileChooser accessory component
  60     private JPanel accessoryPanel = null;
  61 
  62     private String newFolderButtonText = null;
  63     private String newFolderErrorSeparator = null;
  64     private String newFolderErrorText = null;
  65     private String newFolderDialogText = null;
  66     private String newFolderNoDirectoryErrorTitleText = null;
  67     private String newFolderNoDirectoryErrorText = null;
  68 
  69     private String deleteFileButtonText = null;
  70     private String renameFileButtonText = null;
  71 
  72     private String newFolderButtonToolTipText = null;
  73     private String deleteFileButtonToolTipText = null;
  74     private String renameFileButtonToolTipText = null;
  75 
  76     private int newFolderButtonMnemonic = 0;
  77     private int deleteFileButtonMnemonic = 0;
  78     private int renameFileButtonMnemonic = 0;
  79     private int foldersLabelMnemonic = 0;
  80     private int filesLabelMnemonic = 0;
  81 
  82     private String renameFileDialogText = null;
  83     private String renameFileErrorTitle = null;
  84     private String renameFileErrorText = null;
  85 
  86     private JComboBox filterComboBox;
  87     private FilterComboBoxModel filterComboBoxModel;
  88 
  89     // From Motif
  90 
  91     private JPanel rightPanel;
  92     private JList directoryList;
  93     private JList fileList;
  94 
  95     private JLabel pathField;
  96     private JTextField fileNameTextField;
  97 
  98     private static final Dimension hstrut3 = new Dimension(3, 1);
  99     private static final Dimension vstrut10 = new Dimension(1, 10);
 100 
 101     private static Dimension prefListSize = new Dimension(75, 150);
 102 
 103     private static Dimension PREF_SIZE = new Dimension(435, 360);
 104     private static Dimension MIN_SIZE = new Dimension(200, 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 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     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 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         StringBuffer buf = new StringBuffer();
 174         len = result.size();
 175 
 176         // construct the resulting string
 177         for (int i=0; i<len; i++) {
 178             if (i > 0) {
 179                 buf.append(" ");
 180             }
 181             if (len > 1) {
 182                 buf.append("\"");
 183             }
 184             buf.append(result.get(i));
 185             if (len > 1) {
 186                 buf.append("\"");
 187             }
 188         }
 189         return buf.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     protected class SelectionListener implements ListSelectionListener {
 424         public void valueChanged(ListSelectionEvent e) {
 425             if (!e.getValueIsAdjusting()) {
 426                 JFileChooser chooser = getFileChooser();
 427                 JList list = (JList) e.getSource();
 428 
 429                 if (chooser.isMultiSelectionEnabled()) {
 430                     File[] files = null;
 431                     Object[] objects = list.getSelectedValues();
 432                     if (objects != null) {
 433                         if (objects.length == 1
 434                             && ((File)objects[0]).isDirectory()
 435                             && chooser.isTraversable(((File)objects[0]))
 436                             && (chooser.getFileSelectionMode() != chooser.DIRECTORIES_ONLY
 437                                 || !chooser.getFileSystemView().isFileSystem(((File)objects[0])))) {
 438                             setDirectorySelected(true);
 439                             setDirectory(((File)objects[0]));
 440                         } else {
 441                             ArrayList<File> fList = new ArrayList<File>(objects.length);
 442                             for (Object object : objects) {
 443                                 File f = (File) object;
 444                                 if ((chooser.isFileSelectionEnabled() && f.isFile())
 445                                     || (chooser.isDirectorySelectionEnabled() && f.isDirectory())) {
 446                                     fList.add(f);
 447                                 }
 448                             }
 449                             if (fList.size() > 0) {
 450                                 files = fList.toArray(new File[fList.size()]);
 451                             }
 452                             setDirectorySelected(false);
 453                         }
 454                     }
 455                     chooser.setSelectedFiles(files);
 456                 } else {
 457                     File file = (File)list.getSelectedValue();
 458                     if (file != null
 459                         && file.isDirectory()
 460                         && chooser.isTraversable(file)
 461                         && (chooser.getFileSelectionMode() == chooser.FILES_ONLY
 462                             || !chooser.getFileSystemView().isFileSystem(file))) {
 463 
 464                         setDirectorySelected(true);
 465                         setDirectory(file);
 466                     } else {
 467                         setDirectorySelected(false);
 468                         if (file != null) {
 469                             chooser.setSelectedFile(file);
 470                         }
 471                     }
 472                 }
 473             }
 474         }
 475     }
 476 
 477 
 478     //
 479     // ComponentUI Interface Implementation methods
 480     //
 481     public static ComponentUI createUI(JComponent c) {
 482         return new GTKFileChooserUI((JFileChooser)c);
 483     }
 484 
 485     public void installUI(JComponent c) {
 486         accessoryPanel = new JPanel(new BorderLayout(10, 10));
 487         accessoryPanel.setName("GTKFileChooser.accessoryPanel");
 488 
 489         super.installUI(c);
 490     }
 491 
 492     public void uninstallUI(JComponent c) {
 493         c.removePropertyChangeListener(filterComboBoxModel);
 494         super.uninstallUI(c);
 495 
 496         if (accessoryPanel != null) {
 497             accessoryPanel.removeAll();
 498         }
 499         accessoryPanel = null;
 500         getFileChooser().removeAll();
 501     }
 502 
 503     public void installComponents(JFileChooser fc) {
 504         super.installComponents(fc);
 505 
 506         boolean leftToRight = fc.getComponentOrientation().isLeftToRight();
 507 
 508         fc.setLayout(new BorderLayout());
 509         fc.setAlignmentX(JComponent.CENTER_ALIGNMENT);
 510 
 511         // Top row of buttons
 512         JPanel topButtonPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0));
 513         topButtonPanel.setBorder(new EmptyBorder(10, 10, 0, 10));
 514         topButtonPanel.setName("GTKFileChooser.topButtonPanel");
 515 
 516         if (!UIManager.getBoolean("FileChooser.readOnly")) {
 517             JButton newFolderButton = new JButton(getNewFolderAction());
 518             newFolderButton.setName("GTKFileChooser.newFolderButton");
 519             newFolderButton.setMnemonic(newFolderButtonMnemonic);
 520             newFolderButton.setToolTipText(newFolderButtonToolTipText);
 521             newFolderButton.setText(newFolderButtonText);
 522             topButtonPanel.add(newFolderButton);
 523         }
 524         JButton deleteFileButton = new JButton(deleteFileButtonText);
 525         deleteFileButton.setName("GTKFileChooser.deleteFileButton");
 526         deleteFileButton.setMnemonic(deleteFileButtonMnemonic);
 527         deleteFileButton.setToolTipText(deleteFileButtonToolTipText);
 528         deleteFileButton.setEnabled(false);
 529         topButtonPanel.add(deleteFileButton);
 530 
 531         RenameFileAction rfa = new RenameFileAction();
 532         JButton renameFileButton = new JButton(rfa);
 533         if (readOnly) {
 534             rfa.setEnabled(false);
 535         }
 536         renameFileButton.setText(renameFileButtonText);
 537         renameFileButton.setName("GTKFileChooser.renameFileButton");
 538         renameFileButton.setMnemonic(renameFileButtonMnemonic);
 539         renameFileButton.setToolTipText(renameFileButtonToolTipText);
 540         topButtonPanel.add(renameFileButton);
 541 
 542         fc.add(topButtonPanel, BorderLayout.NORTH);
 543 
 544 
 545         JPanel interior = new JPanel();
 546         interior.setBorder(new EmptyBorder(0, 10, 10, 10));
 547         interior.setName("GTKFileChooser.interiorPanel");
 548         align(interior);
 549         interior.setLayout(new BoxLayout(interior, BoxLayout.PAGE_AXIS));
 550 
 551         fc.add(interior, BorderLayout.CENTER);
 552 
 553         JPanel comboBoxPanel = new JPanel(new FlowLayout(FlowLayout.CENTER,
 554                                                          0, 0) {
 555             public void layoutContainer(Container target) {
 556                 super.layoutContainer(target);
 557                 JComboBox comboBox = directoryComboBox;
 558                 if (comboBox.getWidth() > target.getWidth()) {
 559                     comboBox.setBounds(0, comboBox.getY(), target.getWidth(),
 560                                        comboBox.getHeight());
 561                 }
 562             }
 563         });
 564         comboBoxPanel.setBorder(new EmptyBorder(0, 0, 4, 0));
 565         comboBoxPanel.setName("GTKFileChooser.directoryComboBoxPanel");
 566         // CurrentDir ComboBox
 567         directoryComboBoxModel = createDirectoryComboBoxModel(fc);
 568         directoryComboBox = new JComboBox(directoryComboBoxModel);
 569         directoryComboBox.setName("GTKFileChooser.directoryComboBox");
 570         directoryComboBox.putClientProperty( "JComboBox.lightweightKeyboardNavigation", "Lightweight" );
 571         directoryComboBox.addActionListener(directoryComboBoxAction);
 572         directoryComboBox.setMaximumRowCount(8);
 573         comboBoxPanel.add(directoryComboBox);
 574         interior.add(comboBoxPanel);
 575 
 576 
 577         // CENTER: left, right, accessory
 578         JPanel centerPanel = new JPanel(new BorderLayout());
 579         centerPanel.setName("GTKFileChooser.centerPanel");
 580 
 581         // SPLIT PANEL: left, right
 582         JSplitPane splitPanel = new JSplitPane();
 583         splitPanel.setName("GTKFileChooser.splitPanel");
 584         splitPanel.setDividerLocation((PREF_SIZE.width-8)/2);
 585 
 586         // left panel - Filter & directoryList
 587         JPanel leftPanel = new JPanel(new GridBagLayout());
 588         leftPanel.setName("GTKFileChooser.directoryListPanel");
 589 
 590         // Add the Directory List
 591         // Create a label that looks like button (should be a table header)
 592         TableCellRenderer headerRenderer = new JTableHeader().getDefaultRenderer();
 593         JLabel directoryListLabel =
 594             (JLabel)headerRenderer.getTableCellRendererComponent(null, foldersLabelText,
 595                                                                      false, false, 0, 0);
 596         directoryListLabel.setName("GTKFileChooser.directoryListLabel");
 597         leftPanel.add(directoryListLabel, new GridBagConstraints(
 598                           0, 0, 1, 1, 1, 0, GridBagConstraints.WEST,
 599                           GridBagConstraints.HORIZONTAL,
 600                           new Insets(0, 0, 0, 0), 0, 0));
 601         leftPanel.add(createDirectoryList(), new GridBagConstraints(
 602                           0, 1, 1, 1, 1, 1, GridBagConstraints.EAST,
 603                           GridBagConstraints.BOTH,
 604                           new Insets(0, 0, 0, 0), 0, 0));
 605         directoryListLabel.setDisplayedMnemonic(foldersLabelMnemonic);
 606         directoryListLabel.setLabelFor(directoryList);
 607 
 608         // create files list
 609         rightPanel = new JPanel(new GridBagLayout());
 610         rightPanel.setName("GTKFileChooser.fileListPanel");
 611 
 612         headerRenderer = new JTableHeader().getDefaultRenderer();
 613         JLabel fileListLabel =
 614             (JLabel)headerRenderer.getTableCellRendererComponent(null, filesLabelText,
 615                                                                      false, false, 0, 0);
 616         fileListLabel.setName("GTKFileChooser.fileListLabel");
 617         rightPanel.add(fileListLabel, new GridBagConstraints(
 618                           0, 0, 1, 1, 1, 0, GridBagConstraints.WEST,
 619                           GridBagConstraints.HORIZONTAL,
 620                           new Insets(0, 0, 0, 0), 0, 0));
 621         rightPanel.add(createFilesList(), new GridBagConstraints(
 622                           0, 1, 1, 1, 1, 1, GridBagConstraints.EAST,
 623                           GridBagConstraints.BOTH,
 624                           new Insets(0, 0, 0, 0), 0, 0));
 625         fileListLabel.setDisplayedMnemonic(filesLabelMnemonic);
 626         fileListLabel.setLabelFor(fileList);
 627 
 628         splitPanel.add(leftPanel,  leftToRight ? JSplitPane.LEFT : JSplitPane.RIGHT);
 629         splitPanel.add(rightPanel, leftToRight ? JSplitPane.RIGHT : JSplitPane.LEFT);
 630         centerPanel.add(splitPanel, BorderLayout.CENTER);
 631 
 632         JComponent accessoryPanel = getAccessoryPanel();
 633         JComponent accessory = fc.getAccessory();
 634         if (accessoryPanel != null) {
 635             if (accessory == null) {
 636                 accessoryPanel.setPreferredSize(ZERO_ACC_SIZE);
 637                 accessoryPanel.setMaximumSize(ZERO_ACC_SIZE);
 638             } else {
 639                 getAccessoryPanel().add(accessory, BorderLayout.CENTER);
 640                 accessoryPanel.setPreferredSize(accessory.getPreferredSize());
 641                 accessoryPanel.setMaximumSize(MAX_SIZE);
 642             }
 643             align(accessoryPanel);
 644             centerPanel.add(accessoryPanel, BorderLayout.AFTER_LINE_ENDS);
 645         }
 646         interior.add(centerPanel);
 647         interior.add(Box.createRigidArea(vstrut10));
 648 
 649         JPanel pathFieldPanel = new JPanel(new FlowLayout(FlowLayout.LEADING,
 650                                                           0, 0));
 651         pathFieldPanel.setBorder(new EmptyBorder(0, 0, 4, 0));
 652         JLabel pathFieldLabel = new JLabel(pathLabelText);
 653         pathFieldLabel.setName("GTKFileChooser.pathFieldLabel");
 654         pathFieldLabel.setDisplayedMnemonic(pathLabelMnemonic);
 655         align(pathFieldLabel);
 656         pathFieldPanel.add(pathFieldLabel);
 657         pathFieldPanel.add(Box.createRigidArea(hstrut3));
 658 
 659         File currentDirectory = fc.getCurrentDirectory();
 660         String curDirName = null;
 661         if (currentDirectory != null) {
 662             curDirName = currentDirectory.getPath();
 663         }
 664         pathField = new JLabel(curDirName) {
 665             public Dimension getMaximumSize() {
 666                 Dimension d = super.getMaximumSize();
 667                 d.height = getPreferredSize().height;
 668                 return d;
 669             }
 670         };
 671         pathField.setName("GTKFileChooser.pathField");
 672         align(pathField);
 673         pathFieldPanel.add(pathField);
 674         interior.add(pathFieldPanel);
 675 
 676         // add the fileName field
 677         fileNameTextField = new JTextField() {
 678             public Dimension getMaximumSize() {
 679                 Dimension d = super.getMaximumSize();
 680                 d.height = getPreferredSize().height;
 681                 return d;
 682             }
 683         };
 684 
 685         pathFieldLabel.setLabelFor(fileNameTextField);
 686 
 687         Set<AWTKeyStroke> forwardTraversalKeys = fileNameTextField.getFocusTraversalKeys(
 688             KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
 689         forwardTraversalKeys = new HashSet<AWTKeyStroke>(forwardTraversalKeys);
 690         forwardTraversalKeys.remove(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0));
 691         fileNameTextField.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forwardTraversalKeys);
 692 
 693         fileNameTextField.setName("GTKFileChooser.fileNameTextField");
 694         fileNameTextField.getActionMap().put("fileNameCompletionAction", getFileNameCompletionAction());
 695         fileNameTextField.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB, 0), "fileNameCompletionAction");
 696         interior.add(fileNameTextField);
 697 
 698         // Add the filter combo box
 699         JPanel panel = new JPanel();
 700         panel.setLayout(new FlowLayout(FlowLayout.LEADING, 0, 0));
 701         panel.setBorder(new EmptyBorder(0, 0, 4, 0));
 702         JLabel filterLabel = new JLabel(filterLabelText);
 703         filterLabel.setName("GTKFileChooser.filterLabel");
 704         filterLabel.setDisplayedMnemonic(filterLabelMnemonic);
 705         panel.add(filterLabel);
 706 
 707         filterComboBoxModel = createFilterComboBoxModel();
 708         fc.addPropertyChangeListener(filterComboBoxModel);
 709         filterComboBox = new JComboBox(filterComboBoxModel);
 710         filterComboBox.setRenderer(createFilterComboBoxRenderer());
 711         filterLabel.setLabelFor(filterComboBox);
 712 
 713         interior.add(Box.createRigidArea(vstrut10));
 714         interior.add(panel);
 715         interior.add(filterComboBox);
 716 
 717         // Add buttons
 718         bottomButtonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
 719         bottomButtonPanel.setName("GTKFileChooser.bottomButtonPanel");
 720         align(bottomButtonPanel);
 721 
 722         JPanel pnButtons = new JPanel(new GridLayout(1, 2, 5, 0));
 723 
 724         JButton cancelButton = getCancelButton(fc);
 725         align(cancelButton);
 726         cancelButton.setMargin(buttonMargin);
 727         pnButtons.add(cancelButton);
 728 
 729         JButton approveButton = getApproveButton(fc);
 730         align(approveButton);
 731         approveButton.setMargin(buttonMargin);
 732         pnButtons.add(approveButton);
 733 
 734         bottomButtonPanel.add(pnButtons);
 735 
 736         if (fc.getControlButtonsAreShown()) {
 737             fc.add(bottomButtonPanel, BorderLayout.SOUTH);
 738         }
 739     }
 740 
 741     protected void installListeners(JFileChooser fc) {
 742         super.installListeners(fc);
 743 
 744         gtkFCPropertyChangeListener = new GTKFCPropertyChangeListener();
 745         fc.addPropertyChangeListener(gtkFCPropertyChangeListener);
 746     }
 747 
 748     private int getMnemonic(String key, Locale l) {
 749         return SwingUtilities2.getUIDefaultsInt(key, l);
 750     }
 751 
 752     protected void uninstallListeners(JFileChooser fc) {
 753         super.uninstallListeners(fc);
 754 
 755         if (gtkFCPropertyChangeListener != null) {
 756             fc.removePropertyChangeListener(gtkFCPropertyChangeListener);
 757         }
 758     }
 759 
 760     private class GTKFCPropertyChangeListener implements PropertyChangeListener {
 761         public void propertyChange(PropertyChangeEvent e) {
 762             String prop = e.getPropertyName();
 763             if (prop.equals("GTKFileChooser.showDirectoryIcons")) {
 764                 showDirectoryIcons = Boolean.TRUE.equals(e.getNewValue());
 765             } else if (prop.equals("GTKFileChooser.showFileIcons")) {
 766                 showFileIcons      = Boolean.TRUE.equals(e.getNewValue());
 767             }
 768         }
 769     }
 770 
 771     protected void installDefaults(JFileChooser fc) {
 772         super.installDefaults(fc);
 773         readOnly = UIManager.getBoolean("FileChooser.readOnly");
 774         showDirectoryIcons =
 775             Boolean.TRUE.equals(fc.getClientProperty("GTKFileChooser.showDirectoryIcons"));
 776         showFileIcons =
 777             Boolean.TRUE.equals(fc.getClientProperty("GTKFileChooser.showFileIcons"));
 778     }
 779 
 780     protected void installIcons(JFileChooser fc) {
 781         directoryIcon    = UIManager.getIcon("FileView.directoryIcon");
 782         fileIcon         = UIManager.getIcon("FileView.fileIcon");
 783     }
 784 
 785     protected void installStrings(JFileChooser fc) {
 786         super.installStrings(fc);
 787 
 788         Locale l = fc.getLocale();
 789 
 790         newFolderDialogText = UIManager.getString("FileChooser.newFolderDialogText", l);
 791         newFolderErrorText = UIManager.getString("FileChooser.newFolderErrorText",l);
 792         newFolderErrorSeparator = UIManager.getString("FileChooser.newFolderErrorSeparator",l);
 793         newFolderButtonText = UIManager.getString("FileChooser.newFolderButtonText", l);
 794         newFolderNoDirectoryErrorTitleText = UIManager.getString("FileChooser.newFolderNoDirectoryErrorTitleText", l);
 795         newFolderNoDirectoryErrorText = UIManager.getString("FileChooser.newFolderNoDirectoryErrorText", l);
 796         deleteFileButtonText = UIManager.getString("FileChooser.deleteFileButtonText", l);
 797         renameFileButtonText = UIManager.getString("FileChooser.renameFileButtonText", l);
 798 
 799         newFolderButtonMnemonic = getMnemonic("FileChooser.newFolderButtonMnemonic", l);
 800         deleteFileButtonMnemonic = getMnemonic("FileChooser.deleteFileButtonMnemonic", l);
 801         renameFileButtonMnemonic = getMnemonic("FileChooser.renameFileButtonMnemonic", l);
 802 
 803         newFolderButtonToolTipText = UIManager.getString("FileChooser.newFolderButtonToolTipText", l);
 804         deleteFileButtonToolTipText = UIManager.getString("FileChooser.deleteFileButtonToolTipText", l);
 805         renameFileButtonToolTipText = UIManager.getString("FileChooser.renameFileButtonToolTipText", l);
 806 
 807         renameFileDialogText = UIManager.getString("FileChooser.renameFileDialogText", l);
 808         renameFileErrorTitle = UIManager.getString("FileChooser.renameFileErrorTitle", l);
 809         renameFileErrorText = UIManager.getString("FileChooser.renameFileErrorText", l);
 810 
 811         foldersLabelText = UIManager.getString("FileChooser.foldersLabelText",l);
 812         foldersLabelMnemonic = getMnemonic("FileChooser.foldersLabelMnemonic", l);
 813 
 814         filesLabelText = UIManager.getString("FileChooser.filesLabelText",l);
 815         filesLabelMnemonic = getMnemonic("FileChooser.filesLabelMnemonic", l);
 816 
 817         pathLabelText = UIManager.getString("FileChooser.pathLabelText",l);
 818         pathLabelMnemonic = getMnemonic("FileChooser.pathLabelMnemonic", l);
 819 
 820         filterLabelText = UIManager.getString("FileChooser.filterLabelText", l);
 821         filterLabelMnemonic = UIManager.getInt("FileChooser.filterLabelMnemonic");
 822     }
 823 
 824     protected void uninstallStrings(JFileChooser fc) {
 825         super.uninstallStrings(fc);
 826 
 827         newFolderButtonText = null;
 828         deleteFileButtonText = null;
 829         renameFileButtonText = null;
 830 
 831         newFolderButtonToolTipText = null;
 832         deleteFileButtonToolTipText = null;
 833         renameFileButtonToolTipText = null;
 834 
 835         renameFileDialogText = null;
 836         renameFileErrorTitle = null;
 837         renameFileErrorText = null;
 838 
 839         foldersLabelText = null;
 840         filesLabelText = null;
 841 
 842         pathLabelText = null;
 843 
 844         newFolderDialogText = null;
 845         newFolderErrorText = null;
 846         newFolderErrorSeparator = null;
 847     }
 848 
 849     protected JScrollPane createFilesList() {
 850         fileList = new JList();
 851         fileList.setName("GTKFileChooser.fileList");
 852         fileList.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, filesLabelText);
 853 
 854         if (getFileChooser().isMultiSelectionEnabled()) {
 855             fileList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
 856         } else {
 857             fileList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 858         }
 859 
 860         fileList.setModel(new GTKFileListModel());
 861         fileList.getSelectionModel().removeSelectionInterval(0, 0);
 862         fileList.setCellRenderer(new FileCellRenderer());
 863         fileList.addListSelectionListener(createListSelectionListener(getFileChooser()));
 864         fileList.addMouseListener(createDoubleClickListener(getFileChooser(), fileList));
 865         align(fileList);
 866         JScrollPane scrollpane = new JScrollPane(fileList);
 867     scrollpane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
 868         scrollpane.setName("GTKFileChooser.fileListScrollPane");
 869         scrollpane.setPreferredSize(prefListSize);
 870         scrollpane.setMaximumSize(MAX_SIZE);
 871         align(scrollpane);
 872         return scrollpane;
 873     }
 874 
 875     protected JScrollPane createDirectoryList() {
 876         directoryList = new JList();
 877         directoryList.setName("GTKFileChooser.directoryList");
 878         directoryList.putClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY, foldersLabelText);
 879         align(directoryList);
 880 
 881         directoryList.setCellRenderer(new DirectoryCellRenderer());
 882         directoryListModel = new GTKDirectoryListModel();
 883         directoryList.getSelectionModel().removeSelectionInterval(0, 0);
 884         directoryList.setModel(directoryListModel);
 885         directoryList.addMouseListener(createDoubleClickListener(getFileChooser(), directoryList));
 886         directoryList.addListSelectionListener(createListSelectionListener(getFileChooser()));
 887 
 888         JScrollPane scrollpane = new JScrollPane(directoryList);
 889     scrollpane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
 890         scrollpane.setName("GTKFileChooser.directoryListScrollPane");
 891         scrollpane.setMaximumSize(MAX_SIZE);
 892         scrollpane.setPreferredSize(prefListSize);
 893         align(scrollpane);
 894         return scrollpane;
 895     }
 896 
 897     protected void createModel() {
 898         model = new GTKDirectoryModel();
 899     }
 900 
 901     public BasicDirectoryModel getModel() {
 902         return model;
 903     }
 904 
 905     public Action getApproveSelectionAction() {
 906         return approveSelectionAction;
 907     }
 908 
 909     private class GTKDirectoryModel extends BasicDirectoryModel {
 910         FileSystemView fsv;
 911         private Comparator<File> fileComparator = new Comparator<File>() {
 912             public int compare(File o, File o1) {
 913                 return fsv.getSystemDisplayName(o).compareTo(fsv.getSystemDisplayName(o1));
 914             }
 915         };
 916 
 917         public GTKDirectoryModel() {
 918             super(getFileChooser());
 919         }
 920 
 921         protected void sort(Vector<? extends File> v) {
 922             fsv = getFileChooser().getFileSystemView();
 923             Collections.sort(v, fileComparator);
 924         }
 925     }
 926 
 927     protected class GTKDirectoryListModel extends AbstractListModel implements ListDataListener {
 928         File curDir;
 929         public GTKDirectoryListModel() {
 930             getModel().addListDataListener(this);
 931             directoryChanged();
 932         }
 933 
 934         public int getSize() {
 935             return getModel().getDirectories().size() + 1;
 936         }
 937 
 938         public Object getElementAt(int index) {
 939             return index > 0 ? getModel().getDirectories().elementAt(index - 1):
 940                     curDir;
 941         }
 942 
 943         public void intervalAdded(ListDataEvent e) {
 944             fireIntervalAdded(this, e.getIndex0(), e.getIndex1());
 945         }
 946 
 947         public void intervalRemoved(ListDataEvent e) {
 948             fireIntervalRemoved(this, e.getIndex0(), e.getIndex1());
 949         }
 950 
 951         // PENDING - this is inefficient - should sent out
 952         // incremental adjustment values instead of saying that the
 953         // whole list has changed.
 954         public void fireContentsChanged() {
 955             fireContentsChanged(this, 0, getModel().getDirectories().size()-1);
 956         }
 957 
 958         // PENDING - fire the correct interval changed - currently sending
 959         // out that everything has changed
 960         public void contentsChanged(ListDataEvent e) {
 961             fireContentsChanged();
 962         }
 963 
 964         private void directoryChanged() {
 965             curDir = getFileChooser().getFileSystemView().createFileObject(
 966                     getFileChooser().getCurrentDirectory(), ".");
 967         }
 968     }
 969 
 970     protected class GTKFileListModel extends AbstractListModel implements ListDataListener {
 971         public GTKFileListModel() {
 972             getModel().addListDataListener(this);
 973         }
 974 
 975         public int getSize() {
 976             return getModel().getFiles().size();
 977         }
 978 
 979         public boolean contains(Object o) {
 980             return getModel().getFiles().contains(o);
 981         }
 982 
 983         public int indexOf(Object o) {
 984             return getModel().getFiles().indexOf(o);
 985         }
 986 
 987         public Object getElementAt(int index) {
 988             return getModel().getFiles().elementAt(index);
 989         }
 990 
 991         public void intervalAdded(ListDataEvent e) {
 992             fireIntervalAdded(this, e.getIndex0(), e.getIndex1());
 993         }
 994 
 995         public void intervalRemoved(ListDataEvent e) {
 996             fireIntervalRemoved(this, e.getIndex0(), e.getIndex1());
 997         }
 998 
 999         // PENDING - this is inefficient - should sent out
1000         // incremental adjustment values instead of saying that the
1001         // whole list has changed.
1002         public void fireContentsChanged() {
1003             fireContentsChanged(this, 0, getModel().getFiles().size()-1);
1004         }
1005 
1006         // PENDING - fire the interval changed
1007         public void contentsChanged(ListDataEvent e) {
1008             fireContentsChanged();
1009         }
1010     }
1011 
1012 
1013     protected class FileCellRenderer extends DefaultListCellRenderer  {
1014         public Component getListCellRendererComponent(JList list, Object value, int index,
1015                                                       boolean isSelected, boolean cellHasFocus) {
1016 
1017             super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
1018             setText(getFileChooser().getName((File) value));
1019             if (showFileIcons) {
1020                 setIcon(getFileChooser().getIcon((File)value));
1021             }
1022             return this;
1023         }
1024     }
1025 
1026     protected class DirectoryCellRenderer 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 
1032             if (showDirectoryIcons) {
1033                 setIcon(getFileChooser().getIcon((File)value));
1034                 setText(getFileChooser().getName((File)value));
1035             } else {
1036                 setText(getFileChooser().getName((File)value) + "/");
1037             }
1038             return this;
1039         }
1040     }
1041 
1042     public Dimension getPreferredSize(JComponent c) {
1043         Dimension prefSize = new Dimension(PREF_SIZE);
1044         JComponent accessory = getFileChooser().getAccessory();
1045         if (accessory != null) {
1046             prefSize.width += accessory.getPreferredSize().width + 20;
1047         }
1048         Dimension d = c.getLayout().preferredLayoutSize(c);
1049         if (d != null) {
1050             return new Dimension(d.width < prefSize.width ? prefSize.width : d.width,
1051                                  d.height < prefSize.height ? prefSize.height : d.height);
1052         } else {
1053             return prefSize;
1054         }
1055     }
1056 
1057     public Dimension getMinimumSize(JComponent x)  {
1058         return new Dimension(MIN_SIZE);
1059     }
1060 
1061     public Dimension getMaximumSize(JComponent x) {
1062         return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
1063     }
1064 
1065     protected void align(JComponent c) {
1066         c.setAlignmentX(JComponent.LEFT_ALIGNMENT);
1067         c.setAlignmentY(JComponent.TOP_ALIGNMENT);
1068     }
1069 
1070     public Action getNewFolderAction() {
1071         if (newFolderAction == null) {
1072             newFolderAction = new NewFolderAction();
1073             newFolderAction.setEnabled(!readOnly);
1074         }
1075         return newFolderAction;
1076     }
1077 
1078     //
1079     // DataModel for DirectoryComboxbox
1080     //
1081     protected DirectoryComboBoxModel createDirectoryComboBoxModel(JFileChooser fc) {
1082         return new DirectoryComboBoxModel();
1083     }
1084 
1085     /**
1086      * Data model for a type-face selection combo-box.
1087      */
1088     protected class DirectoryComboBoxModel extends AbstractListModel implements ComboBoxModel {
1089         Vector<File> directories = new Vector<File>();
1090         File selectedDirectory = null;
1091         JFileChooser chooser = getFileChooser();
1092         FileSystemView fsv = chooser.getFileSystemView();
1093 
1094         public DirectoryComboBoxModel() {
1095             // Add the current directory to the model, and make it the
1096             // selectedDirectory
1097             File dir = getFileChooser().getCurrentDirectory();
1098             if (dir != null) {
1099                 addItem(dir);
1100             }
1101         }
1102 
1103         /**
1104          * Adds the directory to the model and sets it to be selected,
1105          * additionally clears out the previous selected directory and
1106          * the paths leading up to it, if any.
1107          */
1108         private void addItem(File directory) {
1109 
1110             if (directory == null) {
1111                 return;
1112             }
1113 
1114             int oldSize = directories.size();
1115             directories.clear();
1116             if (oldSize > 0) {
1117                 fireIntervalRemoved(this, 0, oldSize);
1118             }
1119 
1120             // Get the canonical (full) path. This has the side
1121             // benefit of removing extraneous chars from the path,
1122             // for example /foo/bar/ becomes /foo/bar
1123             File canonical;
1124             try {
1125                 canonical = fsv.createFileObject(ShellFolder.getNormalizedFile(directory).getPath());
1126             } catch (IOException e) {
1127                 // Maybe drive is not ready. Can't abort here.
1128                 canonical = directory;
1129             }
1130 
1131             // create File instances of each directory leading up to the top
1132             File f = canonical;
1133             do {
1134                 directories.add(f);
1135             } while ((f = f.getParentFile()) != null);
1136             int newSize = directories.size();
1137             if (newSize > 0) {
1138                 fireIntervalAdded(this, 0, newSize);
1139             }
1140             setSelectedItem(canonical);
1141         }
1142 
1143         public void setSelectedItem(Object selectedDirectory) {
1144             this.selectedDirectory = (File)selectedDirectory;
1145             fireContentsChanged(this, -1, -1);
1146         }
1147 
1148         public Object getSelectedItem() {
1149             return selectedDirectory;
1150         }
1151 
1152         public int getSize() {
1153             return directories.size();
1154         }
1155 
1156         public Object getElementAt(int index) {
1157             return directories.elementAt(index);
1158         }
1159     }
1160 
1161     /**
1162      * Acts when DirectoryComboBox has changed the selected item.
1163      */
1164     protected class DirectoryComboBoxAction extends AbstractAction {
1165         protected DirectoryComboBoxAction() {
1166             super("DirectoryComboBoxAction");
1167         }
1168 
1169         public void actionPerformed(ActionEvent e) {
1170             File f = (File)directoryComboBox.getSelectedItem();
1171             getFileChooser().setCurrentDirectory(f);
1172         }
1173     }
1174 
1175     /**
1176      * Creates a new folder.
1177      */
1178     private class NewFolderAction extends AbstractAction {
1179         protected NewFolderAction() {
1180             super(FilePane.ACTION_NEW_FOLDER);
1181         }
1182         public void actionPerformed(ActionEvent e) {
1183             if (readOnly) {
1184                 return;
1185             }
1186             JFileChooser fc = getFileChooser();
1187             File currentDirectory = fc.getCurrentDirectory();
1188             String dirName = JOptionPane.showInputDialog(fc,
1189                     newFolderDialogText, newFolderButtonText,
1190                     JOptionPane.PLAIN_MESSAGE);
1191 
1192             if (dirName != null) {
1193                 if (!currentDirectory.exists()) {
1194                     JOptionPane.showMessageDialog(fc,
1195                             MessageFormat.format(newFolderNoDirectoryErrorText, dirName),
1196                             newFolderNoDirectoryErrorTitleText, JOptionPane.ERROR_MESSAGE);
1197                     return;
1198                 }
1199 
1200                 File newDir = fc.getFileSystemView().createFileObject
1201                         (currentDirectory, dirName);
1202                 if (newDir == null || !newDir.mkdir()) {
1203                     JOptionPane.showMessageDialog(fc,
1204                             newFolderErrorText + newFolderErrorSeparator + " \"" +
1205                             dirName + "\"",
1206                             newFolderErrorText, JOptionPane.ERROR_MESSAGE);
1207                 }
1208                 fc.rescanCurrentDirectory();
1209             }
1210         }
1211     }
1212 
1213     private class GTKApproveSelectionAction extends ApproveSelectionAction {
1214         public void actionPerformed(ActionEvent e) {
1215             if (isDirectorySelected()) {
1216                 File dir = getDirectory();
1217                 try {
1218                     // Strip trailing ".."
1219                     if (dir != null) {
1220                         dir = ShellFolder.getNormalizedFile(dir);
1221                     }
1222                 } catch (IOException ex) {
1223                     // Ok, use f as is
1224                 }
1225                 if (getFileChooser().getCurrentDirectory().equals(dir)) {
1226                     directoryList.clearSelection();
1227                     fileList.clearSelection();
1228                     ListSelectionModel sm = fileList.getSelectionModel();
1229                     if (sm instanceof DefaultListSelectionModel) {
1230                         ((DefaultListSelectionModel)sm).moveLeadSelectionIndex(0);
1231                         sm.setAnchorSelectionIndex(0);
1232                     }
1233                     rescanCurrentDirectory(getFileChooser());
1234                     return;
1235                 }
1236             }
1237             super.actionPerformed(e);
1238         }
1239     }
1240 
1241     /**
1242      * Renames file
1243      */
1244     private class RenameFileAction extends AbstractAction {
1245         protected RenameFileAction() {
1246             super(FilePane.ACTION_EDIT_FILE_NAME);
1247         }
1248         public void actionPerformed(ActionEvent e) {
1249             if (getFileName().equals("")) {
1250                 return;
1251             }
1252             JFileChooser fc = getFileChooser();
1253             File currentDirectory = fc.getCurrentDirectory();
1254             String newFileName = (String) JOptionPane.showInputDialog
1255                    (fc, new MessageFormat(renameFileDialogText).format
1256                            (new Object[] { getFileName() }),
1257                            renameFileButtonText, JOptionPane.PLAIN_MESSAGE, null, null,
1258                            getFileName());
1259 
1260             if (newFileName != null) {
1261                 File oldFile = fc.getFileSystemView().createFileObject
1262                         (currentDirectory, getFileName());
1263                 File newFile = fc.getFileSystemView().createFileObject
1264                         (currentDirectory, newFileName);
1265                 if (oldFile == null || newFile == null ||
1266                         !getModel().renameFile(oldFile, newFile)) {
1267                     JOptionPane.showMessageDialog(fc,
1268                             new MessageFormat(renameFileErrorText).
1269                             format(new Object[] { getFileName(), newFileName}),
1270                             renameFileErrorTitle, JOptionPane.ERROR_MESSAGE);
1271                 } else {
1272                     setFileName(getFileChooser().getName(newFile));
1273                     fc.rescanCurrentDirectory();
1274                 }
1275             }
1276         }
1277     }
1278 
1279     //
1280     // Renderer for Filter ComboBox
1281     //
1282     protected FilterComboBoxRenderer createFilterComboBoxRenderer() {
1283         return new FilterComboBoxRenderer();
1284     }
1285 
1286     /**
1287      * Render different filters
1288      */
1289     public class FilterComboBoxRenderer extends DefaultListCellRenderer implements UIResource {
1290         public String getName() {
1291             // As SynthComboBoxRenderer's are asked for a size BEFORE they
1292             // are parented getName is overriden to force the name to be
1293             // ComboBox.renderer if it isn't set. If we didn't do this the
1294             // wrong style could be used for size calculations.
1295             String name = super.getName();
1296             if (name == null) {
1297                 return "ComboBox.renderer";
1298             }
1299             return name;
1300         }
1301 
1302         public Component getListCellRendererComponent(JList list, Object value,
1303                                                       int index, boolean isSelected,
1304                                                       boolean cellHasFocus) {
1305 
1306             super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
1307 
1308             setName("ComboBox.listRenderer");
1309 
1310             if (value != null) {
1311                 if (value instanceof FileFilter) {
1312                     setText(((FileFilter) value).getDescription());
1313                 }
1314             } else {
1315                 setText("");
1316             }
1317 
1318             return this;
1319         }
1320     }
1321 
1322     //
1323     // DataModel for Filter Combobox
1324     //
1325     protected FilterComboBoxModel createFilterComboBoxModel() {
1326         return new FilterComboBoxModel();
1327     }
1328 
1329     /**
1330      * Data model for filter combo-box.
1331      */
1332     protected class FilterComboBoxModel extends AbstractFilterComboBoxModel {
1333         protected JFileChooser getFileChooser() {
1334             return GTKFileChooserUI.this.getFileChooser();
1335         }
1336     }
1337 }