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