/*******************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tiny Look and Feel * * (C) Copyright 2003 - 2007 Hans Bickel * * For
* licensing information and credits, please refer to the * comment in file
* de.muntjak.tinylookandfeel.TinyLookAndFeel * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
/*
* This is an almost unchanged version of MetalFileChooserUI.
* @(#)MetalFileChooserUI.java 1.45 02/04/11 Copyright 2002 Sun Microsystems,
* Inc. All rights reserved. SUN PROPRIETARY/CONFIDENTIAL. Use is subject to
* license terms.
*/
package de.muntjak.tinylookandfeel;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.ComponentOrientation;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.DateFormat;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.EventObject;
import java.util.Iterator;
import java.util.Locale;
import java.util.Vector;
import javax.swing.AbstractAction;
import javax.swing.AbstractListModel;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultListCellRenderer;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.KeyStroke;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.LookAndFeel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileSystemView;
import javax.swing.plaf.ActionMapUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.TableHeaderUI;
import javax.swing.plaf.basic.BasicDirectoryModel;
import javax.swing.plaf.basic.BasicFileChooserUI;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.text.Position;
import sun.awt.shell.ShellFolder;
import de.muntjak.tinylookandfeel.borders.TinyToolButtonBorder;
import de.muntjak.tinylookandfeel.table.SortableTableData;
/**
* TinyFileChooserUI is a customized MetalFileChooserUI.
*
* @author Hans Bickel
* @version 1.3.7
*/
@SuppressWarnings (
{ "all" } )
public class TinyFileChooserUI extends BasicFileChooserUI
{
/** Key for a button's isFileChooserButton client property */
public static final String IS_FILE_CHOOSER_BUTTON_KEY = "JFileChooser.isFileChooserButton";
// This one is evaluated at ensureFileIsVisible() and
// will only be false while DetailsTableModel restores
// the table selection
private boolean doScrolling = true;
private JPanel centerPanel;
private TinyDirectoryModel directoryModel = null;
private JLabel lookInLabel;
private JComboBox directoryComboBox;
private DirectoryComboBoxModel directoryComboBoxModel;
private Action directoryComboBoxAction = new DirectoryComboBoxAction ();
private FilterComboBoxModel filterComboBoxModel;
private JTextField fileNameTextField;
private JToggleButton listViewButton;
private JToggleButton detailsViewButton;
private JPanel listViewPanel;
private JPanel detailsViewPanel;
private JPanel currentViewPanel;
private FocusListener editorFocusListener = new FocusAdapter ()
{
public void focusLost ( FocusEvent e )
{
if ( !e.isTemporary () )
{
applyEdit ();
}
}
};
private boolean useShellFolder;
private ListSelectionModel listSelectionModel;
private JList list;
private JTable detailsTable;
private DetailsTableModel detailsTableModel;
private JButton approveButton;
private JButton cancelButton;
private JPanel buttonPanel;
private JPanel bottomPanel;
private JComboBox filterComboBox;
private static final Dimension hstrut1 = new Dimension ( 1, 1 );
private static final Dimension hstrut4 = new Dimension ( 4, 1 );
private static final Dimension hstrut11 = new Dimension ( 11, 1 );
private static final Dimension vstrut5 = new Dimension ( 1, 5 );
private static final Insets shrinkwrap = new Insets ( 2, 2, 2, 2 );
// Preferred and Minimum sizes for the dialog box
private static int PREF_WIDTH = 500;
private static int PREF_HEIGHT = 326;
private static Dimension PREF_SIZE = new Dimension ( PREF_WIDTH, PREF_HEIGHT );
private static int MIN_WIDTH = 500;
private static int MIN_HEIGHT = 326;
private static Dimension MIN_SIZE = new Dimension ( MIN_WIDTH, MIN_HEIGHT );
private static int LIST_PREF_WIDTH = 405;
private static int LIST_PREF_HEIGHT = 183;
private static Dimension LIST_PREF_SIZE = new Dimension ( LIST_PREF_WIDTH,
LIST_PREF_HEIGHT );
private static final int COLUMN_FILENAME = 0;
private static final int COLUMN_FILESIZE = 1;
private static final int COLUMN_FILETYPE = 2;
private static final int COLUMN_FILEDATE = 3;
// private static final int COLUMN_FILEATTR = 4;
private static final int COLUMN_COLCOUNT = 4;
// name, size, type, last modified, attributes
private int [] COLUMN_WIDTHS =
{ 150, 75, 130, 100 };
// Labels, mnemonics, and tooltips (oh my!)
private int lookInLabelMnemonic = 0;
private String lookInLabelText = null;
private String saveInLabelText = null;
private int fileNameLabelMnemonic = 0;
private String fileNameLabelText = null;
private int filesOfTypeLabelMnemonic = 0;
private String filesOfTypeLabelText = null;
private String upFolderToolTipText = null;
private String upFolderAccessibleName = null;
private String homeFolderToolTipText = null;
private String homeFolderAccessibleName = null;
private String newFolderToolTipText = null;
private String newFolderAccessibleName = null;
private String listViewButtonToolTipText = null;
private String listViewButtonAccessibleName = null;
private String detailsViewButtonToolTipText = null;
private String detailsViewButtonAccessibleName = null;
private String fileNameHeaderText = null;
private String fileSizeHeaderText = null;
private String fileTypeHeaderText = null;
private String fileDateHeaderText = null;
private String fileAttrHeaderText = null;
//
// ComponentUI Interface Implementation methods
//
public static ComponentUI createUI ( JComponent c )
{
return new TinyFileChooserUI ( ( JFileChooser ) c );
}
public TinyFileChooserUI ( JFileChooser filechooser )
{
super ( filechooser );
}
public void uninstallComponents ( JFileChooser fc )
{
fc.removeAll ();
bottomPanel = null;
buttonPanel = null;
}
public void installComponents ( JFileChooser fc )
{
FileSystemView fsv = fc.getFileSystemView ();
fc.setBorder ( new EmptyBorder ( 12, 12, 11, 11 ) );
fc.setLayout ( new BorderLayout ( 0, 11 ) );
// ********************************* //
// **** Construct the top panel **** //
// ********************************* //
// Directory manipulation buttons
JPanel topPanel = new JPanel ( new BorderLayout ( 11, 0 ) );
JPanel topButtonPanel = new JPanel ();
topButtonPanel
.setLayout ( new BoxLayout ( topButtonPanel, BoxLayout.X_AXIS ) );
topPanel.add ( topButtonPanel, BorderLayout.EAST );
// Add the top panel to the fileChooser
fc.add ( topPanel, BorderLayout.NORTH );
// ComboBox Label
lookInLabel = new JLabel ( lookInLabelText );
lookInLabel.setDisplayedMnemonic ( lookInLabelMnemonic );
topPanel.add ( lookInLabel, BorderLayout.BEFORE_LINE_BEGINS );
// CurrentDir ComboBox
directoryComboBox = new JComboBox ();
directoryComboBox.putClientProperty (
"JComboBox.lightweightKeyboardNavigation", "Lightweight" );
lookInLabel.setLabelFor ( directoryComboBox );
directoryComboBoxModel = createDirectoryComboBoxModel ( fc );
directoryComboBox.setModel ( directoryComboBoxModel );
directoryComboBox.addActionListener ( directoryComboBoxAction );
directoryComboBox.setRenderer ( createDirectoryComboBoxRenderer ( fc ) );
directoryComboBox.setAlignmentX ( JComponent.LEFT_ALIGNMENT );
directoryComboBox.setAlignmentY ( JComponent.TOP_ALIGNMENT );
directoryComboBox.setMaximumRowCount ( 8 );
topPanel.add ( directoryComboBox, BorderLayout.CENTER );
Border toolButtonBorder = new TinyToolButtonBorder ();
// Up Button
Insets margin = new Insets ( 2, 2, 2, 2 );
JButton b = new JButton ( upFolderIcon );
b.putClientProperty ( IS_FILE_CHOOSER_BUTTON_KEY, Boolean.TRUE );
b.setOpaque ( false );
b.setText ( null );
b.setIcon ( upFolderIcon );
b.setToolTipText ( upFolderToolTipText );
b.getAccessibleContext ().setAccessibleName ( upFolderAccessibleName );
b.setAlignmentX ( JComponent.LEFT_ALIGNMENT );
b.setAlignmentY ( JComponent.CENTER_ALIGNMENT );
b.setMargin ( margin );
b.addActionListener ( getChangeToParentDirectoryAction () );
b.setBorder ( toolButtonBorder );
topButtonPanel.add ( b );
// Home Button
File homeDir = fsv.getHomeDirectory ();
String toolTipText = homeFolderToolTipText;
if ( fsv.isRoot ( homeDir ) )
{
toolTipText = getFileView ( fc ).getName ( homeDir ); // Probably
// "Desktop".
}
b = new JButton ( homeFolderIcon );
b.putClientProperty ( IS_FILE_CHOOSER_BUTTON_KEY, Boolean.TRUE );
b.setToolTipText ( toolTipText );
b.getAccessibleContext ().setAccessibleName ( homeFolderAccessibleName );
b.setAlignmentX ( JComponent.LEFT_ALIGNMENT );
b.setAlignmentY ( JComponent.CENTER_ALIGNMENT );
b.setMargin ( margin );
b.addActionListener ( getGoHomeAction () );
b.setBorder ( toolButtonBorder );
topButtonPanel.add ( b );
// New Directory Button
if ( !UIManager.getBoolean ( "FileChooser.readOnly" ) )
{
b = new JButton ( newFolderIcon );
b.putClientProperty ( IS_FILE_CHOOSER_BUTTON_KEY, Boolean.TRUE );
b.setText ( null );
b.setToolTipText ( newFolderToolTipText );
b.getAccessibleContext ().setAccessibleName ( newFolderAccessibleName );
b.setAlignmentX ( JComponent.LEFT_ALIGNMENT );
b.setAlignmentY ( JComponent.CENTER_ALIGNMENT );
b.setMargin ( margin );
b.addActionListener ( getNewFolderAction () );
b.setBorder ( toolButtonBorder );
topButtonPanel.add ( b );
}
topButtonPanel.add ( Box.createRigidArea ( hstrut1 ) );
// View button group
ButtonGroup viewButtonGroup = new ButtonGroup ();
class ViewButtonListener implements ActionListener
{
JFileChooser fc;
ViewButtonListener ( JFileChooser fc )
{
this.fc = fc;
}
public void actionPerformed ( ActionEvent e )
{
JToggleButton b = ( JToggleButton ) e.getSource ();
JPanel oldViewPanel = currentViewPanel;
if ( b == detailsViewButton )
{
if ( detailsViewPanel == null )
{
detailsViewPanel = createDetailsView ( fc );
detailsViewPanel.setPreferredSize ( LIST_PREF_SIZE );
}
currentViewPanel = detailsViewPanel;
}
else
{
currentViewPanel = listViewPanel;
}
if ( currentViewPanel != oldViewPanel )
{
centerPanel.remove ( oldViewPanel );
centerPanel.add ( currentViewPanel, BorderLayout.CENTER );
centerPanel.revalidate ();
centerPanel.repaint ();
}
}
}
ViewButtonListener viewButtonListener = new ViewButtonListener ( fc );
// List Button
listViewButton = new JToggleButton ( listViewIcon );
listViewButton
.putClientProperty ( IS_FILE_CHOOSER_BUTTON_KEY, Boolean.TRUE );
listViewButton.setToolTipText ( listViewButtonToolTipText );
listViewButton.getAccessibleContext ().setAccessibleName (
listViewButtonAccessibleName );
listViewButton.setSelected ( true );
listViewButton.setAlignmentX ( JComponent.LEFT_ALIGNMENT );
listViewButton.setAlignmentY ( JComponent.CENTER_ALIGNMENT );
listViewButton.setMargin ( /* shrinkwrap */new Insets ( 4, 2, 5, 2 ) );
listViewButton.addActionListener ( viewButtonListener );
listViewButton.setBorder ( toolButtonBorder );
topButtonPanel.add ( listViewButton );
topButtonPanel.add ( Box.createRigidArea ( hstrut1 ) );
viewButtonGroup.add ( listViewButton );
// Details Button
detailsViewButton = new JToggleButton ( detailsViewIcon );
detailsViewButton.putClientProperty ( IS_FILE_CHOOSER_BUTTON_KEY,
Boolean.TRUE );
detailsViewButton.setToolTipText ( detailsViewButtonToolTipText );
detailsViewButton.getAccessibleContext ().setAccessibleName (
detailsViewButtonAccessibleName );
detailsViewButton.setAlignmentX ( JComponent.LEFT_ALIGNMENT );
detailsViewButton.setAlignmentY ( JComponent.CENTER_ALIGNMENT );
detailsViewButton.setMargin ( /* shrinkwrap */new Insets ( 4, 2, 5, 2 ) );
detailsViewButton.addActionListener ( viewButtonListener );
detailsViewButton.setBorder ( toolButtonBorder );
topButtonPanel.add ( detailsViewButton );
viewButtonGroup.add ( detailsViewButton );
// Use ShellFolder class to populate combobox only if
// FileSystemView.getRoots() returns one folder and that is
// the same as the first item in the ShellFolder combobox list.
{
useShellFolder = false;
File [] roots = fsv.getRoots ();
if ( roots != null && roots.length == 1 )
{
File [] cbFolders = ( File [] ) ShellFolder
.get ( "fileChooserComboBoxFolders" );
if ( cbFolders != null && cbFolders.length > 0
&& roots [ 0 ] == cbFolders [ 0 ] )
{
useShellFolder = true;
}
}
}
// ************************************** //
// ******* Add the directory pane ******* //
// ************************************** //
centerPanel = new JPanel ( new BorderLayout () );
listViewPanel = createList ( fc );
listSelectionModel = list.getSelectionModel ();
listViewPanel.setPreferredSize ( LIST_PREF_SIZE );
centerPanel.add ( listViewPanel, BorderLayout.CENTER );
currentViewPanel = listViewPanel;
centerPanel.add ( getAccessoryPanel (), BorderLayout.AFTER_LINE_ENDS );
JComponent accessory = fc.getAccessory ();
if ( accessory != null )
{
getAccessoryPanel ().add ( accessory );
}
fc.add ( centerPanel, BorderLayout.CENTER );
// ********************************** //
// **** Construct the bottom panel ** //
// ********************************** //
JPanel bottomPanel = getBottomPanel ();
bottomPanel.setLayout ( new BoxLayout ( bottomPanel, BoxLayout.Y_AXIS ) );
fc.add ( bottomPanel, BorderLayout.SOUTH );
// FileName label and textfield
JPanel fileNamePanel = new JPanel ();
fileNamePanel.setLayout ( new BoxLayout ( fileNamePanel,
BoxLayout.LINE_AXIS ) );
bottomPanel.add ( fileNamePanel );
bottomPanel.add ( Box.createRigidArea ( vstrut5 ) );
AlignedLabel fileNameLabel = new AlignedLabel ( fileNameLabelText );
fileNameLabel.setDisplayedMnemonic ( fileNameLabelMnemonic );
fileNamePanel.add ( fileNameLabel );
fileNameTextField = new JTextField ()
{
public Dimension getMaximumSize ()
{
return new Dimension ( Short.MAX_VALUE,
super.getPreferredSize ().height );
}
};
fileNamePanel.add ( fileNameTextField );
fileNameLabel.setLabelFor ( fileNameTextField );
fileNameTextField.addFocusListener ( new FocusAdapter ()
{
public void focusGained ( FocusEvent e )
{
if ( !getFileChooser ().isMultiSelectionEnabled () )
{
listSelectionModel.clearSelection ();
}
}
} );
if ( fc.isMultiSelectionEnabled () )
{
setFileName ( fileNameString ( fc.getSelectedFiles () ) );
}
else
{
setFileName ( fileNameString ( fc.getSelectedFile () ) );
}
// Filetype label and combobox
JPanel filesOfTypePanel = new JPanel ();
filesOfTypePanel.setLayout ( new BoxLayout ( filesOfTypePanel,
BoxLayout.LINE_AXIS ) );
bottomPanel.add ( filesOfTypePanel );
AlignedLabel filesOfTypeLabel = new AlignedLabel ( filesOfTypeLabelText );
filesOfTypeLabel.setDisplayedMnemonic ( filesOfTypeLabelMnemonic );
filesOfTypePanel.add ( filesOfTypeLabel );
filterComboBoxModel = createFilterComboBoxModel ();
fc.addPropertyChangeListener ( filterComboBoxModel );
filterComboBox = new JComboBox ( filterComboBoxModel );
filesOfTypeLabel.setLabelFor ( filterComboBox );
filterComboBox.setRenderer ( createFilterComboBoxRenderer () );
filesOfTypePanel.add ( filterComboBox );
// buttons
getButtonPanel ().setLayout ( new ButtonAreaLayout () );
approveButton = new JButton ( getApproveButtonText ( fc ) );
// Note: Metal does not use mnemonics for approve and cancel
approveButton.addActionListener ( getApproveSelectionAction () );
approveButton.setToolTipText ( getApproveButtonToolTipText ( fc ) );
getButtonPanel ().add ( approveButton );
cancelButton = new JButton ( cancelButtonText );
cancelButton.setToolTipText ( cancelButtonToolTipText );
cancelButton.addActionListener ( getCancelSelectionAction () );
getButtonPanel ().add ( cancelButton );
if ( fc.getControlButtonsAreShown () )
{
addControlButtons ();
}
groupLabels ( new AlignedLabel []
{ fileNameLabel, filesOfTypeLabel } );
}
protected JPanel getButtonPanel ()
{
if ( buttonPanel == null )
{
buttonPanel = new JPanel ();
}
return buttonPanel;
}
protected JPanel getBottomPanel ()
{
if ( bottomPanel == null )
{
bottomPanel = new JPanel ();
}
return bottomPanel;
}
protected void installStrings ( JFileChooser fc )
{
super.installStrings ( fc );
Locale l = fc.getLocale ();
lookInLabelMnemonic = UIManager.getInt ( "FileChooser.lookInLabelMnemonic" );
lookInLabelText = UIManager.getString ( "FileChooser.lookInLabelText", l );
saveInLabelText = UIManager.getString ( "FileChooser.saveInLabelText", l );
fileNameLabelMnemonic = UIManager
.getInt ( "FileChooser.fileNameLabelMnemonic" );
fileNameLabelText = UIManager.getString ( "FileChooser.fileNameLabelText",
l );
filesOfTypeLabelMnemonic = UIManager
.getInt ( "FileChooser.filesOfTypeLabelMnemonic" );
filesOfTypeLabelText = UIManager.getString (
"FileChooser.filesOfTypeLabelText", l );
upFolderToolTipText = UIManager.getString (
"FileChooser.upFolderToolTipText", l );
upFolderAccessibleName = UIManager.getString (
"FileChooser.upFolderAccessibleName", l );
homeFolderToolTipText = UIManager.getString (
"FileChooser.homeFolderToolTipText", l );
homeFolderAccessibleName = UIManager.getString (
"FileChooser.homeFolderAccessibleName", l );
newFolderToolTipText = UIManager.getString (
"FileChooser.newFolderToolTipText", l );
newFolderAccessibleName = UIManager.getString (
"FileChooser.newFolderAccessibleName", l );
listViewButtonToolTipText = UIManager.getString (
"FileChooser.listViewButtonToolTipText", l );
listViewButtonAccessibleName = UIManager.getString (
"FileChooser.listViewButtonAccessibleName", l );
detailsViewButtonToolTipText = UIManager.getString (
"FileChooser.detailsViewButtonToolTipText", l );
detailsViewButtonAccessibleName = UIManager.getString (
"FileChooser.detailsViewButtonAccessibleName", l );
fileNameHeaderText = UIManager.getString (
"FileChooser.fileNameHeaderText", l );
fileSizeHeaderText = UIManager.getString (
"FileChooser.fileSizeHeaderText", l );
fileTypeHeaderText = UIManager.getString (
"FileChooser.fileTypeHeaderText", l );
fileDateHeaderText = UIManager.getString (
"FileChooser.fileDateHeaderText", l );
fileAttrHeaderText = UIManager.getString (
"FileChooser.fileAttrHeaderText", l );
}
protected void installListeners ( JFileChooser fc )
{
super.installListeners ( fc );
ActionMap actionMap = getActionMap ();
SwingUtilities.replaceUIActionMap ( fc, actionMap );
}
protected ActionMap getActionMap ()
{
return createActionMap ();
}
protected ActionMap createActionMap ()
{
AbstractAction escAction = new AbstractAction ()
{
public void actionPerformed ( ActionEvent e )
{
if ( editFile != null )
{
cancelEdit ();
}
else
{
getFileChooser ().cancelSelection ();
}
}
public boolean isEnabled ()
{
return getFileChooser ().isEnabled ();
}
};
ActionMap map = new ActionMapUIResource ();
map.put ( "approveSelection", getApproveSelectionAction () );
map.put ( "cancelSelection", escAction );
map.put ( "Go Up", getChangeToParentDirectoryAction () );
return map;
}
protected JPanel createList ( JFileChooser fc )
{
JPanel p = new JPanel ( new BorderLayout () );
final JFileChooser fileChooser = fc;
list = new JList ()
{
public int getNextMatch ( String prefix, int startIndex,
Position.Bias bias )
{
ListModel model = getModel ();
int max = model.getSize ();
if ( prefix == null || startIndex < 0 || startIndex >= max )
{
throw new IllegalArgumentException ();
}
// start search from the next element before/after the selected element
boolean backwards = ( bias == Position.Bias.Backward );
for ( int i = startIndex ; backwards ? i >= 0 : i < max ; i += ( backwards ? -1
: 1 ) )
{
String filename = fileChooser.getName ( ( File ) model
.getElementAt ( i ) );
if ( filename.regionMatches ( true, 0, prefix, 0, prefix.length () ) )
{
return i;
}
}
return -1;
}
};
list.setCellRenderer ( new FileRenderer () );
list.setLayoutOrientation ( JList.VERTICAL_WRAP );
list.setVisibleRowCount ( -1 );
if ( fc.isMultiSelectionEnabled () )
{
list.setSelectionMode ( ListSelectionModel.MULTIPLE_INTERVAL_SELECTION );
}
else
{
list.setSelectionMode ( ListSelectionModel.SINGLE_SELECTION );
}
list.setModel ( getModel () );
list.addListSelectionListener ( createListSelectionListener ( fc ) );
list.addMouseListener ( createDoubleClickListener ( fc, list ) );
list.addMouseListener ( createSingleClickListener ( fc, list ) );
getModel ().addListDataListener ( new ListDataListener ()
{
public void contentsChanged ( ListDataEvent e )
{
// Update the selection after JList has been updated
new DelayedSelectionUpdater ();
}
public void intervalAdded ( ListDataEvent e )
{
new DelayedSelectionUpdater ();
}
public void intervalRemoved ( ListDataEvent e )
{
}
} );
JScrollPane scrollpane = new JScrollPane ( list );
p.add ( scrollpane, BorderLayout.CENTER );
return p;
}
class DetailsTableModel extends AbstractTableModel implements
ListDataListener, SortableTableData
{
String [] columnNames =
{ " " + fileNameHeaderText, fileSizeHeaderText, " " + fileTypeHeaderText,
" " + fileDateHeaderText, " " + fileAttrHeaderText };
JFileChooser chooser;
ListModel listModel;
// Comparators are lazily created
Comparator fileAttributeComparator;
Comparator fileDateComparator;
Comparator fileNameComparator;
Comparator fileSizeComparator;
Comparator fileTypeComparator;
int sortingDirection;
int [] sortColumns;
int [] sortDirections;
DetailsTableModel ( JFileChooser fc )
{
this.chooser = fc;
listModel = getModel ();
listModel.addListDataListener ( this );
}
public int getRowCount ()
{
return listModel.getSize ();
}
public int getColumnCount ()
{
return COLUMN_COLCOUNT;
}
public String getColumnName ( int column )
{
return columnNames [ column ];
}
public Class getColumnClass ( int column )
{
switch ( column )
{
case COLUMN_FILENAME :
return File.class;
case COLUMN_FILEDATE :
return Date.class;
case COLUMN_FILESIZE :
return Long.class;
case COLUMN_FILETYPE :
// case COLUMN_FILEATTR :
return String.class;
default :
return super.getColumnClass ( column );
}
}
public Object getValueAt ( int row, int col )
{
// Note: It is very important to avoid getting info on drives, as
// this will trigger "No disk in A:" and similar dialogs.
//
// Use (f.exists() && !chooser.getFileSystemView().isFileSystemRoot(f)) to
// determine if it is safe to call methods directly on f.
File f = ( File ) listModel.getElementAt ( row );
switch ( col )
{
case COLUMN_FILENAME :
return f;
case COLUMN_FILESIZE :
if ( !f.exists () || f.isDirectory () )
{
return null;
}
return new Long ( f.length () );
case COLUMN_FILETYPE :
if ( !f.exists () )
{
return null;
}
return chooser.getFileSystemView ().getSystemTypeDescription ( f );
case COLUMN_FILEDATE :
if ( !f.exists ()
|| chooser.getFileSystemView ().isFileSystemRoot ( f ) )
{
return null;
}
long time = f.lastModified ();
return ( time == 0L ) ? null : new Date ( time );
// case COLUMN_FILEATTR :
// if(!f.exists() || chooser.getFileSystemView().isFileSystemRoot(f))
// {
// return null;
// }
//
// String attributes = "";
//
// if(!f.canWrite()) {
// attributes += "R";
// }
//
// if(f.isHidden()) {
// attributes += "H";
// }
//
// return attributes;
}
return null;
}
public void setValueAt ( Object value, int row, int col )
{
if ( col == COLUMN_FILENAME )
{
JFileChooser chooser = getFileChooser ();
File f = ( File ) getValueAt ( row, col );
if ( f != null )
{
String oldDisplayName = chooser.getName ( f );
String oldFileName = f.getName ();
String newDisplayName = ( ( String ) value ).trim ();
String newFileName;
if ( !newDisplayName.equals ( oldDisplayName ) )
{
newFileName = newDisplayName;
// Check if extension is hidden from user
int i1 = oldFileName.length ();
int i2 = oldDisplayName.length ();
if ( i1 > i2 && oldFileName.charAt ( i2 ) == '.' )
{
newFileName = newDisplayName + oldFileName.substring ( i2 );
}
// rename
FileSystemView fsv = chooser.getFileSystemView ();
File f2 = fsv.createFileObject ( f.getParentFile (), newFileName );
if ( !f2.exists ()
&& TinyFileChooserUI.this.getModel ().renameFile ( f, f2 ) )
{
if ( fsv.isParent ( chooser.getCurrentDirectory (), f2 ) )
{
if ( chooser.isMultiSelectionEnabled () )
{
chooser.setSelectedFiles ( new File []
{ f2 } );
}
else
{
chooser.setSelectedFile ( f2 );
}
}
else
{
// Could be because of delay in updating Desktop folder
// chooser.setSelectedFile(null);
}
}
else
{
// PENDING(jeff) - show a dialog indicating failure
}
}
}
}
}
public boolean isCellEditable ( int row, int column )
{
return ( column == COLUMN_FILENAME && !UIManager
.getBoolean ( "FileChooser.readOnly" ) );
}
public void contentsChanged ( ListDataEvent e )
{
DetailsTableModel model = ( DetailsTableModel ) detailsTable.getModel ();
model.sortColumns ( detailsTable );
}
public void intervalAdded ( ListDataEvent e )
{
DetailsTableModel model = ( DetailsTableModel ) detailsTable.getModel ();
model.sortColumns ( detailsTable );
}
public void intervalRemoved ( ListDataEvent e )
{
DetailsTableModel model = ( DetailsTableModel ) detailsTable.getModel ();
model.sortColumns ( detailsTable );
}
public void invalidateCachedFiles ()
{
}
// SortableTableData implementation
public boolean isColumnSortable ( int column )
{
return Comparable.class.isAssignableFrom ( getColumnClass ( column ) );
}
public boolean supportsMultiColumnSort ()
{
return false;
}
public void sortColumns ( final int [] columns,
final int [] sortingDirections, JTable table )
{
sortColumns = new int [ columns.length ];
sortDirections = new int [ sortingDirections.length ];
System.arraycopy ( columns, 0, sortColumns, 0, columns.length );
System.arraycopy ( sortingDirections, 0, sortDirections, 0,
sortingDirections.length );
sortColumns ( table );
}
private void sortColumns ( JTable table )
{
// long t = System.currentTimeMillis();
Vector files = ( ( TinyDirectoryModel ) listModel ).getFileCache ();
// store column selection
int [] sc = table.getSelectedColumns ();
int [] sr = new int [ table.getSelectedRowCount () ];
// store file list, each file knows if it is selected or not
Vector sortFiles = new Vector ( files.size () );
int end = files.size ();
// System.out.println("\nNumber of files: " + end);
for ( int i = 0 ; i < end ; i++ )
{
sortFiles.add ( new SelectedFile ( ( File ) files.get ( i ), table
.isRowSelected ( i ) ) );
}
// System.out.println("Create sortFiles: " + (System.currentTimeMillis() -
// t));
if ( sortColumns.length == 0 )
{
// sort file names ascending
sortingDirection = SORT_ASCENDING;
if ( fileNameComparator == null )
{
fileNameComparator = createFileNameComparator ();
}
Collections.sort ( sortFiles, fileNameComparator );
}
else
{
// perform single-column sort
sortingDirection = ( sortDirections [ 0 ] == SORT_ASCENDING ? 1 : -1 );
switch ( sortColumns [ 0 ] )
{
case COLUMN_FILENAME :
if ( fileNameComparator == null )
{
fileNameComparator = createFileNameComparator ();
}
Collections.sort ( sortFiles, fileNameComparator );
break;
case COLUMN_FILESIZE :
if ( fileSizeComparator == null )
{
fileSizeComparator = createFileSizeComparator ();
}
Collections.sort ( sortFiles, fileSizeComparator );
break;
case COLUMN_FILETYPE :
if ( fileTypeComparator == null )
{
fileTypeComparator = createFileTypeComparator ();
}
Collections.sort ( sortFiles, fileTypeComparator );
break;
case COLUMN_FILEDATE :
if ( fileDateComparator == null )
{
fileDateComparator = createFileDateComparator ();
}
Collections.sort ( sortFiles, fileDateComparator );
break;
// case COLUMN_FILEATTR:
// if(fileAttributeComparator == null) {
// fileAttributeComparator = createFileAttributeComparator();
// }
//
// Collections.sort(sortFiles, fileAttributeComparator);
// break;
}
}
// System.out.println("sort: " + (System.currentTimeMillis() - t));
// store sorted files and restore selection
files.clear ();
int row = 0;
int index = 0;
Iterator ii = sortFiles.iterator ();
while ( ii.hasNext () )
{
SelectedFile sf = ( SelectedFile ) ii.next ();
files.add ( sf.file );
if ( sf.selected )
{
sr [ index++ ] = row;
}
row++ ;
}
// System.out.println("restore files: " + (System.currentTimeMillis() -
// t));
fireTableDataChanged ();
// We don't want the table's scroll pane to scroll
// as we restore the selection
doScrolling = false;
for ( int i = 0 ; i < sr.length ; i++ )
{
table.addRowSelectionInterval ( sr [ i ], sr [ i ] );
}
for ( int i = 0 ; i < sc.length ; i++ )
{
table.addColumnSelectionInterval ( sc [ i ], sc [ i ] );
}
doScrolling = true;
// System.out.println("restore selection: " + (System.currentTimeMillis()
// - t));
}
// A container for a File and its selected state
private class SelectedFile
{
File file;
boolean selected;
String name;
// String attribute;
Long size;
Long date;
String type;
Boolean isDirectory;
Boolean exists;
Boolean isFileSystemRoot;
SelectedFile ( File file, boolean selected )
{
this.file = file;
this.selected = selected;
}
// public String getAttribute() {
// if(attribute == null) {
// attribute = "";
// if(exists() && !isFileSystemRoot()) {
// if(!file.canWrite()) {
// attribute += "R";
// }
//
// if(file.isHidden()) {
// attribute += "H";
// }
// }
// }
//
// return attribute;
// }
public Long getDate ()
{
if ( date == null )
{
if ( exists () && !isFileSystemRoot () )
{
date = new Long ( file.lastModified () );
}
else
{
date = new Long ( 0 );
}
}
return date;
}
public String getName ()
{
if ( name == null )
{
name = chooser.getName ( file );
if ( name == null )
name = "";
else
name = name.toLowerCase ();
}
return name;
}
public Long getSize ()
{
if ( size == null )
{
if ( exists () && !isDirectory () )
{
size = new Long ( file.length () );
}
else
{
size = new Long ( 0L );
}
}
return size;
}
public String getType ()
{
if ( type == null )
{
if ( exists () )
{
type = chooser.getFileSystemView ()
.getSystemTypeDescription ( file );
}
else
{
type = "";
}
}
return type;
}
public boolean isDirectory ()
{
if ( isDirectory == null )
{
isDirectory = new Boolean ( exists () && file.isDirectory () );
}
return isDirectory.booleanValue ();
}
public boolean exists ()
{
if ( exists == null )
{
exists = new Boolean ( file.exists () );
}
return exists.booleanValue ();
}
public boolean isFileSystemRoot ()
{
if ( isFileSystemRoot == null )
{
isFileSystemRoot = new Boolean ( chooser.getFileSystemView ()
.isFileSystemRoot ( file ) );
}
return isFileSystemRoot.booleanValue ();
}
}
Comparator createFileNameComparator ()
{
return new Comparator ()
{
public int compare ( Object o1, Object o2 )
{
SelectedFile f1 = ( SelectedFile ) o1;
SelectedFile f2 = ( SelectedFile ) o2;
if ( f1.isDirectory () == f2.isDirectory () )
{
return f1.getName ().compareTo ( f2.getName () ) * sortingDirection;
}
else if ( f1.isDirectory () )
{
return -1 * sortingDirection;
}
else
{
return 1 * sortingDirection;
}
}
};
}
Comparator createFileSizeComparator ()
{
return new Comparator ()
{
public int compare ( Object o1, Object o2 )
{
Long s1 = ( ( SelectedFile ) o1 ).getSize ();
Long s2 = ( ( SelectedFile ) o2 ).getSize ();
return s1.compareTo ( s2 ) * sortingDirection;
}
};
}
Comparator createFileTypeComparator ()
{
return new Comparator ()
{
public int compare ( Object o1, Object o2 )
{
SelectedFile f1 = ( SelectedFile ) o1;
SelectedFile f2 = ( SelectedFile ) o2;
if ( f1.isDirectory () == f2.isDirectory () )
{
return f1.getType ().compareTo ( f2.getType () ) * sortingDirection;
}
else if ( f1.isDirectory () )
{
return -1 * sortingDirection;
}
else
{
return 1 * sortingDirection;
}
}
};
}
Comparator createFileDateComparator ()
{
return new Comparator ()
{
public int compare ( Object o1, Object o2 )
{
Long d1 = ( ( SelectedFile ) o1 ).getDate ();
Long d2 = ( ( SelectedFile ) o2 ).getDate ();
return d1.compareTo ( d2 ) * sortingDirection;
}
};
}
// Comparator createFileAttributeComparator() {
// return new Comparator() {
// public int compare(Object o1, Object o2) {
// String a1 = ((SelectedFile)o1).getAttribute();
// String a2 = ((SelectedFile)o2).getAttribute();
//
// return a1.compareTo(a2) * sortingDirection;
// }
// };
// }
}
class DetailsTableCellRenderer extends DefaultTableCellRenderer
{
JFileChooser chooser;
DateFormat df;
DetailsTableCellRenderer ( JFileChooser chooser )
{
this.chooser = chooser;
df = DateFormat.getDateTimeInstance ( DateFormat.SHORT, DateFormat.SHORT,
chooser.getLocale () );
}
public Component getTableCellRendererComponent ( JTable table,
Object value, boolean isSelected, boolean hasFocus, int row, int column )
{
int modelColumn = table.getColumnModel ().getColumn ( column )
.getModelIndex ();
if ( modelColumn == COLUMN_FILESIZE /* || modelColumn == COLUMN_FILEATTR */)
{
super.setHorizontalAlignment ( SwingConstants.TRAILING );
}
else
{
super.setHorizontalAlignment ( SwingConstants.LEADING );
}
Component c = super.getTableCellRendererComponent ( table, value,
isSelected & ( modelColumn == 0 ), false, row, column );
int w1 = table.getColumnModel ().getColumn ( column ).getWidth ();
int w2 = c.getPreferredSize ().width;
if ( w2 > w1 )
{
super.setToolTipText ( getText () );
}
else
{
super.setToolTipText ( null );
}
// paint selection only for file name column and
// don't paint focus
return c;
}
public void setValue ( Object value )
{
setIcon ( null );
if ( value == null )
{
setText ( "" );
}
else if ( value instanceof File )
{
File file = ( File ) value;
String fileName = chooser.getName ( file );
setText ( fileName );
Icon icon = chooser.getIcon ( file );
setIcon ( icon );
}
else if ( value instanceof Date )
{
setText ( ( value == null ) ? "" : df.format ( ( Date ) value ) );
}
else if ( value instanceof Long )
{
long len = ( ( Long ) value ).longValue () / 1024L;
if ( len < 1024L )
{
setText ( ( ( len == 0L ) ? 1L : len ) + " KB" );
}
else
{
len /= 1024L;
if ( len < 1024L )
{
setText ( len + " MB" );
}
else
{
len /= 1024L;
setText ( len + " GB" );
}
}
}
else
{
super.setValue ( value );
}
}
}
protected JPanel createDetailsView ( JFileChooser fc )
{
final JFileChooser chooser = fc;
JPanel p = new JPanel ( new BorderLayout () );
detailsTableModel = new DetailsTableModel ( chooser );
detailsTable = new JTable ( detailsTableModel )
{
// Handle Escape key events here
protected boolean processKeyBinding ( KeyStroke ks, KeyEvent e,
int condition, boolean pressed )
{
if ( e.getKeyCode () == KeyEvent.VK_ESCAPE && getCellEditor () == null )
{
// We are not editing, forward to filechooser.
chooser.dispatchEvent ( e );
return true;
}
return super.processKeyBinding ( ks, e, condition, pressed );
}
};
detailsTable.setComponentOrientation ( chooser.getComponentOrientation () );
detailsTable.setAutoResizeMode ( JTable.AUTO_RESIZE_OFF );
detailsTable.setShowGrid ( false );
detailsTable.setSelectionModel ( listSelectionModel );
detailsTable.putClientProperty ( "JTable.autoStartsEdit", Boolean.FALSE );
Font font = detailsTable.getFont ();
// Minimum row height will be 18 px. (in MetalFileChooserUI is 22 px.)
detailsTable.setRowHeight ( Math.max ( font.getSize (), 15 ) + 3 );
TableColumnModel columnModel = detailsTable.getColumnModel ();
TableColumn [] columns = new TableColumn [ COLUMN_COLCOUNT ];
boolean isWin = System.getProperty ( "os.name" ).startsWith ( "Windows" );
for ( int i = 0 ; i < COLUMN_COLCOUNT ; i++ )
{
columns [ i ] = columnModel.getColumn ( i );
columns [ i ].setPreferredWidth ( COLUMN_WIDTHS [ i ] );
}
if ( !isWin )
{
columnModel.removeColumn ( columns [ COLUMN_FILETYPE ] );
// columnModel.removeColumn(columns[COLUMN_FILEATTR]);
}
TableHeaderUI headerUI = detailsTable.getTableHeader ().getUI ();
if ( headerUI instanceof TinyTableHeaderUI )
{
// sort first column (= directory/file name)
( ( TinyTableHeaderUI ) headerUI ).sortColumns ( new int []
{ 0 }, new int []
{ SortableTableData.SORT_ASCENDING }, detailsTable );
// set horizontal alignments of table header renderers
if ( isWin )
{
( ( TinyTableHeaderUI ) headerUI ).setHorizontalAlignments ( new int []
{ SwingConstants.LEADING, SwingConstants.TRAILING,
SwingConstants.LEADING, SwingConstants.LEADING } );
}
else
{
( ( TinyTableHeaderUI ) headerUI ).setHorizontalAlignments ( new int []
{ SwingConstants.LEADING, SwingConstants.TRAILING,
SwingConstants.LEADING } );
}
}
TableCellRenderer cellRenderer = new DetailsTableCellRenderer ( chooser );
detailsTable.setDefaultRenderer ( File.class, cellRenderer );
detailsTable.setDefaultRenderer ( Date.class, cellRenderer );
detailsTable.setDefaultRenderer ( Long.class, cellRenderer );
detailsTable.setDefaultRenderer ( String.class, cellRenderer );
detailsTable.setDefaultRenderer ( Object.class, cellRenderer );
// Install cell editor for editing file name
final JTextField tf = new JTextField ();
tf.addFocusListener ( editorFocusListener );
columns [ COLUMN_FILENAME ].setCellEditor ( new DefaultCellEditor ( tf )
{
public boolean isCellEditable ( EventObject e )
{
if ( e instanceof MouseEvent )
{
MouseEvent me = ( MouseEvent ) e;
int index = detailsTable.rowAtPoint ( me.getPoint () );
return ( me.getClickCount () == 1 && detailsTable
.isRowSelected ( index ) );
}
return super.isCellEditable ( e );
}
public Component getTableCellEditorComponent ( JTable table,
Object value, boolean isSelected, int row, int column )
{
Component comp = super.getTableCellEditorComponent ( table, value,
isSelected, row, column );
if ( value instanceof File )
{
tf.setText ( chooser.getName ( ( File ) value ) );
tf.requestFocus ();
tf.selectAll ();
}
return comp;
}
} );
JList fakeList = new JList ( detailsTableModel.listModel )
{
JTable table = detailsTable;
public int locationToIndex ( Point location )
{
return table.rowAtPoint ( location );
}
public Rectangle getCellBounds ( int index0, int index1 )
{
Rectangle r0 = table.getCellRect ( index0, COLUMN_FILENAME, false );
Rectangle r1 = table.getCellRect ( index1, COLUMN_FILENAME, false );
return r0.union ( r1 );
}
public Object getSelectedValue ()
{
return table.getValueAt ( table.getSelectedRow (), COLUMN_FILENAME );
}
public Component add ( Component comp )
{
if ( comp instanceof JTextField )
{
return table.add ( comp );
}
else
{
return super.add ( comp );
}
}
public void repaint ()
{
if ( table != null )
table.repaint ();
}
public TransferHandler getTransferHandler ()
{
if ( table != null )
{
return table.getTransferHandler ();
}
else
{
return super.getTransferHandler ();
}
}
public void setTransferHandler ( TransferHandler newHandler )
{
if ( table != null )
{
table.setTransferHandler ( newHandler );
}
else
{
super.setTransferHandler ( newHandler );
}
}
public boolean getDragEnabled ()
{
if ( table != null )
{
return table.getDragEnabled ();
}
else
{
return super.getDragEnabled ();
}
}
public void setDragEnabled ( boolean b )
{
if ( table != null )
{
table.setDragEnabled ( b );
}
else
{
super.setDragEnabled ( b );
}
}
};
fakeList.setSelectionModel ( listSelectionModel );
detailsTable.addMouseListener ( createDoubleClickListener ( chooser,
fakeList ) );
// detailsTable.addMouseListener(createSingleClickListener(chooser,
// fakeList));
JScrollPane scrollpane = new JScrollPane ( detailsTable );
scrollpane.setComponentOrientation ( chooser.getComponentOrientation () );
LookAndFeel.installColors ( scrollpane.getViewport (), "Table.background",
"Table.foreground" );
// Adjust width of first column so the table fills the viewport when
// first displayed (temporary listener).
scrollpane.addComponentListener ( new ComponentAdapter ()
{
public void componentResized ( ComponentEvent e )
{
JScrollPane sp = ( JScrollPane ) e.getComponent ();
fixNameColumnWidth ( sp.getViewport ().getSize ().width );
sp.removeComponentListener ( this );
}
} );
p.add ( scrollpane, BorderLayout.CENTER );
return p;
}
private void fixNameColumnWidth ( int viewWidth )
{
TableColumn nameCol = detailsTable.getColumnModel ().getColumn (
COLUMN_FILENAME );
int tableWidth = detailsTable.getPreferredSize ().width;
if ( tableWidth < viewWidth )
{
nameCol.setPreferredWidth ( nameCol.getPreferredWidth () + viewWidth
- tableWidth );
}
}
private class DelayedSelectionUpdater implements Runnable
{
DelayedSelectionUpdater ()
{
SwingUtilities.invokeLater ( this );
}
public void run ()
{
setFileSelected ();
}
}
/**
* Creates a selection listener for the list of files and directories.
*
* @param fc a <code>JFileChooser</code>
* @return a <code>ListSelectionListener</code>
*/
public ListSelectionListener createListSelectionListener ( JFileChooser fc )
{
return new SelectionListener ()
{
public void valueChanged ( ListSelectionEvent e )
{
if ( !e.getValueIsAdjusting () )
{
JFileChooser chooser = getFileChooser ();
FileSystemView fsv = chooser.getFileSystemView ();
JList list = ( JList ) e.getSource ();
if ( chooser.isMultiSelectionEnabled () )
{
File [] files = null;
Object [] objects = list.getSelectedValues ();
if ( objects != null )
{
if ( objects.length == 1
&& ( ( File ) objects [ 0 ] ).isDirectory ()
&& chooser.isTraversable ( ( ( File ) objects [ 0 ] ) )
&& ( chooser.getFileSelectionMode () == chooser.FILES_ONLY || !fsv
.isFileSystem ( ( ( File ) objects [ 0 ] ) ) ) )
{
setDirectorySelected ( true );
setDirectory ( ( ( File ) objects [ 0 ] ) );
}
else
{
files = new File [ objects.length ];
int j = 0;
for ( int i = 0 ; i < objects.length ; i++ )
{
File f = ( File ) objects [ i ];
if ( ( chooser.isFileSelectionEnabled () && f.isFile () )
|| ( chooser.isDirectorySelectionEnabled ()
&& fsv.isFileSystem ( f ) && f.isDirectory () ) )
{
files [ j++ ] = f;
}
}
if ( j == 0 )
{
files = null;
}
else if ( j < objects.length )
{
File [] tmpFiles = new File [ j ];
System.arraycopy ( files, 0, tmpFiles, 0, j );
files = tmpFiles;
}
setDirectorySelected ( false );
}
}
chooser.setSelectedFiles ( files );
}
else
{
File file = ( File ) list.getSelectedValue ();
if ( file != null
&& file.isDirectory ()
&& chooser.isTraversable ( file )
&& ( chooser.getFileSelectionMode () == chooser.FILES_ONLY || !fsv
.isFileSystem ( file ) ) )
{
setDirectorySelected ( true );
setDirectory ( file );
chooser.setSelectedFile ( null );
}
else
{
setDirectorySelected ( false );
if ( file != null )
{
chooser.setSelectedFile ( file );
}
}
}
}
}
};
}
private MouseListener createSingleClickListener ( JFileChooser fc, JList list )
{
return new SingleClickListener ( list );
}
int lastIndex = -1;
File editFile = null;
int editX = 20;
private int getEditIndex ()
{
return lastIndex;
}
private void setEditIndex ( int i )
{
lastIndex = i;
}
private void resetEditIndex ()
{
lastIndex = -1;
}
private void cancelEdit ()
{
if ( editFile != null )
{
editFile = null;
list.remove ( editCell );
centerPanel.repaint ();
}
else if ( detailsTable != null && detailsTable.isEditing () )
{
detailsTable.getCellEditor ().cancelCellEditing ();
}
}
JTextField editCell = null;
private void editFileName ( int index )
{
if ( UIManager.getBoolean ( "FileChooser.readOnly" ) )
return;
ensureIndexIsVisible ( index );
if ( listViewPanel.isVisible () )
{
editFile = ( File ) getModel ().getElementAt ( index );
Rectangle r = list.getCellBounds ( index, index );
if ( editCell == null )
{
editCell = new JTextField ();
editCell.addActionListener ( new EditActionListener () );
editCell.addFocusListener ( editorFocusListener );
editCell.setNextFocusableComponent ( list );
}
list.add ( editCell );
editCell.setText ( getFileChooser ().getName ( editFile ) );
if ( list.getComponentOrientation ().isLeftToRight () )
{
editCell.setBounds ( editX + r.x, r.y, r.width - editX, r.height );
}
else
{
editCell.setBounds ( r.x, r.y, r.width - editX, r.height );
}
editCell.requestFocus ();
editCell.selectAll ();
}
else if ( detailsViewPanel.isVisible () )
{
detailsTable.editCellAt ( index, COLUMN_FILENAME );
}
}
protected class SingleClickListener extends MouseAdapter
{
JList list;
public SingleClickListener ( JList list )
{
this.list = list;
}
public void mouseClicked ( MouseEvent e )
{
if ( SwingUtilities.isLeftMouseButton ( e ) )
{
if ( e.getClickCount () == 1 )
{
JFileChooser fc = getFileChooser ();
int index = list.locationToIndex ( e.getPoint () );
if ( ( !fc.isMultiSelectionEnabled () || fc.getSelectedFiles ().length <= 1 )
&& index >= 0
&& list.isSelectedIndex ( index )
&& getEditIndex () == index && editFile == null )
{
editFileName ( index );
}
else
{
if ( index >= 0 )
{
setEditIndex ( index );
}
else
{
resetEditIndex ();
}
}
}
else
{
// on double click (open or drill down one directory) be
// sure to clear the edit index
resetEditIndex ();
}
}
}
}
class EditActionListener implements ActionListener
{
public void actionPerformed ( ActionEvent e )
{
applyEdit ();
}
}
private void applyEdit ()
{
if ( editFile != null && editFile.exists () )
{
JFileChooser chooser = getFileChooser ();
String oldDisplayName = chooser.getName ( editFile );
String oldFileName = editFile.getName ();
String newDisplayName = editCell.getText ().trim ();
String newFileName;
if ( !newDisplayName.equals ( oldDisplayName ) )
{
newFileName = newDisplayName;
// Check if extension is hidden from user
int i1 = oldFileName.length ();
int i2 = oldDisplayName.length ();
if ( i1 > i2 && oldFileName.charAt ( i2 ) == '.' )
{
newFileName = newDisplayName + oldFileName.substring ( i2 );
}
// rename
FileSystemView fsv = chooser.getFileSystemView ();
File f2 = fsv
.createFileObject ( editFile.getParentFile (), newFileName );
if ( !f2.exists () && getModel ().renameFile ( editFile, f2 ) )
{
if ( fsv.isParent ( chooser.getCurrentDirectory (), f2 ) )
{
if ( chooser.isMultiSelectionEnabled () )
{
chooser.setSelectedFiles ( new File []
{ f2 } );
}
else
{
chooser.setSelectedFile ( f2 );
}
}
else
{
// Could be because of delay in updating Desktop folder
// chooser.setSelectedFile(null);
}
}
else
{
// PENDING(jeff) - show a dialog indicating failure
}
}
}
if ( detailsTable != null && detailsTable.isEditing () )
{
detailsTable.getCellEditor ().stopCellEditing ();
}
cancelEdit ();
}
protected class FileRenderer extends DefaultListCellRenderer
{
public Component getListCellRendererComponent ( JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus )
{
super.getListCellRendererComponent ( list, value, index, isSelected,
cellHasFocus );
File file = ( File ) value;
String fileName = getFileChooser ().getName ( file );
setText ( fileName );
Icon icon = getFileChooser ().getIcon ( file );
setIcon ( icon );
if ( isSelected )
{
// PENDING(jeff) - grab padding (4) below from defaults table.
editX = icon.getIconWidth () + 4;
}
return this;
}
}
public void uninstallUI ( JComponent c )
{
// Remove listeners
c.removePropertyChangeListener ( filterComboBoxModel );
cancelButton.removeActionListener ( getCancelSelectionAction () );
approveButton.removeActionListener ( getApproveSelectionAction () );
fileNameTextField.removeActionListener ( getApproveSelectionAction () );
super.uninstallUI ( c );
}
/**
* Returns the preferred size of the specified <code>JFileChooser</code>.
* The preferred size is at least as large, in both height and width, as the
* preferred size recommended by the file chooser's layout manager.
*
* @param mainColor a <code>JFileChooser</code>
* @return a <code>Dimension</code> specifying the preferred width and
* height of the file chooser
*/
public Dimension getPreferredSize ( JComponent c )
{
int prefWidth = PREF_SIZE.width;
Dimension d = c.getLayout ().preferredLayoutSize ( c );
if ( d != null )
{
return new Dimension ( d.width < prefWidth ? prefWidth : d.width,
d.height < PREF_SIZE.height ? PREF_SIZE.height : d.height );
}
else
{
return new Dimension ( prefWidth, PREF_SIZE.height );
}
}
/**
* Returns the minimum size of the <code>JFileChooser</code>.
*
* @param mainColor a <code>JFileChooser</code>
* @return a <code>Dimension</code> specifying the minimum width and height
* of the file chooser
*/
public Dimension getMinimumSize ( JComponent c )
{
return MIN_SIZE;
}
/**
* Returns the maximum size of the <code>JFileChooser</code>.
*
* @param mainColor a <code>JFileChooser</code>
* @return a <code>Dimension</code> specifying the maximum width and height
* of the file chooser
*/
public Dimension getMaximumSize ( JComponent c )
{
return new Dimension ( Integer.MAX_VALUE, Integer.MAX_VALUE );
}
void setFileSelected ()
{
if ( getFileChooser ().isMultiSelectionEnabled ()
&& !isDirectorySelected () )
{
File [] files = getFileChooser ().getSelectedFiles (); // Should be
// selected
Object [] selectedObjects = list.getSelectedValues (); // Are actually
// selected
// Remove files that shouldn't be selected
for ( int j = 0 ; j < selectedObjects.length ; j++ )
{
boolean found = false;
for ( int i = 0 ; i < files.length ; i++ )
{
if ( files [ i ].equals ( selectedObjects [ j ] ) )
{
found = true;
break;
}
}
if ( !found )
{
int index = getModel ().indexOf ( selectedObjects [ j ] );
if ( index >= 0 )
{
listSelectionModel.removeSelectionInterval ( index, index );
}
}
}
// Add files that should be selected
for ( int i = 0 ; i < files.length ; i++ )
{
boolean found = false;
for ( int j = 0 ; j < selectedObjects.length ; j++ )
{
if ( files [ i ].equals ( selectedObjects [ j ] ) )
{
found = true;
break;
}
}
if ( !found )
{
int index = getModel ().indexOf ( files [ i ] );
if ( index >= 0 )
{
listSelectionModel.addSelectionInterval ( index, index );
}
}
}
}
else
{
JFileChooser chooser = getFileChooser ();
File f = null;
if ( isDirectorySelected () )
{
f = getDirectory ();
}
else
{
f = chooser.getSelectedFile ();
}
int i;
if ( f != null && ( i = getModel ().indexOf ( f ) ) >= 0 )
{
listSelectionModel.setSelectionInterval ( i, i );
ensureIndexIsVisible ( i );
}
else
{
listSelectionModel.clearSelection ();
}
}
}
private String fileNameString ( File file )
{
if ( file == null )
{
return null;
}
else
{
JFileChooser fc = getFileChooser ();
if ( fc.isDirectorySelectionEnabled () && !fc.isFileSelectionEnabled () )
{
return file.getPath ();
}
else
{
return file.getName ();
}
}
}
private String fileNameString ( File [] files )
{
StringBuffer buf = new StringBuffer ();
for ( int i = 0 ; files != null && i < files.length ; i++ )
{
if ( i > 0 )
{
buf.append ( " " );
}
if ( files.length > 1 )
{
buf.append ( "\"" );
}
buf.append ( fileNameString ( files [ i ] ) );
if ( files.length > 1 )
{
buf.append ( "\"" );
}
}
return buf.toString ();
}
/* The following methods are used by the PropertyChange Listener */
private void doSelectedFileChanged ( PropertyChangeEvent e )
{
applyEdit ();
File f = ( File ) e.getNewValue ();
JFileChooser fc = getFileChooser ();
if ( f != null
&& ( ( fc.isFileSelectionEnabled () && !f.isDirectory () ) || ( f
.isDirectory () && fc.isDirectorySelectionEnabled () ) ) )
{
setFileName ( fileNameString ( f ) );
setFileSelected ();
}
}
private void doSelectedFilesChanged ( PropertyChangeEvent e )
{
applyEdit ();
File [] files = ( File [] ) e.getNewValue ();
JFileChooser fc = getFileChooser ();
if ( files != null
&& files.length > 0
&& ( files.length > 1 || fc.isDirectorySelectionEnabled () || !files [ 0 ]
.isDirectory () ) )
{
setFileName ( fileNameString ( files ) );
setFileSelected ();
}
}
private void doDirectoryChanged ( PropertyChangeEvent e )
{
JFileChooser fc = getFileChooser ();
FileSystemView fsv = fc.getFileSystemView ();
applyEdit ();
resetEditIndex ();
clearIconCache ();
listSelectionModel.clearSelection ();
ensureIndexIsVisible ( 0 );
File currentDirectory = fc.getCurrentDirectory ();
if ( currentDirectory != null )
{
directoryComboBoxModel.addItem ( currentDirectory );
getNewFolderAction ().setEnabled ( currentDirectory.canWrite () );
getChangeToParentDirectoryAction ().setEnabled (
!fsv.isRoot ( currentDirectory ) );
if ( fc.isDirectorySelectionEnabled () && !fc.isFileSelectionEnabled () )
{
if ( fsv.isFileSystem ( currentDirectory ) )
{
setFileName ( currentDirectory.getPath () );
}
else
{
setFileName ( null );
}
}
}
}
private void doFilterChanged ( PropertyChangeEvent e )
{
applyEdit ();
resetEditIndex ();
clearIconCache ();
listSelectionModel.clearSelection ();
}
private void doFileSelectionModeChanged ( PropertyChangeEvent e )
{
applyEdit ();
resetEditIndex ();
clearIconCache ();
listSelectionModel.clearSelection ();
JFileChooser fc = getFileChooser ();
File currentDirectory = fc.getCurrentDirectory ();
if ( currentDirectory != null && fc.isDirectorySelectionEnabled ()
&& !fc.isFileSelectionEnabled ()
&& fc.getFileSystemView ().isFileSystem ( currentDirectory ) )
{
setFileName ( currentDirectory.getPath () );
}
else
{
setFileName ( null );
}
}
private void doMultiSelectionChanged ( PropertyChangeEvent e )
{
if ( getFileChooser ().isMultiSelectionEnabled () )
{
listSelectionModel
.setSelectionMode ( ListSelectionModel.MULTIPLE_INTERVAL_SELECTION );
}
else
{
listSelectionModel
.setSelectionMode ( ListSelectionModel.SINGLE_SELECTION );
listSelectionModel.clearSelection ();
getFileChooser ().setSelectedFiles ( null );
}
}
private void doAccessoryChanged ( PropertyChangeEvent e )
{
if ( getAccessoryPanel () != null )
{
if ( e.getOldValue () != null )
{
getAccessoryPanel ().remove ( ( JComponent ) e.getOldValue () );
}
JComponent accessory = ( JComponent ) e.getNewValue ();
if ( accessory != null )
{
getAccessoryPanel ().add ( accessory, BorderLayout.CENTER );
}
}
}
private void doApproveButtonTextChanged ( PropertyChangeEvent e )
{
JFileChooser chooser = getFileChooser ();
approveButton.setText ( getApproveButtonText ( chooser ) );
approveButton.setToolTipText ( getApproveButtonToolTipText ( chooser ) );
}
private void doDialogTypeChanged ( PropertyChangeEvent e )
{
JFileChooser chooser = getFileChooser ();
approveButton.setText ( getApproveButtonText ( chooser ) );
approveButton.setToolTipText ( getApproveButtonToolTipText ( chooser ) );
if ( chooser.getDialogType () == JFileChooser.SAVE_DIALOG )
{
lookInLabel.setText ( saveInLabelText );
}
else
{
lookInLabel.setText ( lookInLabelText );
}
}
private void doApproveButtonMnemonicChanged ( PropertyChangeEvent e )
{
// Note: Metal does not use mnemonics for approve and cancel
}
private void doControlButtonsChanged ( PropertyChangeEvent e )
{
if ( getFileChooser ().getControlButtonsAreShown () )
{
addControlButtons ();
}
else
{
removeControlButtons ();
}
}
/*
* Listen for filechooser property changes, such as the selected file
* changing, or the type of the dialog changing.
*/
public PropertyChangeListener createPropertyChangeListener ( JFileChooser fc )
{
return new PropertyChangeListener ()
{
public void propertyChange ( PropertyChangeEvent e )
{
String s = e.getPropertyName ();
if ( s.equals ( JFileChooser.SELECTED_FILE_CHANGED_PROPERTY ) )
{
doSelectedFileChanged ( e );
}
else if ( s.equals ( JFileChooser.SELECTED_FILES_CHANGED_PROPERTY ) )
{
doSelectedFilesChanged ( e );
}
else if ( s.equals ( JFileChooser.DIRECTORY_CHANGED_PROPERTY ) )
{
doDirectoryChanged ( e );
}
else if ( s.equals ( JFileChooser.FILE_FILTER_CHANGED_PROPERTY ) )
{
doFilterChanged ( e );
}
else if ( s.equals ( JFileChooser.FILE_SELECTION_MODE_CHANGED_PROPERTY ) )
{
doFileSelectionModeChanged ( e );
}
else if ( s
.equals ( JFileChooser.MULTI_SELECTION_ENABLED_CHANGED_PROPERTY ) )
{
doMultiSelectionChanged ( e );
}
else if ( s.equals ( JFileChooser.ACCESSORY_CHANGED_PROPERTY ) )
{
doAccessoryChanged ( e );
}
else if ( s.equals ( JFileChooser.APPROVE_BUTTON_TEXT_CHANGED_PROPERTY )
|| s
.equals ( JFileChooser.APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY ) )
{
doApproveButtonTextChanged ( e );
}
else if ( s.equals ( JFileChooser.DIALOG_TYPE_CHANGED_PROPERTY ) )
{
doDialogTypeChanged ( e );
}
else if ( s
.equals ( JFileChooser.APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY ) )
{
doApproveButtonMnemonicChanged ( e );
}
else if ( s
.equals ( JFileChooser.CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY ) )
{
doControlButtonsChanged ( e );
}
else if ( s.equals ( JFileChooser.CANCEL_SELECTION ) )
{
applyEdit ();
}
else if ( s.equals ( "componentOrientation" ) )
{
ComponentOrientation o = ( ComponentOrientation ) e.getNewValue ();
JFileChooser cc = ( JFileChooser ) e.getSource ();
if ( o != ( ComponentOrientation ) e.getOldValue () )
{
cc.applyComponentOrientation ( o );
}
if ( detailsTable != null )
{
detailsTable.setComponentOrientation ( o );
detailsTable.getParent ().getParent ().setComponentOrientation ( o );
}
}
else if ( s.equals ( "ancestor" ) )
{
if ( e.getOldValue () == null && e.getNewValue () != null )
{
// Ancestor was added, set initial focus
fileNameTextField.selectAll ();
fileNameTextField.requestFocus ();
}
}
}
};
}
protected void createModel ()
{
if ( directoryModel != null )
{
directoryModel.invalidateFileCache ();
}
directoryModel = new TinyDirectoryModel ( getFileChooser () );
}
public BasicDirectoryModel getModel ()
{
return directoryModel;
}
protected void removeControlButtons ()
{
getBottomPanel ().remove ( getButtonPanel () );
}
protected void addControlButtons ()
{
getBottomPanel ().add ( getButtonPanel () );
}
private void ensureIndexIsVisible ( int i )
{
if ( i >= 0 )
{
list.ensureIndexIsVisible ( i );
if ( detailsTable != null )
{
// This is the Metal code ...
// detailsTable.scrollRectToVisible(detailsTable.getCellRect(i,
// COLUMN_FILENAME, true));
// ... we only want to make sure that the row is visible
// (but not scroll to the file name column)
Rectangle r1 = detailsTable.getCellRect ( i, COLUMN_FILENAME, true );
Rectangle r2 = detailsTable.getCellRect ( i, detailsTable
.getColumnCount () - 1, true );
r1.x = ( r1.x + r2.x + r2.width ) / 2;
r1.width = 1;
detailsTable.scrollRectToVisible ( r1 );
}
}
}
public void ensureFileIsVisible ( JFileChooser fc, File f )
{
if ( !doScrolling )
return;
ensureIndexIsVisible ( getModel ().indexOf ( f ) );
}
public void rescanCurrentDirectory ( JFileChooser fc )
{
getModel ().validateFileCache ();
}
public String getFileName ()
{
if ( fileNameTextField != null )
{
return fileNameTextField.getText ();
}
else
{
return null;
}
}
public void setFileName ( String filename )
{
if ( fileNameTextField != null )
{
fileNameTextField.setText ( filename );
}
}
/**
* Property to remember whether a directory is currently selected in the UI.
* This is normally called by the UI on a selection event.
*
* @param directorySelected if a directory is currently selected.
* @since 1.4
*/
protected void setDirectorySelected ( boolean directorySelected )
{
super.setDirectorySelected ( directorySelected );
JFileChooser chooser = getFileChooser ();
if ( directorySelected )
{
approveButton.setText ( directoryOpenButtonText );
approveButton.setToolTipText ( directoryOpenButtonToolTipText );
}
else
{
approveButton.setText ( getApproveButtonText ( chooser ) );
approveButton.setToolTipText ( getApproveButtonToolTipText ( chooser ) );
}
}
public String getDirectoryName ()
{
// PENDING(jeff) - get the name from the directory combobox
return null;
}
public void setDirectoryName ( String dirname )
{
// PENDING(jeff) - set the name in the directory combobox
}
protected DirectoryComboBoxRenderer createDirectoryComboBoxRenderer (
JFileChooser fc )
{
return new DirectoryComboBoxRenderer ();
}
//
// Renderer for DirectoryComboBox
//
class DirectoryComboBoxRenderer extends DefaultListCellRenderer
{
IndentIcon ii = new IndentIcon ();
public Component getListCellRendererComponent ( JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus )
{
super.getListCellRendererComponent ( list, value, index, isSelected,
cellHasFocus );
if ( value == null )
{
setText ( "" );
return this;
}
File directory = ( File ) value;
setText ( getFileChooser ().getName ( directory ) );
Icon icon = getFileChooser ().getIcon ( directory );
ii.icon = icon;
ii.depth = directoryComboBoxModel.getDepth ( index );
setIcon ( ii );
return this;
}
}
final static int space = 10;
class IndentIcon implements Icon
{
Icon icon = null;
int depth = 0;
public void paintIcon ( Component c, Graphics g, int x, int y )
{
if ( c.getComponentOrientation ().isLeftToRight () )
{
icon.paintIcon ( c, g, x + depth * space, y );
}
else
{
icon.paintIcon ( c, g, x, y );
}
}
public int getIconWidth ()
{
return icon.getIconWidth () + depth * space;
}
public int getIconHeight ()
{
return icon.getIconHeight ();
}
}
//
// DataModel for DirectoryComboxbox
//
protected DirectoryComboBoxModel createDirectoryComboBoxModel (
JFileChooser fc )
{
return new DirectoryComboBoxModel ();
}
/**
* Data model for a type-face selection combo-box.
*/
protected class DirectoryComboBoxModel extends AbstractListModel implements
ComboBoxModel
{
Vector directories = new Vector ();
int [] depths = null;
File selectedDirectory = null;
JFileChooser chooser = getFileChooser ();
FileSystemView fsv = chooser.getFileSystemView ();
public DirectoryComboBoxModel ()
{
// Add the current directory to the model, and make it the
// selectedDirectory
File dir = getFileChooser ().getCurrentDirectory ();
if ( dir != null )
{
addItem ( dir );
}
}
/**
* Adds the directory to the model and sets it to be selected, additionally
* clears out the previous selected directory and the paths leading up to
* it, if any.
*/
private void addItem ( File directory )
{
if ( directory == null )
{
return;
}
directories.clear ();
File [] baseFolders;
if ( useShellFolder )
{
baseFolders = ( File [] ) ShellFolder
.get ( "fileChooserComboBoxFolders" );
}
else
{
baseFolders = fsv.getRoots ();
}
directories.addAll ( Arrays.asList ( baseFolders ) );
// Get the canonical (full) path. This has the side
// benefit of removing extraneous chars from the path,
// for example /foo/bar/ becomes /foo/bar
File canonical = null;
try
{
canonical = directory.getCanonicalFile ();
}
catch ( IOException e )
{
// Maybe drive is not ready. Can't abort here.
canonical = directory;
}
// create File instances of each directory leading up to the top
try
{
File sf = ShellFolder.getShellFolder ( canonical );
File f = sf;
Vector path = new Vector ( 10 );
do
{
path.addElement ( f );
}
while ( ( f = f.getParentFile () ) != null );
int pathCount = path.size ();
// Insert chain at appropriate place in vector
for ( int i = 0 ; i < pathCount ; i++ )
{
f = ( File ) path.get ( i );
if ( directories.contains ( f ) )
{
int topIndex = directories.indexOf ( f );
for ( int j = i - 1 ; j >= 0 ; j-- )
{
directories.insertElementAt ( path.get ( j ), topIndex + i - j );
}
break;
}
}
calculateDepths ();
setSelectedItem ( sf );
}
catch ( FileNotFoundException ex )
{
calculateDepths ();
}
}
private void calculateDepths ()
{
depths = new int [ directories.size () ];
for ( int i = 0 ; i < depths.length ; i++ )
{
File dir = ( File ) directories.get ( i );
File parent = dir.getParentFile ();
depths [ i ] = 0;
if ( parent != null )
{
for ( int j = i - 1 ; j >= 0 ; j-- )
{
if ( parent.equals ( ( File ) directories.get ( j ) ) )
{
depths [ i ] = depths [ j ] + 1;
break;
}
}
}
}
}
public int getDepth ( int i )
{
return ( depths != null && i >= 0 && i < depths.length ) ? depths [ i ]
: 0;
}
public void setSelectedItem ( Object selectedDirectory )
{
this.selectedDirectory = ( File ) selectedDirectory;
fireContentsChanged ( this, -1, -1 );
}
public Object getSelectedItem ()
{
return selectedDirectory;
}
public int getSize ()
{
return directories.size ();
}
public Object getElementAt ( int index )
{
return directories.elementAt ( index );
}
}
//
// Renderer for Types ComboBox
//
protected FilterComboBoxRenderer createFilterComboBoxRenderer ()
{
return new FilterComboBoxRenderer ();
}
/**
* Render different type sizes and styles.
*/
public class FilterComboBoxRenderer extends DefaultListCellRenderer
{
public Component getListCellRendererComponent ( JList list, Object value,
int index, boolean isSelected, boolean cellHasFocus )
{
super.getListCellRendererComponent ( list, value, index, isSelected,
cellHasFocus );
if ( value != null && value instanceof FileFilter )
{
setText ( ( ( FileFilter ) value ).getDescription () );
}
return this;
}
}
//
// DataModel for Types Comboxbox
//
protected FilterComboBoxModel createFilterComboBoxModel ()
{
return new FilterComboBoxModel ();
}
/**
* Data model for a type-face selection combo-box.
*/
protected class FilterComboBoxModel extends AbstractListModel implements
ComboBoxModel, PropertyChangeListener
{
protected FileFilter [] filters;
protected FilterComboBoxModel ()
{
super ();
filters = getFileChooser ().getChoosableFileFilters ();
}
public void propertyChange ( PropertyChangeEvent e )
{
String prop = e.getPropertyName ();
if ( prop == JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY )
{
filters = ( FileFilter [] ) e.getNewValue ();
fireContentsChanged ( this, -1, -1 );
}
else if ( prop == JFileChooser.FILE_FILTER_CHANGED_PROPERTY )
{
fireContentsChanged ( this, -1, -1 );
}
}
public void setSelectedItem ( Object filter )
{
if ( filter != null )
{
getFileChooser ().setFileFilter ( ( FileFilter ) filter );
setFileName ( null );
fireContentsChanged ( this, -1, -1 );
}
}
public Object getSelectedItem ()
{
// Ensure that the current filter is in the list.
// NOTE: we shouldnt' have to do this, since JFileChooser adds
// the filter to the choosable filters list when the filter
// is set. Lets be paranoid just in case someone overrides
// setFileFilter in JFileChooser.
FileFilter currentFilter = getFileChooser ().getFileFilter ();
boolean found = false;
if ( currentFilter != null )
{
for ( int i = 0 ; i < filters.length ; i++ )
{
if ( filters [ i ] == currentFilter )
{
found = true;
}
}
if ( found == false )
{
getFileChooser ().addChoosableFileFilter ( currentFilter );
}
}
return getFileChooser ().getFileFilter ();
}
public int getSize ()
{
if ( filters != null )
{
return filters.length;
}
else
{
return 0;
}
}
public Object getElementAt ( int index )
{
if ( index > getSize () - 1 )
{
// This shouldn't happen. Try to recover gracefully.
return getFileChooser ().getFileFilter ();
}
if ( filters != null )
{
return filters [ index ];
}
else
{
return null;
}
}
}
public void valueChanged ( ListSelectionEvent e )
{
JFileChooser fc = getFileChooser ();
File f = fc.getSelectedFile ();
if ( !e.getValueIsAdjusting () && f != null
&& !getFileChooser ().isTraversable ( f ) )
{
setFileName ( fileNameString ( f ) );
}
}
/**
* Acts when DirectoryComboBox has changed the selected item.
*/
protected class DirectoryComboBoxAction extends AbstractAction
{
protected DirectoryComboBoxAction ()
{
super ( "DirectoryComboBoxAction" );
}
public void actionPerformed ( ActionEvent e )
{
File f = ( File ) directoryComboBox.getSelectedItem ();
getFileChooser ().setCurrentDirectory ( f );
}
}
protected JButton getApproveButton ( JFileChooser fc )
{
return approveButton;
}
/**
* <code>ButtonAreaLayout</code> behaves in a similar manner to
* <code>FlowLayout</code>. It lays out all components from left to right,
* flushed right. The widths of all components will be set to the largest
* preferred size width.
*/
private static class ButtonAreaLayout implements LayoutManager
{
private int hGap = 5;
private int topMargin = 17;
public void addLayoutComponent ( String string, Component comp )
{
}
public void layoutContainer ( Container container )
{
Component [] children = container.getComponents ();
if ( children != null && children.length > 0 )
{
int numChildren = children.length;
Dimension [] sizes = new Dimension [ numChildren ];
Insets insets = container.getInsets ();
int yLocation = insets.top + topMargin;
int maxWidth = 0;
for ( int counter = 0 ; counter < numChildren ; counter++ )
{
sizes [ counter ] = children [ counter ].getPreferredSize ();
maxWidth = Math.max ( maxWidth, sizes [ counter ].width );
}
int xLocation, xOffset;
if ( container.getComponentOrientation ().isLeftToRight () )
{
xLocation = container.getSize ().width - insets.left - maxWidth;
xOffset = hGap + maxWidth;
}
else
{
xLocation = insets.left;
xOffset = - ( hGap + maxWidth );
}
for ( int counter = numChildren - 1 ; counter >= 0 ; counter-- )
{
children [ counter ].setBounds ( xLocation, yLocation, maxWidth,
sizes [ counter ].height );
xLocation -= xOffset;
}
}
}
public Dimension minimumLayoutSize ( Container c )
{
if ( c != null )
{
Component [] children = c.getComponents ();
if ( children != null && children.length > 0 )
{
int numChildren = children.length;
int height = 0;
Insets cInsets = c.getInsets ();
int extraHeight = topMargin + cInsets.top + cInsets.bottom;
int extraWidth = cInsets.left + cInsets.right;
int maxWidth = 0;
for ( int counter = 0 ; counter < numChildren ; counter++ )
{
Dimension aSize = children [ counter ].getPreferredSize ();
height = Math.max ( height, aSize.height );
maxWidth = Math.max ( maxWidth, aSize.width );
}
return new Dimension ( extraWidth + numChildren * maxWidth
+ ( numChildren - 1 ) * hGap, extraHeight + height );
}
}
return new Dimension ( 0, 0 );
}
public Dimension preferredLayoutSize ( Container c )
{
return minimumLayoutSize ( c );
}
public void removeLayoutComponent ( Component c )
{
}
}
private static void groupLabels ( AlignedLabel [] group )
{
for ( int i = 0 ; i < group.length ; i++ )
{
group [ i ].group = group;
}
}
private class AlignedLabel extends JLabel
{
private AlignedLabel [] group;
private int maxWidth = 0;
AlignedLabel ( String text )
{
super ( text );
setAlignmentX ( JComponent.LEFT_ALIGNMENT );
}
public Dimension getPreferredSize ()
{
Dimension d = super.getPreferredSize ();
// Align the width with all other labels in group.
return new Dimension ( getMaxWidth () + 11, d.height );
}
private int getMaxWidth ()
{
if ( maxWidth == 0 && group != null )
{
int max = 0;
for ( int i = 0 ; i < group.length ; i++ )
{
max = Math.max ( group [ i ].getSuperPreferredWidth (), max );
}
for ( int i = 0 ; i < group.length ; i++ )
{
group [ i ].maxWidth = max;
}
}
return maxWidth;
}
private int getSuperPreferredWidth ()
{
return super.getPreferredSize ().width;
}
}
}