1 /*
   2  * Copyright (c) 1997, 2013, 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 Dimension MIN_SIZE = new Dimension(200, 300);
  69 
  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         StringBuffer buf = new StringBuffer();
 125         for (int i = 0; files != null && i < files.length; i++) {
 126             if (i > 0) {
 127                 buf.append(" ");
 128             }
 129             if (files.length > 1) {
 130                 buf.append("\"");
 131             }
 132             buf.append(fileNameString(files[i]));
 133             if (files.length > 1) {
 134                 buf.append("\"");
 135             }
 136         }
 137         return buf.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         JPanel interior = new JPanel() {
 285             public Insets getInsets() {
 286                 return insets;
 287             }
 288         };
 289         interior.setInheritsPopupMenu(true);
 290         align(interior);
 291         interior.setLayout(new BoxLayout(interior, BoxLayout.PAGE_AXIS));
 292 
 293         fc.add(interior, BorderLayout.CENTER);
 294 
 295         // PENDING(jeff) - I18N
 296         JLabel l = new JLabel(pathLabelText);
 297         l.setDisplayedMnemonic(pathLabelMnemonic);
 298         align(l);
 299         interior.add(l);
 300 
 301         File currentDirectory = fc.getCurrentDirectory();
 302         String curDirName = null;
 303         if(currentDirectory != null) {
 304             curDirName = currentDirectory.getPath();
 305         }
 306         pathField = new JTextField(curDirName) {
 307             public Dimension getMaximumSize() {
 308                 Dimension d = super.getMaximumSize();
 309                 d.height = getPreferredSize().height;
 310                 return d;
 311             }
 312         };
 313         pathField.setInheritsPopupMenu(true);
 314         l.setLabelFor(pathField);
 315         align(pathField);
 316 
 317         // Change to folder on return
 318         pathField.addActionListener(getUpdateAction());
 319         interior.add(pathField);
 320 
 321         interior.add(Box.createRigidArea(vstrut10));
 322 
 323 
 324         // CENTER: left, right accessory
 325         JPanel centerPanel = new JPanel();
 326         centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.LINE_AXIS));
 327         align(centerPanel);
 328 
 329         // left panel - Filter & folderList
 330         JPanel leftPanel = new JPanel();
 331         leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.PAGE_AXIS));
 332         align(leftPanel);
 333 
 334         // add the filter PENDING(jeff) - I18N
 335         l = new JLabel(filterLabelText);
 336         l.setDisplayedMnemonic(filterLabelMnemonic);
 337         align(l);
 338         leftPanel.add(l);
 339 
 340         filterComboBox = new JComboBox<FileFilter>() {
 341             public Dimension getMaximumSize() {
 342                 Dimension d = super.getMaximumSize();
 343                 d.height = getPreferredSize().height;
 344                 return d;
 345             }
 346         };
 347         filterComboBox.setInheritsPopupMenu(true);
 348         l.setLabelFor(filterComboBox);
 349         filterComboBoxModel = createFilterComboBoxModel();
 350         filterComboBox.setModel(filterComboBoxModel);
 351         filterComboBox.setRenderer(createFilterComboBoxRenderer());
 352         fc.addPropertyChangeListener(filterComboBoxModel);
 353         align(filterComboBox);
 354         leftPanel.add(filterComboBox);
 355 
 356         // leftPanel.add(Box.createRigidArea(vstrut10));
 357 
 358         // Add the Folder List PENDING(jeff) - I18N
 359         l = new JLabel(foldersLabelText);
 360         l.setDisplayedMnemonic(foldersLabelMnemonic);
 361         align(l);
 362         leftPanel.add(l);
 363         JScrollPane sp = createDirectoryList();
 364         sp.getVerticalScrollBar().setFocusable(false);
 365         sp.getHorizontalScrollBar().setFocusable(false);
 366         sp.setInheritsPopupMenu(true);
 367         l.setLabelFor(sp.getViewport().getView());
 368         leftPanel.add(sp);
 369         leftPanel.setInheritsPopupMenu(true);
 370 
 371 
 372         // create files list
 373         JPanel rightPanel = new JPanel();
 374         align(rightPanel);
 375         rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.PAGE_AXIS));
 376         rightPanel.setInheritsPopupMenu(true);
 377 
 378         l = new JLabel(filesLabelText);
 379         l.setDisplayedMnemonic(filesLabelMnemonic);
 380         align(l);
 381         rightPanel.add(l);
 382         sp = createFilesList();
 383         l.setLabelFor(sp.getViewport().getView());
 384         rightPanel.add(sp);
 385         sp.setInheritsPopupMenu(true);
 386 
 387         centerPanel.add(leftPanel);
 388         centerPanel.add(Box.createRigidArea(hstrut10));
 389         centerPanel.add(rightPanel);
 390         centerPanel.setInheritsPopupMenu(true);
 391 
 392         JComponent accessoryPanel = getAccessoryPanel();
 393         JComponent accessory = fc.getAccessory();
 394         if(accessoryPanel != null) {
 395             if(accessory == null) {
 396                 accessoryPanel.setPreferredSize(ZERO_ACC_SIZE);
 397                 accessoryPanel.setMaximumSize(ZERO_ACC_SIZE);
 398             } else {
 399                 getAccessoryPanel().add(accessory, BorderLayout.CENTER);
 400                 accessoryPanel.setPreferredSize(PREF_ACC_SIZE);
 401                 accessoryPanel.setMaximumSize(MAX_SIZE);
 402             }
 403             align(accessoryPanel);
 404             centerPanel.add(accessoryPanel);
 405             accessoryPanel.setInheritsPopupMenu(true);
 406         }
 407         interior.add(centerPanel);
 408         interior.add(Box.createRigidArea(vstrut10));
 409 
 410         // add the filename field PENDING(jeff) - I18N
 411         fileNameLabel = new JLabel();
 412         populateFileNameLabel();
 413         align(fileNameLabel);
 414         interior.add(fileNameLabel);
 415 
 416         filenameTextField = new JTextField() {
 417             public Dimension getMaximumSize() {
 418                 Dimension d = super.getMaximumSize();
 419                 d.height = getPreferredSize().height;
 420                 return d;
 421             }
 422         };
 423         filenameTextField.setInheritsPopupMenu(true);
 424         fileNameLabel.setLabelFor(filenameTextField);
 425         filenameTextField.addActionListener(getApproveSelectionAction());
 426         align(filenameTextField);
 427         filenameTextField.setAlignmentX(JComponent.LEFT_ALIGNMENT);
 428         interior.add(filenameTextField);
 429 
 430         bottomPanel = getBottomPanel();
 431         bottomPanel.add(new JSeparator(), BorderLayout.NORTH);
 432 
 433         // Add buttons
 434         JPanel buttonPanel = new JPanel();
 435         align(buttonPanel);
 436         buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS));
 437         buttonPanel.add(Box.createGlue());
 438 
 439         approveButton = new JButton(getApproveButtonText(fc)) {
 440             public Dimension getMaximumSize() {
 441                 return new Dimension(MAX_SIZE.width, this.getPreferredSize().height);
 442             }
 443         };
 444         approveButton.setMnemonic(getApproveButtonMnemonic(fc));
 445         approveButton.setToolTipText(getApproveButtonToolTipText(fc));
 446         approveButton.setInheritsPopupMenu(true);
 447         align(approveButton);
 448         approveButton.setMargin(buttonMargin);
 449         approveButton.addActionListener(getApproveSelectionAction());
 450         buttonPanel.add(approveButton);
 451         buttonPanel.add(Box.createGlue());
 452 
 453         JButton updateButton = new JButton(updateButtonText) {
 454             public Dimension getMaximumSize() {
 455                 return new Dimension(MAX_SIZE.width, this.getPreferredSize().height);
 456             }
 457         };
 458         updateButton.setMnemonic(updateButtonMnemonic);
 459         updateButton.setToolTipText(updateButtonToolTipText);
 460         updateButton.setInheritsPopupMenu(true);
 461         align(updateButton);
 462         updateButton.setMargin(buttonMargin);
 463         updateButton.addActionListener(getUpdateAction());
 464         buttonPanel.add(updateButton);
 465         buttonPanel.add(Box.createGlue());
 466 
 467         JButton cancelButton = new JButton(cancelButtonText) {
 468             public Dimension getMaximumSize() {
 469                 return new Dimension(MAX_SIZE.width, this.getPreferredSize().height);
 470             }
 471         };
 472         cancelButton.setMnemonic(cancelButtonMnemonic);
 473         cancelButton.setToolTipText(cancelButtonToolTipText);
 474         cancelButton.setInheritsPopupMenu(true);
 475         align(cancelButton);
 476         cancelButton.setMargin(buttonMargin);
 477         cancelButton.addActionListener(getCancelSelectionAction());
 478         buttonPanel.add(cancelButton);
 479         buttonPanel.add(Box.createGlue());
 480 
 481         JButton helpButton = new JButton(helpButtonText) {
 482             public Dimension getMaximumSize() {
 483                 return new Dimension(MAX_SIZE.width, this.getPreferredSize().height);
 484             }
 485         };
 486         helpButton.setMnemonic(helpButtonMnemonic);
 487         helpButton.setToolTipText(helpButtonToolTipText);
 488         align(helpButton);
 489         helpButton.setMargin(buttonMargin);
 490         helpButton.setEnabled(false);
 491         helpButton.setInheritsPopupMenu(true);
 492         buttonPanel.add(helpButton);
 493         buttonPanel.add(Box.createGlue());
 494         buttonPanel.setInheritsPopupMenu(true);
 495 
 496         bottomPanel.add(buttonPanel, BorderLayout.SOUTH);
 497         bottomPanel.setInheritsPopupMenu(true);
 498         if (fc.getControlButtonsAreShown()) {
 499            fc.add(bottomPanel, BorderLayout.SOUTH);
 500         }
 501     }
 502 
 503     protected JPanel getBottomPanel() {
 504         if (bottomPanel == null) {
 505             bottomPanel = new JPanel(new BorderLayout(0, 4));
 506         }
 507         return bottomPanel;
 508     }
 509 
 510     private void doControlButtonsChanged(PropertyChangeEvent e) {
 511         if (getFileChooser().getControlButtonsAreShown()) {
 512             getFileChooser().add(bottomPanel,BorderLayout.SOUTH);
 513         } else {
 514             getFileChooser().remove(getBottomPanel());
 515         }
 516     }
 517 
 518     public void uninstallComponents(JFileChooser fc) {
 519         fc.removeAll();
 520         bottomPanel = null;
 521         if (filterComboBoxModel != null) {
 522             fc.removePropertyChangeListener(filterComboBoxModel);
 523         }
 524     }
 525 
 526     protected void installStrings(JFileChooser fc) {
 527         super.installStrings(fc);
 528 
 529         Locale l = fc.getLocale();
 530 
 531         enterFolderNameLabelText = UIManager.getString("FileChooser.enterFolderNameLabelText",l);
 532         enterFolderNameLabelMnemonic = getMnemonic("FileChooser.enterFolderNameLabelMnemonic", l);
 533         enterFileNameLabelText = UIManager.getString("FileChooser.enterFileNameLabelText",l);
 534         enterFileNameLabelMnemonic = getMnemonic("FileChooser.enterFileNameLabelMnemonic", l);
 535 
 536         filesLabelText = UIManager.getString("FileChooser.filesLabelText",l);
 537         filesLabelMnemonic = getMnemonic("FileChooser.filesLabelMnemonic", l);
 538 
 539         foldersLabelText = UIManager.getString("FileChooser.foldersLabelText",l);
 540         foldersLabelMnemonic = getMnemonic("FileChooser.foldersLabelMnemonic", l);
 541 
 542         pathLabelText = UIManager.getString("FileChooser.pathLabelText",l);
 543         pathLabelMnemonic = getMnemonic("FileChooser.pathLabelMnemonic", l);
 544 
 545         filterLabelText = UIManager.getString("FileChooser.filterLabelText",l);
 546         filterLabelMnemonic = getMnemonic("FileChooser.filterLabelMnemonic", l);
 547     }
 548 
 549     private Integer getMnemonic(String key, Locale l) {
 550         return SwingUtilities2.getUIDefaultsInt(key, l);
 551     }
 552 
 553     protected void installIcons(JFileChooser fc) {
 554         // Since motif doesn't have button icons, leave this empty
 555         // which overrides the supertype icon loading
 556     }
 557 
 558     protected void uninstallIcons(JFileChooser fc) {
 559         // Since motif doesn't have button icons, leave this empty
 560         // which overrides the supertype icon loading
 561     }
 562 
 563     protected JScrollPane createFilesList() {
 564         fileList = new JList<File>();
 565 
 566         if(getFileChooser().isMultiSelectionEnabled()) {
 567             fileList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
 568         } else {
 569             fileList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 570         }
 571 
 572         fileList.setModel(new MotifFileListModel());
 573         fileList.getSelectionModel().removeSelectionInterval(0, 0);
 574         fileList.setCellRenderer(new FileCellRenderer());
 575         fileList.addListSelectionListener(createListSelectionListener(getFileChooser()));
 576         fileList.addMouseListener(createDoubleClickListener(getFileChooser(), fileList));
 577         fileList.addMouseListener(new MouseAdapter() {
 578             public void mouseClicked(MouseEvent e) {
 579                 JFileChooser chooser = getFileChooser();
 580                 if (SwingUtilities.isLeftMouseButton(e) && !chooser.isMultiSelectionEnabled()) {
 581                     int index = SwingUtilities2.loc2IndexFileList(fileList, e.getPoint());
 582                     if (index >= 0) {
 583                         File file = fileList.getModel().getElementAt(index);
 584                         setFileName(chooser.getName(file));
 585                     }
 586                 }
 587             }
 588         });
 589         align(fileList);
 590         JScrollPane scrollpane = new JScrollPane(fileList);
 591         scrollpane.setPreferredSize(prefListSize);
 592         scrollpane.setMaximumSize(MAX_SIZE);
 593         align(scrollpane);
 594         fileList.setInheritsPopupMenu(true);
 595         scrollpane.setInheritsPopupMenu(true);
 596         return scrollpane;
 597     }
 598 
 599     protected JScrollPane createDirectoryList() {
 600         directoryList = new JList<File>();
 601         align(directoryList);
 602 
 603         directoryList.setCellRenderer(new DirectoryCellRenderer());
 604         directoryList.setModel(new MotifDirectoryListModel());
 605         directoryList.getSelectionModel().removeSelectionInterval(0, 0);
 606         directoryList.addMouseListener(createDoubleClickListener(getFileChooser(), directoryList));
 607         directoryList.addListSelectionListener(createListSelectionListener(getFileChooser()));
 608         directoryList.setInheritsPopupMenu(true);
 609 
 610         JScrollPane scrollpane = new JScrollPane(directoryList);
 611         scrollpane.setMaximumSize(MAX_SIZE);
 612         scrollpane.setPreferredSize(prefListSize);
 613         scrollpane.setInheritsPopupMenu(true);
 614         align(scrollpane);
 615         return scrollpane;
 616     }
 617 
 618     public Dimension getPreferredSize(JComponent c) {
 619         Dimension prefSize =
 620             (getFileChooser().getAccessory() != null) ? WITH_ACCELERATOR_PREF_SIZE : PREF_SIZE;
 621         Dimension d = c.getLayout().preferredLayoutSize(c);
 622         if (d != null) {
 623             return new Dimension(d.width < prefSize.width ? prefSize.width : d.width,
 624                                  d.height < prefSize.height ? prefSize.height : d.height);
 625         } else {
 626             return prefSize;
 627         }
 628     }
 629 
 630     public Dimension getMinimumSize(JComponent x)  {
 631         return MIN_SIZE;
 632     }
 633 
 634     public Dimension getMaximumSize(JComponent x) {
 635         return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
 636     }
 637 
 638     protected void align(JComponent c) {
 639         c.setAlignmentX(JComponent.LEFT_ALIGNMENT);
 640         c.setAlignmentY(JComponent.TOP_ALIGNMENT);
 641     }
 642 
 643     protected class FileCellRenderer extends DefaultListCellRenderer  {
 644         public Component getListCellRendererComponent(JList list, Object value, int index,
 645                                                       boolean isSelected, boolean cellHasFocus) {
 646 
 647             super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
 648             setText(getFileChooser().getName((File) value));
 649             setInheritsPopupMenu(true);
 650             return this;
 651         }
 652     }
 653 
 654     protected class DirectoryCellRenderer extends DefaultListCellRenderer  {
 655         public Component getListCellRendererComponent(JList list, Object value, int index,
 656                                                       boolean isSelected, boolean cellHasFocus) {
 657 
 658             super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
 659             setText(getFileChooser().getName((File) value));
 660             setInheritsPopupMenu(true);
 661             return this;
 662         }
 663     }
 664 
 665     protected class MotifDirectoryListModel extends AbstractListModel<File> implements ListDataListener {
 666         public MotifDirectoryListModel() {
 667             getModel().addListDataListener(this);
 668         }
 669 
 670         public int getSize() {
 671             return getModel().getDirectories().size();
 672         }
 673 
 674         public File getElementAt(int index) {
 675             return getModel().getDirectories().elementAt(index);
 676         }
 677 
 678         public void intervalAdded(ListDataEvent e) {
 679             fireIntervalAdded(this, e.getIndex0(), e.getIndex1());
 680         }
 681 
 682         public void intervalRemoved(ListDataEvent e) {
 683             fireIntervalRemoved(this, e.getIndex0(), e.getIndex1());
 684         }
 685 
 686         // PENDING(jeff) - this is inefficient - should sent out
 687         // incremental adjustment values instead of saying that the
 688         // whole list has changed.
 689         public void fireContentsChanged() {
 690             fireContentsChanged(this, 0, getModel().getDirectories().size()-1);
 691         }
 692 
 693         // PENDING(jeff) - fire the correct interval changed - currently sending
 694         // out that everything has changed
 695         public void contentsChanged(ListDataEvent e) {
 696             fireContentsChanged();
 697         }
 698 
 699     }
 700 
 701     protected class MotifFileListModel extends AbstractListModel<File> implements ListDataListener {
 702         public MotifFileListModel() {
 703             getModel().addListDataListener(this);
 704         }
 705 
 706         public int getSize() {
 707             return getModel().getFiles().size();
 708         }
 709 
 710         public boolean contains(Object o) {
 711             return getModel().getFiles().contains(o);
 712         }
 713 
 714         public int indexOf(Object o) {
 715             return getModel().getFiles().indexOf(o);
 716         }
 717 
 718         public File getElementAt(int index) {
 719             return getModel().getFiles().elementAt(index);
 720         }
 721 
 722         public void intervalAdded(ListDataEvent e) {
 723             fireIntervalAdded(this, e.getIndex0(), e.getIndex1());
 724         }
 725 
 726         public void intervalRemoved(ListDataEvent e) {
 727             fireIntervalRemoved(this, e.getIndex0(), e.getIndex1());
 728         }
 729 
 730         // PENDING(jeff) - this is inefficient - should sent out
 731         // incremental adjustment values instead of saying that the
 732         // whole list has changed.
 733         public void fireContentsChanged() {
 734             fireContentsChanged(this, 0, getModel().getFiles().size()-1);
 735         }
 736 
 737         // PENDING(jeff) - fire the interval changed
 738         public void contentsChanged(ListDataEvent e) {
 739             fireContentsChanged();
 740         }
 741 
 742     }
 743 
 744     //
 745     // DataModel for Types Comboxbox
 746     //
 747     protected FilterComboBoxModel createFilterComboBoxModel() {
 748         return new FilterComboBoxModel();
 749     }
 750 
 751     //
 752     // Renderer for Types ComboBox
 753     //
 754     protected FilterComboBoxRenderer createFilterComboBoxRenderer() {
 755         return new FilterComboBoxRenderer();
 756     }
 757 
 758 
 759     /**
 760      * Render different type sizes and styles.
 761      */
 762     public class FilterComboBoxRenderer extends DefaultListCellRenderer {
 763         public Component getListCellRendererComponent(JList list,
 764             Object value, int index, boolean isSelected,
 765             boolean cellHasFocus) {
 766 
 767             super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
 768 
 769             if (value != null && value instanceof FileFilter) {
 770                 setText(((FileFilter)value).getDescription());
 771             }
 772 
 773             return this;
 774         }
 775     }
 776 
 777     /**
 778      * Data model for a type-face selection combo-box.
 779      */
 780     protected class FilterComboBoxModel extends AbstractListModel<FileFilter> implements ComboBoxModel<FileFilter>,
 781             PropertyChangeListener {
 782         protected FileFilter[] filters;
 783         protected FilterComboBoxModel() {
 784             super();
 785             filters = getFileChooser().getChoosableFileFilters();
 786         }
 787 
 788         public void propertyChange(PropertyChangeEvent e) {
 789             String prop = e.getPropertyName();
 790             if(prop.equals(JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY)) {
 791                 filters = (FileFilter[]) e.getNewValue();
 792                 fireContentsChanged(this, -1, -1);
 793             } else if (prop.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)) {
 794                 fireContentsChanged(this, -1, -1);
 795             }
 796         }
 797 
 798         public void setSelectedItem(Object filter) {
 799             if(filter != null) {
 800                 getFileChooser().setFileFilter((FileFilter) filter);
 801                 fireContentsChanged(this, -1, -1);
 802             }
 803         }
 804 
 805         public Object getSelectedItem() {
 806             // Ensure that the current filter is in the list.
 807             // NOTE: we shouldnt' have to do this, since JFileChooser adds
 808             // the filter to the choosable filters list when the filter
 809             // is set. Lets be paranoid just in case someone overrides
 810             // setFileFilter in JFileChooser.
 811             FileFilter currentFilter = getFileChooser().getFileFilter();
 812             boolean found = false;
 813             if(currentFilter != null) {
 814                 for (FileFilter filter : filters) {
 815                     if (filter == currentFilter) {
 816                         found = true;
 817                     }
 818                 }
 819                 if (!found) {
 820                     getFileChooser().addChoosableFileFilter(currentFilter);
 821                 }
 822             }
 823             return getFileChooser().getFileFilter();
 824         }
 825 
 826         public int getSize() {
 827             if(filters != null) {
 828                 return filters.length;
 829             } else {
 830                 return 0;
 831             }
 832         }
 833 
 834         public FileFilter getElementAt(int index) {
 835             if(index > getSize() - 1) {
 836                 // This shouldn't happen. Try to recover gracefully.
 837                 return getFileChooser().getFileFilter();
 838             }
 839             if(filters != null) {
 840                 return filters[index];
 841             } else {
 842                 return null;
 843             }
 844         }
 845     }
 846 
 847     protected JButton getApproveButton(JFileChooser fc) {
 848         return approveButton;
 849     }
 850 
 851 }