       1 /*
       2  * Copyright (c) 1997, 2015, 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
      26 package com.sun.java.swing.plaf.motif;
      27
      28 import javax.swing.*;
      29 import javax.swing.filechooser.*;
      30 import javax.swing.event.*;
      31 import javax.swing.plaf.*;
      32 import javax.swing.plaf.basic.*;
      33 import java.awt.*;
      34 import java.awt.event.MouseAdapter;
      35 import java.awt.event.MouseEvent;
      36 import java.beans.*;
      37 import java.io.File;
      38 import java.io.IOException;
      39 import java.util.*;
      40 import sun.awt.shell.ShellFolder;
      41 import sun.swing.SwingUtilities2;
      42
      43 /**
      44  * Motif FileChooserUI.
      45  *
      46  * @author Jeff Dinkins
      47  */
      48 public class MotifFileChooserUI extends BasicFileChooserUI {
      49
      50     private FilterComboBoxModel filterComboBoxModel;
      51
      52     protected JList<File> directoryList = null;
      53     protected JList<File> fileList = null;
      54
      55     protected JTextField pathField = null;
      56     protected JComboBox<FileFilter> filterComboBox = null;
      57     protected JTextField filenameTextField = null;
      58
      59     private static final Dimension hstrut10 = new Dimension(10, 1);
      60     private static final Dimension vstrut10 = new Dimension(1, 10);
      61
      62     private static final Insets insets = new Insets(10, 10, 10, 10);
      63
      64     private static Dimension prefListSize = new Dimension(75, 150);
      65
      66     private static Dimension WITH_ACCELERATOR_PREF_SIZE = new Dimension(650, 450);
      67     private static Dimension PREF_SIZE = new Dimension(350, 450);
      68     private static final int MIN_WIDTH = 200;
      69     private static final int MIN_HEIGHT = 300;
      70     private static Dimension PREF_ACC_SIZE = new Dimension(10, 10);
      71     private static Dimension ZERO_ACC_SIZE = new Dimension(1, 1);
      72
      73     private static Dimension MAX_SIZE = new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
      74
      75     private static final Insets buttonMargin = new Insets(3, 3, 3, 3);
      76
      77     private JPanel bottomPanel;
      78
      79     protected JButton approveButton;
      80
      81     private String enterFolderNameLabelText = null;
      82     private int enterFolderNameLabelMnemonic = 0;
      83     private String enterFileNameLabelText = null;
      84     private int enterFileNameLabelMnemonic = 0;
      85
      86     private String filesLabelText = null;
      87     private int filesLabelMnemonic = 0;
      88
      89     private String foldersLabelText = null;
      90     private int foldersLabelMnemonic = 0;
      91
      92     private String pathLabelText = null;
      93     private int pathLabelMnemonic = 0;
      94
      95     private String filterLabelText = null;
      96     private int filterLabelMnemonic = 0;
      97
      98     private JLabel fileNameLabel;
      99
     100     private void populateFileNameLabel() {
     101         if (getFileChooser().getFileSelectionMode() == JFileChooser.DIRECTORIES_ONLY) {
     102             fileNameLabel.setText(enterFolderNameLabelText);
     103             fileNameLabel.setDisplayedMnemonic(enterFolderNameLabelMnemonic);
     104         } else {
     105             fileNameLabel.setText(enterFileNameLabelText);
     106             fileNameLabel.setDisplayedMnemonic(enterFileNameLabelMnemonic);
     107         }
     108     }
     109
     110     private String fileNameString(File file) {
     111         if (file == null) {
     112             return null;
     113         } else {
     114             JFileChooser fc = getFileChooser();
     115             if (fc.isDirectorySelectionEnabled() && !fc.isFileSelectionEnabled()) {
     116                 return file.getPath();
     117             } else {
     118                 return file.getName();
     119             }
     120         }
     121     }
     122
     123     private String fileNameString(File[] files) {
     124         StringBuilder sb = new StringBuilder();
     125         for (int i = 0; files != null && i < files.length; i++) {
     126             if (i > 0) {
     127                 sb.append(" ");
     128             }
     129             if (files.length > 1) {
     130                 sb.append("\"");
     131             }
     132             sb.append(fileNameString(files[i]));
     133             if (files.length > 1) {
     134                 sb.append("\"");
     135             }
     136         }
     137         return sb.toString();
     138     }
     139
     140     public MotifFileChooserUI(JFileChooser filechooser) {
     141         super(filechooser);
     142     }
     143
     144     public String getFileName() {
     145         if(filenameTextField != null) {
     146             return filenameTextField.getText();
     147         } else {
     148             return null;
     149         }
     150     }
     151
     152     public void setFileName(String filename) {
     153         if(filenameTextField != null) {
     154             filenameTextField.setText(filename);
     155         }
     156     }
     157
     158     public String getDirectoryName() {
     159         return pathField.getText();
     160     }
     161
     162     public void setDirectoryName(String dirname) {
     163         pathField.setText(dirname);
     164     }
     165
     166     public void ensureFileIsVisible(JFileChooser fc, File f) {
     167         // PENDING(jeff)
     168     }
     169
     170     public void rescanCurrentDirectory(JFileChooser fc) {
     171         getModel().validateFileCache();
     172     }
     173
     174     public PropertyChangeListener createPropertyChangeListener(JFileChooser fc) {
     175         return new PropertyChangeListener() {
     176             public void propertyChange(PropertyChangeEvent e) {
     177                 String prop = e.getPropertyName();
     178                 if(prop.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) {
     179                     File f = (File) e.getNewValue();
     180                     if(f != null) {
     181                         setFileName(getFileChooser().getName(f));
     182                     }
     183                 } else if (prop.equals(JFileChooser.SELECTED_FILES_CHANGED_PROPERTY)) {
     184                     File[] files = (File[]) e.getNewValue();
     185                     JFileChooser fc = getFileChooser();
     186                     if (files != null && files.length > 0 && (files.length > 1 || fc.isDirectorySelectionEnabled()
     187                             || !files[0].isDirectory())) {
     188                         setFileName(fileNameString(files));
     189                     }
     190                 } else if (prop.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)) {
     191                     fileList.clearSelection();
     192                 } else if(prop.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)) {
     193                     directoryList.clearSelection();
     194                     ListSelectionModel sm = directoryList.getSelectionModel();
     195                     if (sm instanceof DefaultListSelectionModel) {
     196                         ((DefaultListSelectionModel)sm).moveLeadSelectionIndex(0);
     197                         sm.setAnchorSelectionIndex(0);
     198                     }
     199                     fileList.clearSelection();
     200                     sm = fileList.getSelectionModel();
     201                     if (sm instanceof DefaultListSelectionModel) {
     202                         ((DefaultListSelectionModel)sm).moveLeadSelectionIndex(0);
     203                         sm.setAnchorSelectionIndex(0);
     204                     }
     205                     File currentDirectory = getFileChooser().getCurrentDirectory();
     206                     if(currentDirectory != null) {
     207                         try {
     208                             setDirectoryName(ShellFolder.getNormalizedFile((File)e.getNewValue()).getPath());
     209                         } catch (IOException ioe) {
     210                             setDirectoryName(((File)e.getNewValue()).getAbsolutePath());
     211                         }
     212                         if ((getFileChooser().getFileSelectionMode() == JFileChooser.DIRECTORIES_ONLY) && !getFileChooser().isMultiSelectionEnabled()) {
     213                             setFileName(getDirectoryName());
     214                         }
     215                     }
     216                 } else if(prop.equals(JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY)) {
     217                     if (fileNameLabel != null) {
     218                         populateFileNameLabel();
     219                     }
     220                     directoryList.clearSelection();
     221                 } else if (prop.equals(JFileChooser.MULTI_SELECTION_ENABLED_CHANGED_PROPERTY)) {
     222                     if(getFileChooser().isMultiSelectionEnabled()) {
     223                         fileList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
     224                     } else {
     225                         fileList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     226                         fileList.clearSelection();
     227                         getFileChooser().setSelectedFiles(null);
     228                     }
     229                 } else if (prop.equals(JFileChooser.ACCESSORY_CHANGED_PROPERTY)) {
     230                     if(getAccessoryPanel() != null) {
     231                         if(e.getOldValue() != null) {
     232                             getAccessoryPanel().remove((JComponent) e.getOldValue());
     233                         }
     234                         JComponent accessory = (JComponent) e.getNewValue();
     235                         if(accessory != null) {
     236                             getAccessoryPanel().add(accessory, BorderLayout.CENTER);
     237                             getAccessoryPanel().setPreferredSize(PREF_ACC_SIZE);
     238                             getAccessoryPanel().setMaximumSize(MAX_SIZE);
     239                         } else {
     240                             getAccessoryPanel().setPreferredSize(ZERO_ACC_SIZE);
     241                             getAccessoryPanel().setMaximumSize(ZERO_ACC_SIZE);
     242                         }
     243                     }
     244                 } else if (prop.equals(JFileChooser.APPROVE_BUTTON_TEXT_CHANGED_PROPERTY) ||
     245                         prop.equals(JFileChooser.APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY) ||
     246                         prop.equals(JFileChooser.DIALOG_TYPE_CHANGED_PROPERTY)) {
     247                     approveButton.setText(getApproveButtonText(getFileChooser()));
     248                     approveButton.setToolTipText(getApproveButtonToolTipText(getFileChooser()));
     249                 } else if (prop.equals(JFileChooser.CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY)) {
     250                     doControlButtonsChanged(e);
     251                 } else if (prop.equals("componentOrientation")) {
     252                     ComponentOrientation o = (ComponentOrientation)e.getNewValue();
     253                     JFileChooser cc = (JFileChooser)e.getSource();
     254                     if (o != (ComponentOrientation)e.getOldValue()) {
     255                         cc.applyComponentOrientation(o);
     256                     }
     257                 }
     258             }
     259         };
     260     }
     261
     262     //
     263     // ComponentUI Interface Implementation methods
     264     //
     265     public static ComponentUI createUI(JComponent c) {
     266         return new MotifFileChooserUI((JFileChooser)c);
     267     }
     268
     269     public void installUI(JComponent c) {
     270         super.installUI(c);
     271     }
     272
     273     public void uninstallUI(JComponent c) {
     274         c.removePropertyChangeListener(filterComboBoxModel);
     275         approveButton.removeActionListener(getApproveSelectionAction());
     276         filenameTextField.removeActionListener(getApproveSelectionAction());
     277         super.uninstallUI(c);
     278     }
     279
     280     public void installComponents(JFileChooser fc) {
     281         fc.setLayout(new BorderLayout(10, 10));
     282         fc.setAlignmentX(JComponent.CENTER_ALIGNMENT);
     283
     284         @SuppressWarnings("serial") // anonymous class
     285         JPanel interior = new JPanel() {
     286             public Insets getInsets() {
     287                 return insets;
     288             }
     289         };
     290         interior.setInheritsPopupMenu(true);
     291         align(interior);
     292         interior.setLayout(new BoxLayout(interior, BoxLayout.PAGE_AXIS));
     293
     294         fc.add(interior, BorderLayout.CENTER);
     295
     296         // PENDING(jeff) - I18N
     297         JLabel l = new JLabel(pathLabelText);
     298         l.setDisplayedMnemonic(pathLabelMnemonic);
     299         align(l);
     300         interior.add(l);
     301
     302         File currentDirectory = fc.getCurrentDirectory();
     303         String curDirName = null;
     304         if(currentDirectory != null) {
     305             curDirName = currentDirectory.getPath();
     306         }
     307
     308         @SuppressWarnings("serial") // anonymous class
     309         JTextField tmp1 = new JTextField(curDirName, 35) {
     310             public Dimension getMaximumSize() {
     311                 Dimension d = super.getMaximumSize();
     312                 d.height = getPreferredSize().height;
     313                 return d;
     314             }
     315         };
     316         pathField = tmp1;
     317         pathField.setInheritsPopupMenu(true);
     318         l.setLabelFor(pathField);
     319         align(pathField);
     320
     321         // Change to folder on return
     322         pathField.addActionListener(getUpdateAction());
     323         interior.add(pathField);
     324
     325         interior.add(Box.createRigidArea(vstrut10));
     326
     327
     328         // CENTER: left, right accessory
     329         JPanel centerPanel = new JPanel();
     330         centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.LINE_AXIS));
     331         align(centerPanel);
     332
     333         // left panel - Filter & folderList
     334         JPanel leftPanel = new JPanel();
     335         leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.PAGE_AXIS));
     336         align(leftPanel);
     337
     338         // add the filter PENDING(jeff) - I18N
     339         l = new JLabel(filterLabelText);
     340         l.setDisplayedMnemonic(filterLabelMnemonic);
     341         align(l);
     342         leftPanel.add(l);
     343
     344         @SuppressWarnings("serial") // anonymous class
     345         JComboBox<FileFilter> tmp2 = new JComboBox<FileFilter>() {
     346             public Dimension getMaximumSize() {
     347                 Dimension d = super.getMaximumSize();
     348                 d.height = getPreferredSize().height;
     349                 return d;
     350             }
     351         };
     352         filterComboBox = tmp2;
     353         filterComboBox.setInheritsPopupMenu(true);
     354         l.setLabelFor(filterComboBox);
     355         filterComboBoxModel = createFilterComboBoxModel();
     356         filterComboBox.setModel(filterComboBoxModel);
     357         filterComboBox.setRenderer(createFilterComboBoxRenderer());
     358         fc.addPropertyChangeListener(filterComboBoxModel);
     359         align(filterComboBox);
     360         leftPanel.add(filterComboBox);
     361
     362         // leftPanel.add(Box.createRigidArea(vstrut10));
     363
     364         // Add the Folder List PENDING(jeff) - I18N
     365         l = new JLabel(foldersLabelText);
     366         l.setDisplayedMnemonic(foldersLabelMnemonic);
     367         align(l);
     368         leftPanel.add(l);
     369         JScrollPane sp = createDirectoryList();
     370         sp.getVerticalScrollBar().setFocusable(false);
     371         sp.getHorizontalScrollBar().setFocusable(false);
     372         sp.setInheritsPopupMenu(true);
     373         l.setLabelFor(sp.getViewport().getView());
     374         leftPanel.add(sp);
     375         leftPanel.setInheritsPopupMenu(true);
     376
     377
     378         // create files list
     379         JPanel rightPanel = new JPanel();
     380         align(rightPanel);
     381         rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.PAGE_AXIS));
     382         rightPanel.setInheritsPopupMenu(true);
     383
     384         l = new JLabel(filesLabelText);
     385         l.setDisplayedMnemonic(filesLabelMnemonic);
     386         align(l);
     387         rightPanel.add(l);
     388         sp = createFilesList();
     389         l.setLabelFor(sp.getViewport().getView());
     390         rightPanel.add(sp);
     391         sp.setInheritsPopupMenu(true);
     392
     393         centerPanel.add(leftPanel);
     394         centerPanel.add(Box.createRigidArea(hstrut10));
     395         centerPanel.add(rightPanel);
     396         centerPanel.setInheritsPopupMenu(true);
     397
     398         JComponent accessoryPanel = getAccessoryPanel();
     399         JComponent accessory = fc.getAccessory();
     400         if(accessoryPanel != null) {
     401             if(accessory == null) {
     402                 accessoryPanel.setPreferredSize(ZERO_ACC_SIZE);
     403                 accessoryPanel.setMaximumSize(ZERO_ACC_SIZE);
     404             } else {
     405                 getAccessoryPanel().add(accessory, BorderLayout.CENTER);
     406                 accessoryPanel.setPreferredSize(PREF_ACC_SIZE);
     407                 accessoryPanel.setMaximumSize(MAX_SIZE);
     408             }
     409             align(accessoryPanel);
     410             centerPanel.add(accessoryPanel);
     411             accessoryPanel.setInheritsPopupMenu(true);
     412         }
     413         interior.add(centerPanel);
     414         interior.add(Box.createRigidArea(vstrut10));
     415
     416         // add the filename field PENDING(jeff) - I18N
     417         fileNameLabel = new JLabel();
     418         populateFileNameLabel();
     419         align(fileNameLabel);
     420         interior.add(fileNameLabel);
     421
     422         @SuppressWarnings("serial") // anonymous class
     423         JTextField tmp3 = new JTextField(35) {
     424             public Dimension getMaximumSize() {
     425                 Dimension d = super.getMaximumSize();
     426                 d.height = getPreferredSize().height;
     427                 return d;
     428             }
     429         };
     430         filenameTextField = tmp3;
     431         filenameTextField.setInheritsPopupMenu(true);
     432         fileNameLabel.setLabelFor(filenameTextField);
     433         filenameTextField.addActionListener(getApproveSelectionAction());
     434         align(filenameTextField);
     435         filenameTextField.setAlignmentX(JComponent.LEFT_ALIGNMENT);
     436         interior.add(filenameTextField);
     437
     438         bottomPanel = getBottomPanel();
     439         bottomPanel.add(new JSeparator(), BorderLayout.NORTH);
     440
     441         // Add buttons
     442         JPanel buttonPanel = new JPanel();
     443         align(buttonPanel);
     444         buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS));
     445         buttonPanel.add(Box.createGlue());
     446
     447         @SuppressWarnings("serial") // anonymous class
     448         JButton tmp4 = new JButton(getApproveButtonText(fc)) {
     449             public Dimension getMaximumSize() {
     450                 return new Dimension(MAX_SIZE.width, this.getPreferredSize().height);
     451             }
     452         };
     453         approveButton = tmp4;
     454         approveButton.setMnemonic(getApproveButtonMnemonic(fc));
     455         approveButton.setToolTipText(getApproveButtonToolTipText(fc));
     456         approveButton.setInheritsPopupMenu(true);
     457         align(approveButton);
     458         approveButton.setMargin(buttonMargin);
     459         approveButton.addActionListener(getApproveSelectionAction());
     460         buttonPanel.add(approveButton);
     461         buttonPanel.add(Box.createGlue());
     462
     463         @SuppressWarnings("serial") // anonymous class
     464         JButton updateButton = new JButton(updateButtonText) {
     465             public Dimension getMaximumSize() {
     466                 return new Dimension(MAX_SIZE.width, this.getPreferredSize().height);
     467             }
     468         };
     469         updateButton.setMnemonic(updateButtonMnemonic);
     470         updateButton.setToolTipText(updateButtonToolTipText);
     471         updateButton.setInheritsPopupMenu(true);
     472         align(updateButton);
     473         updateButton.setMargin(buttonMargin);
     474         updateButton.addActionListener(getUpdateAction());
     475         buttonPanel.add(updateButton);
     476         buttonPanel.add(Box.createGlue());
     477
     478         @SuppressWarnings("serial") // anonymous class
     479         JButton cancelButton = new JButton(cancelButtonText) {
     480             public Dimension getMaximumSize() {
     481                 return new Dimension(MAX_SIZE.width, this.getPreferredSize().height);
     482             }
     483         };
     484         cancelButton.setMnemonic(cancelButtonMnemonic);
     485         cancelButton.setToolTipText(cancelButtonToolTipText);
     486         cancelButton.setInheritsPopupMenu(true);
     487         align(cancelButton);
     488         cancelButton.setMargin(buttonMargin);
     489         cancelButton.addActionListener(getCancelSelectionAction());
     490         buttonPanel.add(cancelButton);
     491         buttonPanel.add(Box.createGlue());
     492
     493         @SuppressWarnings("serial") // anonymous class
     494         JButton helpButton = new JButton(helpButtonText) {
     495             public Dimension getMaximumSize() {
     496                 return new Dimension(MAX_SIZE.width, this.getPreferredSize().height);
     497             }
     498         };
     499         helpButton.setMnemonic(helpButtonMnemonic);
     500         helpButton.setToolTipText(helpButtonToolTipText);
     501         align(helpButton);
     502         helpButton.setMargin(buttonMargin);
     503         helpButton.setEnabled(false);
     504         helpButton.setInheritsPopupMenu(true);
     505         buttonPanel.add(helpButton);
     506         buttonPanel.add(Box.createGlue());
     507         buttonPanel.setInheritsPopupMenu(true);
     508
     509         bottomPanel.add(buttonPanel, BorderLayout.SOUTH);
     510         bottomPanel.setInheritsPopupMenu(true);
     511         if (fc.getControlButtonsAreShown()) {
     512            fc.add(bottomPanel, BorderLayout.SOUTH);
     513         }
     514     }
     515
     516     protected JPanel getBottomPanel() {
     517         if (bottomPanel == null) {
     518             bottomPanel = new JPanel(new BorderLayout(0, 4));
     519         }
     520         return bottomPanel;
     521     }
     522
     523     private void doControlButtonsChanged(PropertyChangeEvent e) {
     524         if (getFileChooser().getControlButtonsAreShown()) {
     525             getFileChooser().add(bottomPanel,BorderLayout.SOUTH);
     526         } else {
     527             getFileChooser().remove(getBottomPanel());
     528         }
     529     }
     530
     531     public void uninstallComponents(JFileChooser fc) {
     532         fc.removeAll();
     533         bottomPanel = null;
     534         if (filterComboBoxModel != null) {
     535             fc.removePropertyChangeListener(filterComboBoxModel);
     536         }
     537     }
     538
     539     protected void installStrings(JFileChooser fc) {
     540         super.installStrings(fc);
     541
     542         Locale l = fc.getLocale();
     543
     544         enterFolderNameLabelText = UIManager.getString("FileChooser.enterFolderNameLabelText",l);
     545         enterFolderNameLabelMnemonic = getMnemonic("FileChooser.enterFolderNameLabelMnemonic", l);
     546         enterFileNameLabelText = UIManager.getString("FileChooser.enterFileNameLabelText",l);
     547         enterFileNameLabelMnemonic = getMnemonic("FileChooser.enterFileNameLabelMnemonic", l);
     548
     549         filesLabelText = UIManager.getString("FileChooser.filesLabelText",l);
     550         filesLabelMnemonic = getMnemonic("FileChooser.filesLabelMnemonic", l);
     551
     552         foldersLabelText = UIManager.getString("FileChooser.foldersLabelText",l);
     553         foldersLabelMnemonic = getMnemonic("FileChooser.foldersLabelMnemonic", l);
     554
     555         pathLabelText = UIManager.getString("FileChooser.pathLabelText",l);
     556         pathLabelMnemonic = getMnemonic("FileChooser.pathLabelMnemonic", l);
     557
     558         filterLabelText = UIManager.getString("FileChooser.filterLabelText",l);
     559         filterLabelMnemonic = getMnemonic("FileChooser.filterLabelMnemonic", l);
     560     }
     561
     562     private Integer getMnemonic(String key, Locale l) {
     563         return SwingUtilities2.getUIDefaultsInt(key, l);
     564     }
     565
     566     protected void installIcons(JFileChooser fc) {
     567         // Since motif doesn't have button icons, leave this empty
     568         // which overrides the supertype icon loading
     569     }
     570
     571     protected void uninstallIcons(JFileChooser fc) {
     572         // Since motif doesn't have button icons, leave this empty
     573         // which overrides the supertype icon loading
     574     }
     575
     576     protected JScrollPane createFilesList() {
     577         fileList = new JList<File>();
     578
     579         if(getFileChooser().isMultiSelectionEnabled()) {
     580             fileList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
     581         } else {
     582             fileList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     583         }
     584
     585         fileList.setModel(new MotifFileListModel());
     586         fileList.getSelectionModel().removeSelectionInterval(0, 0);
     587         fileList.setCellRenderer(new FileCellRenderer());
     588         fileList.addListSelectionListener(createListSelectionListener(getFileChooser()));
     589         fileList.addMouseListener(createDoubleClickListener(getFileChooser(), fileList));
     590         fileList.addMouseListener(new MouseAdapter() {
     591             public void mouseClicked(MouseEvent e) {
     592                 JFileChooser chooser = getFileChooser();
     593                 if (SwingUtilities.isLeftMouseButton(e) && !chooser.isMultiSelectionEnabled()) {
     594                     int index = SwingUtilities2.loc2IndexFileList(fileList, e.getPoint());
     595                     if (index >= 0) {
     596                         File file = fileList.getModel().getElementAt(index);
     597                         setFileName(chooser.getName(file));
     598                     }
     599                 }
     600             }
     601         });
     602         align(fileList);
     603         JScrollPane scrollpane = new JScrollPane(fileList);
     604         scrollpane.setPreferredSize(prefListSize);
     605         scrollpane.setMaximumSize(MAX_SIZE);
     606         align(scrollpane);
     607         fileList.setInheritsPopupMenu(true);
     608         scrollpane.setInheritsPopupMenu(true);
     609         return scrollpane;
     610     }
     611
     612     protected JScrollPane createDirectoryList() {
     613         directoryList = new JList<File>();
     614         align(directoryList);
     615
     616         directoryList.setCellRenderer(new DirectoryCellRenderer());
     617         directoryList.setModel(new MotifDirectoryListModel());
     618         directoryList.getSelectionModel().removeSelectionInterval(0, 0);
     619         directoryList.addMouseListener(createDoubleClickListener(getFileChooser(), directoryList));
     620         directoryList.addListSelectionListener(createListSelectionListener(getFileChooser()));
     621         directoryList.setInheritsPopupMenu(true);
     622
     623         JScrollPane scrollpane = new JScrollPane(directoryList);
     624         scrollpane.setMaximumSize(MAX_SIZE);
     625         scrollpane.setPreferredSize(prefListSize);
     626         scrollpane.setInheritsPopupMenu(true);
     627         align(scrollpane);
     628         return scrollpane;
     629     }
     630
     631     @Override
     632     public Dimension getPreferredSize(JComponent c) {
     633         Dimension prefSize =
     634             (getFileChooser().getAccessory() != null) ? WITH_ACCELERATOR_PREF_SIZE : PREF_SIZE;
     635         Dimension d = c.getLayout().preferredLayoutSize(c);
     636         if (d != null) {
     637             return new Dimension(d.width < prefSize.width ? prefSize.width : d.width,
     638                                  d.height < prefSize.height ? prefSize.height : d.height);
     639         } else {
     640             return prefSize;
     641         }
     642     }
     643
     644     @Override
     645     public Dimension getMinimumSize(JComponent x) {
     646         return new Dimension(MIN_WIDTH, MIN_HEIGHT);
     647     }
     648
     649     @Override
     650     public Dimension getMaximumSize(JComponent x) {
     651         return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
     652     }
     653
     654     protected void align(JComponent c) {
     655         c.setAlignmentX(JComponent.LEFT_ALIGNMENT);
     656         c.setAlignmentY(JComponent.TOP_ALIGNMENT);
     657     }
     658
     659     @SuppressWarnings("serial") // Superclass is not serializable across versions
     660     protected class FileCellRenderer extends DefaultListCellRenderer  {
     661         public Component getListCellRendererComponent(JList<?> list, Object value, int index,
     662                                                       boolean isSelected, boolean cellHasFocus) {
     663
     664             super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
     665             setText(getFileChooser().getName((File) value));
     666             setInheritsPopupMenu(true);
     667             return this;
     668         }
     669     }
     670
     671     @SuppressWarnings("serial") // Superclass is not serializable across versions
     672     protected class DirectoryCellRenderer extends DefaultListCellRenderer  {
     673         public Component getListCellRendererComponent(JList<?> list, Object value, int index,
     674                                                       boolean isSelected, boolean cellHasFocus) {
     675
     676             super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
     677             setText(getFileChooser().getName((File) value));
     678             setInheritsPopupMenu(true);
     679             return this;
     680         }
     681     }
     682
     683     @SuppressWarnings("serial") // Superclass is not serializable across versions
     684     protected class MotifDirectoryListModel extends AbstractListModel<File> implements ListDataListener {
     685         public MotifDirectoryListModel() {
     686             getModel().addListDataListener(this);
     687         }
     688
     689         public int getSize() {
     690             return getModel().getDirectories().size();
     691         }
     692
     693         public File getElementAt(int index) {
     694             return getModel().getDirectories().elementAt(index);
     695         }
     696
     697         public void intervalAdded(ListDataEvent e) {
     698             fireIntervalAdded(this, e.getIndex0(), e.getIndex1());
     699         }
     700
     701         public void intervalRemoved(ListDataEvent e) {
     702             fireIntervalRemoved(this, e.getIndex0(), e.getIndex1());
     703         }
     704
     705         // PENDING(jeff) - this is inefficient - should sent out
     706         // incremental adjustment values instead of saying that the
     707         // whole list has changed.
     708         public void fireContentsChanged() {
     709             fireContentsChanged(this, 0, getModel().getDirectories().size()-1);
     710         }
     711
     712         // PENDING(jeff) - fire the correct interval changed - currently sending
     713         // out that everything has changed
     714         public void contentsChanged(ListDataEvent e) {
     715             fireContentsChanged();
     716         }
     717
     718     }
     719
     720     @SuppressWarnings("serial") // Superclass is not serializable across versions
     721     protected class MotifFileListModel extends AbstractListModel<File> implements ListDataListener {
     722         public MotifFileListModel() {
     723             getModel().addListDataListener(this);
     724         }
     725
     726         public int getSize() {
     727             return getModel().getFiles().size();
     728         }
     729
     730         public boolean contains(Object o) {
     731             return getModel().getFiles().contains(o);
     732         }
     733
     734         public int indexOf(Object o) {
     735             return getModel().getFiles().indexOf(o);
     736         }
     737
     738         public File getElementAt(int index) {
     739             return getModel().getFiles().elementAt(index);
     740         }
     741
     742         public void intervalAdded(ListDataEvent e) {
     743             fireIntervalAdded(this, e.getIndex0(), e.getIndex1());
     744         }
     745
     746         public void intervalRemoved(ListDataEvent e) {
     747             fireIntervalRemoved(this, e.getIndex0(), e.getIndex1());
     748         }
     749
     750         // PENDING(jeff) - this is inefficient - should sent out
     751         // incremental adjustment values instead of saying that the
     752         // whole list has changed.
     753         public void fireContentsChanged() {
     754             fireContentsChanged(this, 0, getModel().getFiles().size()-1);
     755         }
     756
     757         // PENDING(jeff) - fire the interval changed
     758         public void contentsChanged(ListDataEvent e) {
     759             fireContentsChanged();
     760         }
     761
     762     }
     763
     764     //
     765     // DataModel for Types Comboxbox
     766     //
     767     protected FilterComboBoxModel createFilterComboBoxModel() {
     768         return new FilterComboBoxModel();
     769     }
     770
     771     //
     772     // Renderer for Types ComboBox
     773     //
     774     protected FilterComboBoxRenderer createFilterComboBoxRenderer() {
     775         return new FilterComboBoxRenderer();
     776     }
     777
     778
     779     /**
     780      * Render different type sizes and styles.
     781      */
     782     @SuppressWarnings("serial") // Superclass is not serializable across versions
     783     public class FilterComboBoxRenderer extends DefaultListCellRenderer {
     784         public Component getListCellRendererComponent(JList<?> list,
     785             Object value, int index, boolean isSelected,
     786             boolean cellHasFocus) {
     787
     788             super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
     789
     790             if (value != null && value instanceof FileFilter) {
     791                 setText(((FileFilter)value).getDescription());
     792             }
     793
     794             return this;
     795         }
     796     }
     797
     798     /**
     799      * Data model for a type-face selection combo-box.
     800      */
     801     @SuppressWarnings("serial") // Superclass is not serializable across versions
     802     protected class FilterComboBoxModel extends AbstractListModel<FileFilter> implements ComboBoxModel<FileFilter>,
     803             PropertyChangeListener {
     804         protected FileFilter[] filters;
     805         protected FilterComboBoxModel() {
     806             super();
     807             filters = getFileChooser().getChoosableFileFilters();
     808         }
     809
     810         public void propertyChange(PropertyChangeEvent e) {
     811             String prop = e.getPropertyName();
     812             if(prop.equals(JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY)) {
     813                 filters = (FileFilter[]) e.getNewValue();
     814                 fireContentsChanged(this, -1, -1);
     815             } else if (prop.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)) {
     816                 fireContentsChanged(this, -1, -1);
     817             }
     818         }
     819
     820         public void setSelectedItem(FileFilter filter) {
     821             if(filter != null) {
     822                 getFileChooser().setFileFilter(filter);
     823                 fireContentsChanged(this, -1, -1);
     824             }
     825         }
     826
     827         public FileFilter getSelectedItem() {
     828             // Ensure that the current filter is in the list.
     829             // NOTE: we shouldnt' have to do this, since JFileChooser adds
     830             // the filter to the choosable filters list when the filter
     831             // is set. Lets be paranoid just in case someone overrides
     832             // setFileFilter in JFileChooser.
     833             FileFilter currentFilter = getFileChooser().getFileFilter();
     834             boolean found = false;
     835             if(currentFilter != null) {
     836                 for (FileFilter filter : filters) {
     837                     if (filter == currentFilter) {
     838                         found = true;
     839                     }
     840                 }
     841                 if (!found) {
     842                     getFileChooser().addChoosableFileFilter(currentFilter);
     843                 }
     844             }
     845             return getFileChooser().getFileFilter();
     846         }
     847
     848         public int getSize() {
     849             if(filters != null) {
     850                 return filters.length;
     851             } else {
     852                 return 0;
     853             }
     854         }
     855
     856         public FileFilter getElementAt(int index) {
     857             if(index > getSize() - 1) {
     858                 // This shouldn't happen. Try to recover gracefully.
     859                 return getFileChooser().getFileFilter();
     860             }
     861             if(filters != null) {
     862                 return filters[index];
     863             } else {
     864                 return null;
     865             }
     866         }
     867     }
     868
     869     protected JButton getApproveButton(JFileChooser fc) {
     870         return approveButton;
     871     }
     872
     873 }