mirror of
https://github.com/autc04/Retro68.git
synced 2024-12-13 03:29:50 +00:00
2121 lines
57 KiB
Java
2121 lines
57 KiB
Java
/* MetalFileChooserUI.java --
|
|
Copyright (C) 2005 Free Software Foundation, Inc.
|
|
|
|
This file is part of GNU Classpath.
|
|
|
|
GNU Classpath is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2, or (at your option)
|
|
any later version.
|
|
|
|
GNU Classpath is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with GNU Classpath; see the file COPYING. If not, write to the
|
|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
02110-1301 USA.
|
|
|
|
Linking this library statically or dynamically with other modules is
|
|
making a combined work based on this library. Thus, the terms and
|
|
conditions of the GNU General Public License cover the whole
|
|
combination.
|
|
|
|
As a special exception, the copyright holders of this library give you
|
|
permission to link this library with independent modules to produce an
|
|
executable, regardless of the license terms of these independent
|
|
modules, and to copy and distribute the resulting executable under
|
|
terms of your choice, provided that you also meet, for each linked
|
|
independent module, the terms and conditions of the license of that
|
|
module. An independent module is a module which is not derived from
|
|
or based on this library. If you modify this library, you may extend
|
|
this exception to your version of the library, but you are not
|
|
obligated to do so. If you do not wish to do so, delete this
|
|
exception statement from your version. */
|
|
|
|
|
|
package javax.swing.plaf.metal;
|
|
|
|
import java.awt.BorderLayout;
|
|
import java.awt.Component;
|
|
import java.awt.Container;
|
|
import java.awt.Dimension;
|
|
import java.awt.Graphics;
|
|
import java.awt.GridLayout;
|
|
import java.awt.Insets;
|
|
import java.awt.LayoutManager;
|
|
import java.awt.Rectangle;
|
|
import java.awt.Window;
|
|
import java.awt.event.ActionEvent;
|
|
import java.awt.event.ActionListener;
|
|
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.text.DateFormat;
|
|
import java.text.NumberFormat;
|
|
import java.util.Date;
|
|
import java.util.List;
|
|
|
|
import javax.swing.AbstractAction;
|
|
import javax.swing.AbstractListModel;
|
|
import javax.swing.ActionMap;
|
|
import javax.swing.BorderFactory;
|
|
import javax.swing.ButtonGroup;
|
|
import javax.swing.ComboBoxModel;
|
|
import javax.swing.DefaultListCellRenderer;
|
|
import javax.swing.Icon;
|
|
import javax.swing.JButton;
|
|
import javax.swing.JComboBox;
|
|
import javax.swing.JComponent;
|
|
import javax.swing.JDialog;
|
|
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.ListModel;
|
|
import javax.swing.ListSelectionModel;
|
|
import javax.swing.SwingUtilities;
|
|
import javax.swing.UIManager;
|
|
import javax.swing.event.ListSelectionEvent;
|
|
import javax.swing.event.ListSelectionListener;
|
|
import javax.swing.filechooser.FileFilter;
|
|
import javax.swing.filechooser.FileSystemView;
|
|
import javax.swing.filechooser.FileView;
|
|
import javax.swing.plaf.ComponentUI;
|
|
import javax.swing.plaf.basic.BasicFileChooserUI;
|
|
import javax.swing.table.DefaultTableCellRenderer;
|
|
import javax.swing.table.DefaultTableModel;
|
|
|
|
|
|
/**
|
|
* A UI delegate for the {@link JFileChooser} component. This class is only
|
|
* partially implemented and is not usable yet.
|
|
*/
|
|
public class MetalFileChooserUI
|
|
extends BasicFileChooserUI
|
|
{
|
|
|
|
/**
|
|
* A renderer for the files and directories in the file chooser table.
|
|
*/
|
|
class TableFileRenderer
|
|
extends DefaultTableCellRenderer
|
|
{
|
|
|
|
/**
|
|
* Creates a new renderer.
|
|
*/
|
|
public TableFileRenderer()
|
|
{
|
|
super();
|
|
}
|
|
|
|
/**
|
|
* Returns a component that can render the specified value.
|
|
*
|
|
* @param table the table
|
|
* @param value the string value of the cell
|
|
* @param isSelected is the item selected?
|
|
* @param hasFocus does the item have the focus?
|
|
* @param row the row
|
|
* @param column the column
|
|
*
|
|
* @return The renderer.
|
|
*/
|
|
public Component getTableCellRendererComponent(JTable table, Object value,
|
|
boolean isSelected, boolean hasFocus, int row, int column)
|
|
{
|
|
if (column == 0)
|
|
{
|
|
FileView v = getFileView(getFileChooser());
|
|
ListModel lm = fileList.getModel();
|
|
if (row < lm.getSize())
|
|
setIcon(v.getIcon((File) lm.getElementAt(row)));
|
|
}
|
|
else
|
|
setIcon(null);
|
|
|
|
setText(value.toString());
|
|
setOpaque(true);
|
|
setEnabled(table.isEnabled());
|
|
setFont(fileList.getFont());
|
|
|
|
if (startEditing && column == 0 || !isSelected)
|
|
{
|
|
setBackground(table.getBackground());
|
|
setForeground(table.getForeground());
|
|
}
|
|
else
|
|
{
|
|
setBackground(table.getSelectionBackground());
|
|
setForeground(table.getSelectionForeground());
|
|
}
|
|
|
|
if (hasFocus)
|
|
setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
|
|
else
|
|
setBorder(noFocusBorder);
|
|
|
|
return this;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ActionListener for the list view.
|
|
*/
|
|
class ListViewActionListener implements ActionListener
|
|
{
|
|
|
|
/**
|
|
* This method is invoked when an action occurs.
|
|
*
|
|
* @param e -
|
|
* the <code>ActionEvent</code> that occurred
|
|
*/
|
|
public void actionPerformed(ActionEvent e)
|
|
{
|
|
if (!listView)
|
|
{
|
|
int[] index = fileTable.getSelectedRows();
|
|
listView = true;
|
|
JFileChooser fc = getFileChooser();
|
|
fc.remove(fileTablePanel);
|
|
createList(fc);
|
|
|
|
fileList.getSelectionModel().clearSelection();
|
|
if (index.length > 0)
|
|
for (int i = 0; i < index.length; i++)
|
|
fileList.getSelectionModel().addSelectionInterval(index[i], index[i]);
|
|
|
|
fc.add(fileListPanel, BorderLayout.CENTER);
|
|
fc.revalidate();
|
|
fc.repaint();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ActionListener for the details view.
|
|
*/
|
|
class DetailViewActionListener implements ActionListener
|
|
{
|
|
|
|
/**
|
|
* This method is invoked when an action occurs.
|
|
*
|
|
* @param e -
|
|
* the <code>ActionEvent</code> that occurred
|
|
*/
|
|
public void actionPerformed(ActionEvent e)
|
|
{
|
|
if (listView)
|
|
{
|
|
int[] index = fileList.getSelectedIndices();
|
|
JFileChooser fc = getFileChooser();
|
|
listView = false;
|
|
fc.remove(fileListPanel);
|
|
|
|
if (fileTable == null)
|
|
createDetailsView(fc);
|
|
else
|
|
updateTable();
|
|
|
|
fileTable.getSelectionModel().clearSelection();
|
|
if (index.length > 0)
|
|
{
|
|
for (int i = 0; i < index.length; i++)
|
|
fileTable.getSelectionModel().addSelectionInterval(index[i], index[i]);
|
|
}
|
|
|
|
fc.add(fileTablePanel, BorderLayout.CENTER);
|
|
fc.revalidate();
|
|
fc.repaint();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A property change listener.
|
|
*/
|
|
class MetalFileChooserPropertyChangeListener
|
|
implements PropertyChangeListener
|
|
{
|
|
/**
|
|
* Default constructor.
|
|
*/
|
|
public MetalFileChooserPropertyChangeListener()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Handles a property change event.
|
|
*
|
|
* @param e the event.
|
|
*/
|
|
public void propertyChange(PropertyChangeEvent e)
|
|
{
|
|
JFileChooser filechooser = getFileChooser();
|
|
|
|
String n = e.getPropertyName();
|
|
if (n.equals(JFileChooser.MULTI_SELECTION_ENABLED_CHANGED_PROPERTY))
|
|
{
|
|
int mode = -1;
|
|
if (filechooser.isMultiSelectionEnabled())
|
|
mode = ListSelectionModel.MULTIPLE_INTERVAL_SELECTION;
|
|
else
|
|
mode = ListSelectionModel.SINGLE_SELECTION;
|
|
|
|
if (listView)
|
|
fileList.setSelectionMode(mode);
|
|
else
|
|
fileTable.setSelectionMode(mode);
|
|
}
|
|
else if (n.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY))
|
|
{
|
|
File file = filechooser.getSelectedFile();
|
|
|
|
if (file != null
|
|
&& filechooser.getDialogType() == JFileChooser.SAVE_DIALOG)
|
|
{
|
|
if (file.isDirectory() && filechooser.isTraversable(file))
|
|
{
|
|
directoryLabel = look;
|
|
dirLabel.setText(directoryLabel);
|
|
filechooser.setApproveButtonText(openButtonText);
|
|
filechooser.setApproveButtonToolTipText(openButtonToolTipText);
|
|
}
|
|
else if (file.isFile())
|
|
{
|
|
directoryLabel = save;
|
|
dirLabel.setText(directoryLabel);
|
|
filechooser.setApproveButtonText(saveButtonText);
|
|
filechooser.setApproveButtonToolTipText(saveButtonToolTipText);
|
|
}
|
|
}
|
|
|
|
if (file == null)
|
|
setFileName(null);
|
|
else if (file.isFile() || filechooser.getFileSelectionMode()
|
|
!= JFileChooser.FILES_ONLY)
|
|
setFileName(file.getName());
|
|
int index = -1;
|
|
index = getModel().indexOf(file);
|
|
if (index >= 0)
|
|
{
|
|
if (listView)
|
|
{
|
|
fileList.setSelectedIndex(index);
|
|
fileList.ensureIndexIsVisible(index);
|
|
fileList.revalidate();
|
|
fileList.repaint();
|
|
}
|
|
else
|
|
{
|
|
fileTable.getSelectionModel().addSelectionInterval(index, index);
|
|
fileTable.scrollRectToVisible(fileTable.getCellRect(index, 0, true));
|
|
fileTable.revalidate();
|
|
fileTable.repaint();
|
|
}
|
|
}
|
|
}
|
|
|
|
else if (n.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY))
|
|
{
|
|
if (listView)
|
|
{
|
|
fileList.clearSelection();
|
|
fileList.revalidate();
|
|
fileList.repaint();
|
|
}
|
|
else
|
|
{
|
|
fileTable.clearSelection();
|
|
fileTable.revalidate();
|
|
fileTable.repaint();
|
|
}
|
|
|
|
setDirectorySelected(false);
|
|
File currentDirectory = filechooser.getCurrentDirectory();
|
|
setDirectory(currentDirectory);
|
|
boolean hasParent = currentDirectory.getParentFile() != null;
|
|
getChangeToParentDirectoryAction().setEnabled(hasParent);
|
|
}
|
|
|
|
else if (n.equals(JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY))
|
|
{
|
|
filterModel.propertyChange(e);
|
|
}
|
|
else if (n.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY))
|
|
{
|
|
filterModel.propertyChange(e);
|
|
}
|
|
else if (n.equals(JFileChooser.DIALOG_TYPE_CHANGED_PROPERTY)
|
|
|| n.equals(JFileChooser.DIALOG_TITLE_CHANGED_PROPERTY))
|
|
{
|
|
Window owner = SwingUtilities.windowForComponent(filechooser);
|
|
if (owner instanceof JDialog)
|
|
((JDialog) owner).setTitle(getDialogTitle(filechooser));
|
|
approveButton.setText(getApproveButtonText(filechooser));
|
|
approveButton.setToolTipText(
|
|
getApproveButtonToolTipText(filechooser));
|
|
approveButton.setMnemonic(getApproveButtonMnemonic(filechooser));
|
|
}
|
|
|
|
else if (n.equals(JFileChooser.APPROVE_BUTTON_TEXT_CHANGED_PROPERTY))
|
|
approveButton.setText(getApproveButtonText(filechooser));
|
|
|
|
else if (n.equals(
|
|
JFileChooser.APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY))
|
|
approveButton.setToolTipText(getApproveButtonToolTipText(filechooser));
|
|
|
|
else if (n.equals(JFileChooser.APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY))
|
|
approveButton.setMnemonic(getApproveButtonMnemonic(filechooser));
|
|
|
|
else if (n.equals(
|
|
JFileChooser.CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY))
|
|
{
|
|
if (filechooser.getControlButtonsAreShown())
|
|
{
|
|
topPanel.add(controls, BorderLayout.EAST);
|
|
}
|
|
else
|
|
topPanel.remove(controls);
|
|
topPanel.revalidate();
|
|
topPanel.repaint();
|
|
topPanel.doLayout();
|
|
}
|
|
|
|
else if (n.equals(
|
|
JFileChooser.ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY))
|
|
{
|
|
if (filechooser.isAcceptAllFileFilterUsed())
|
|
filechooser.addChoosableFileFilter(
|
|
getAcceptAllFileFilter(filechooser));
|
|
else
|
|
filechooser.removeChoosableFileFilter(
|
|
getAcceptAllFileFilter(filechooser));
|
|
}
|
|
|
|
else if (n.equals(JFileChooser.ACCESSORY_CHANGED_PROPERTY))
|
|
{
|
|
JComponent old = (JComponent) e.getOldValue();
|
|
if (old != null)
|
|
getAccessoryPanel().remove(old);
|
|
JComponent newval = (JComponent) e.getNewValue();
|
|
if (newval != null)
|
|
getAccessoryPanel().add(newval);
|
|
}
|
|
|
|
if (n.equals(JFileChooser.DIRECTORY_CHANGED_PROPERTY)
|
|
|| n.equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY)
|
|
|| n.equals(JFileChooser.FILE_HIDING_CHANGED_PROPERTY))
|
|
{
|
|
// Remove editing component
|
|
if (fileTable != null)
|
|
fileTable.removeAll();
|
|
if (fileList != null)
|
|
fileList.removeAll();
|
|
startEditing = false;
|
|
|
|
// Set text on button back to original.
|
|
if (filechooser.getDialogType() == JFileChooser.SAVE_DIALOG)
|
|
{
|
|
directoryLabel = save;
|
|
dirLabel.setText(directoryLabel);
|
|
filechooser.setApproveButtonText(saveButtonText);
|
|
filechooser.setApproveButtonToolTipText(saveButtonToolTipText);
|
|
}
|
|
|
|
rescanCurrentDirectory(filechooser);
|
|
}
|
|
|
|
filechooser.revalidate();
|
|
filechooser.repaint();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A combo box model containing the selected directory and all its parent
|
|
* directories.
|
|
*/
|
|
protected class DirectoryComboBoxModel
|
|
extends AbstractListModel
|
|
implements ComboBoxModel
|
|
{
|
|
/** Storage for the items in the model. */
|
|
private List items;
|
|
|
|
/** The index of the selected item. */
|
|
private int selectedIndex;
|
|
|
|
/**
|
|
* Creates a new model.
|
|
*/
|
|
public DirectoryComboBoxModel()
|
|
{
|
|
items = new java.util.ArrayList();
|
|
selectedIndex = -1;
|
|
}
|
|
|
|
/**
|
|
* Returns the number of items in the model.
|
|
*
|
|
* @return The number of items in the model.
|
|
*/
|
|
public int getSize()
|
|
{
|
|
return items.size();
|
|
}
|
|
|
|
/**
|
|
* Returns the item at the specified index.
|
|
*
|
|
* @param index the item index.
|
|
*
|
|
* @return The item.
|
|
*/
|
|
public Object getElementAt(int index)
|
|
{
|
|
return items.get(index);
|
|
}
|
|
|
|
/**
|
|
* Returns the depth of the item at the given <code>index</code>.
|
|
*
|
|
* @param index the item index.
|
|
*
|
|
* @return The depth.
|
|
*/
|
|
public int getDepth(int index)
|
|
{
|
|
return Math.max(index, 0);
|
|
}
|
|
|
|
/**
|
|
* Returns the selected item, or <code>null</code> if no item is selected.
|
|
*
|
|
* @return The selected item, or <code>null</code>.
|
|
*/
|
|
public Object getSelectedItem()
|
|
{
|
|
if (selectedIndex >= 0)
|
|
return items.get(selectedIndex);
|
|
else
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Sets the selected item. This clears all the directories from the
|
|
* existing list, and repopulates it with the new selected directory
|
|
* and all its parent directories.
|
|
*
|
|
* @param selectedDirectory the selected directory.
|
|
*/
|
|
public void setSelectedItem(Object selectedDirectory)
|
|
{
|
|
items.clear();
|
|
FileSystemView fsv = getFileChooser().getFileSystemView();
|
|
File parent = (File) selectedDirectory;
|
|
while (parent != null)
|
|
{
|
|
items.add(0, parent);
|
|
parent = fsv.getParentDirectory(parent);
|
|
}
|
|
selectedIndex = items.indexOf(selectedDirectory);
|
|
fireContentsChanged(this, 0, items.size() - 1);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Handles changes to the selection in the directory combo box.
|
|
*/
|
|
protected class DirectoryComboBoxAction
|
|
extends AbstractAction
|
|
{
|
|
/**
|
|
* Creates a new action.
|
|
*/
|
|
protected DirectoryComboBoxAction()
|
|
{
|
|
// Nothing to do here.
|
|
}
|
|
|
|
/**
|
|
* Handles the action event.
|
|
*
|
|
* @param e the event.
|
|
*/
|
|
public void actionPerformed(ActionEvent e)
|
|
{
|
|
JFileChooser fc = getFileChooser();
|
|
fc.setCurrentDirectory((File) directoryModel.getSelectedItem());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A renderer for the items in the directory combo box.
|
|
*/
|
|
class DirectoryComboBoxRenderer
|
|
extends DefaultListCellRenderer
|
|
{
|
|
/**
|
|
* This is the icon that is displayed in the combobox. This wraps
|
|
* the standard icon and adds indendation.
|
|
*/
|
|
private IndentIcon indentIcon;
|
|
|
|
/**
|
|
* Creates a new renderer.
|
|
*/
|
|
public DirectoryComboBoxRenderer(JFileChooser fc)
|
|
{
|
|
indentIcon = new IndentIcon();
|
|
}
|
|
|
|
/**
|
|
* Returns a component that can be used to paint the given value within
|
|
* the list.
|
|
*
|
|
* @param list the list.
|
|
* @param value the value (a {@link File}).
|
|
* @param index the item index.
|
|
* @param isSelected is the item selected?
|
|
* @param cellHasFocus does the list cell have focus?
|
|
*
|
|
* @return The list cell renderer.
|
|
*/
|
|
public Component getListCellRendererComponent(JList list, Object value,
|
|
int index,
|
|
boolean isSelected,
|
|
boolean cellHasFocus)
|
|
{
|
|
super.getListCellRendererComponent(list, value, index, isSelected,
|
|
cellHasFocus);
|
|
File file = (File) value;
|
|
setText(getFileChooser().getName(file));
|
|
|
|
// Install indented icon.
|
|
Icon icon = getFileChooser().getIcon(file);
|
|
indentIcon.setIcon(icon);
|
|
int depth = directoryModel.getDepth(index);
|
|
indentIcon.setDepth(depth);
|
|
setIcon(indentIcon);
|
|
|
|
return this;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An icon that wraps another icon and adds indentation.
|
|
*/
|
|
class IndentIcon
|
|
implements Icon
|
|
{
|
|
|
|
/**
|
|
* The indentation level.
|
|
*/
|
|
private static final int INDENT = 10;
|
|
|
|
/**
|
|
* The wrapped icon.
|
|
*/
|
|
private Icon icon;
|
|
|
|
/**
|
|
* The current depth.
|
|
*/
|
|
private int depth;
|
|
|
|
/**
|
|
* Sets the icon to be wrapped.
|
|
*
|
|
* @param i the icon
|
|
*/
|
|
void setIcon(Icon i)
|
|
{
|
|
icon = i;
|
|
}
|
|
|
|
/**
|
|
* Sets the indentation depth.
|
|
*
|
|
* @param d the depth to set
|
|
*/
|
|
void setDepth(int d)
|
|
{
|
|
depth = d;
|
|
}
|
|
|
|
public int getIconHeight()
|
|
{
|
|
return icon.getIconHeight();
|
|
}
|
|
|
|
public int getIconWidth()
|
|
{
|
|
return icon.getIconWidth() + depth * INDENT;
|
|
}
|
|
|
|
public void paintIcon(Component c, Graphics g, int x, int y)
|
|
{
|
|
icon.paintIcon(c, g, x + depth * INDENT, y);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* A renderer for the files and directories in the file chooser.
|
|
*/
|
|
protected class FileRenderer
|
|
extends DefaultListCellRenderer
|
|
{
|
|
|
|
/**
|
|
* Creates a new renderer.
|
|
*/
|
|
protected FileRenderer()
|
|
{
|
|
// Nothing to do here.
|
|
}
|
|
|
|
/**
|
|
* Returns a component that can render the specified value.
|
|
*
|
|
* @param list the list.
|
|
* @param value the value (a {@link File}).
|
|
* @param index the index.
|
|
* @param isSelected is the item selected?
|
|
* @param cellHasFocus does the item have the focus?
|
|
*
|
|
* @return The renderer.
|
|
*/
|
|
public Component getListCellRendererComponent(JList list, Object value,
|
|
int index, boolean isSelected, boolean cellHasFocus)
|
|
{
|
|
FileView v = getFileView(getFileChooser());
|
|
File f = (File) value;
|
|
if (f != null)
|
|
{
|
|
setText(v.getName(f));
|
|
setIcon(v.getIcon(f));
|
|
}
|
|
else
|
|
{
|
|
setText("");
|
|
setIcon(null);
|
|
}
|
|
setOpaque(true);
|
|
if (isSelected)
|
|
{
|
|
setBackground(list.getSelectionBackground());
|
|
setForeground(list.getSelectionForeground());
|
|
}
|
|
else
|
|
{
|
|
setBackground(list.getBackground());
|
|
setForeground(list.getForeground());
|
|
}
|
|
|
|
setEnabled(list.isEnabled());
|
|
setFont(list.getFont());
|
|
|
|
if (cellHasFocus)
|
|
setBorder(UIManager.getBorder("List.focusCellHighlightBorder"));
|
|
else
|
|
setBorder(noFocusBorder);
|
|
return this;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A combo box model for the file selection filters.
|
|
*/
|
|
protected class FilterComboBoxModel
|
|
extends AbstractListModel
|
|
implements ComboBoxModel, PropertyChangeListener
|
|
{
|
|
|
|
/** Storage for the filters in the model. */
|
|
protected FileFilter[] filters;
|
|
|
|
/** The index of the selected file filter. */
|
|
private Object selected;
|
|
|
|
/**
|
|
* Creates a new model.
|
|
*/
|
|
protected FilterComboBoxModel()
|
|
{
|
|
filters = new FileFilter[1];
|
|
filters[0] = getAcceptAllFileFilter(getFileChooser());
|
|
selected = filters[0];
|
|
}
|
|
|
|
/**
|
|
* Handles property changes.
|
|
*
|
|
* @param e the property change event.
|
|
*/
|
|
public void propertyChange(PropertyChangeEvent e)
|
|
{
|
|
if (e.getPropertyName().equals(JFileChooser.FILE_FILTER_CHANGED_PROPERTY))
|
|
{
|
|
JFileChooser fc = getFileChooser();
|
|
FileFilter[] choosableFilters = fc.getChoosableFileFilters();
|
|
filters = choosableFilters;
|
|
fireContentsChanged(this, 0, filters.length);
|
|
selected = e.getNewValue();
|
|
fireContentsChanged(this, -1, -1);
|
|
}
|
|
else if (e.getPropertyName().equals(
|
|
JFileChooser.CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY))
|
|
{
|
|
// repopulate list
|
|
JFileChooser fc = getFileChooser();
|
|
FileFilter[] choosableFilters = fc.getChoosableFileFilters();
|
|
filters = choosableFilters;
|
|
fireContentsChanged(this, 0, filters.length);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the selected filter.
|
|
*
|
|
* @param filter the filter (<code>null</code> ignored).
|
|
*/
|
|
public void setSelectedItem(Object filter)
|
|
{
|
|
if (filter != null)
|
|
{
|
|
selected = filter;
|
|
fireContentsChanged(this, -1, -1);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the selected file filter.
|
|
*
|
|
* @return The selected file filter.
|
|
*/
|
|
public Object getSelectedItem()
|
|
{
|
|
return selected;
|
|
}
|
|
|
|
/**
|
|
* Returns the number of items in the model.
|
|
*
|
|
* @return The number of items in the model.
|
|
*/
|
|
public int getSize()
|
|
{
|
|
return filters.length;
|
|
}
|
|
|
|
/**
|
|
* Returns the item at the specified index.
|
|
*
|
|
* @param index the item index.
|
|
*
|
|
* @return The item at the specified index.
|
|
*/
|
|
public Object getElementAt(int index)
|
|
{
|
|
return filters[index];
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* A renderer for the items in the file filter combo box.
|
|
*/
|
|
public class FilterComboBoxRenderer
|
|
extends DefaultListCellRenderer
|
|
{
|
|
/**
|
|
* Creates a new renderer.
|
|
*/
|
|
public FilterComboBoxRenderer()
|
|
{
|
|
// Nothing to do here.
|
|
}
|
|
|
|
/**
|
|
* Returns a component that can be used to paint the given value within
|
|
* the list.
|
|
*
|
|
* @param list the list.
|
|
* @param value the value (a {@link FileFilter}).
|
|
* @param index the item index.
|
|
* @param isSelected is the item selected?
|
|
* @param cellHasFocus does the list cell have focus?
|
|
*
|
|
* @return This component as the renderer.
|
|
*/
|
|
public Component getListCellRendererComponent(JList list, Object value,
|
|
int index, boolean isSelected, boolean cellHasFocus)
|
|
{
|
|
super.getListCellRendererComponent(list, value, index, isSelected,
|
|
cellHasFocus);
|
|
FileFilter filter = (FileFilter) value;
|
|
setText(filter.getDescription());
|
|
return this;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A listener for selection events in the file list.
|
|
*
|
|
* @see #createListSelectionListener(JFileChooser)
|
|
*/
|
|
class MetalFileChooserSelectionListener
|
|
implements ListSelectionListener
|
|
{
|
|
/**
|
|
* Creates a new <code>SelectionListener</code> object.
|
|
*/
|
|
protected MetalFileChooserSelectionListener()
|
|
{
|
|
// Do nothing here.
|
|
}
|
|
|
|
/**
|
|
* Makes changes to different properties when
|
|
* a value has changed in the filechooser's selection.
|
|
*
|
|
* @param e - the list selection event that occured.
|
|
*/
|
|
public void valueChanged(ListSelectionEvent e)
|
|
{
|
|
File f = (File) fileList.getSelectedValue();
|
|
if (f == null)
|
|
return;
|
|
JFileChooser filechooser = getFileChooser();
|
|
if (! filechooser.isTraversable(f))
|
|
filechooser.setSelectedFile(f);
|
|
else
|
|
filechooser.setSelectedFile(null);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A mouse listener for the {@link JFileChooser}.
|
|
* This listener is used for editing filenames.
|
|
*/
|
|
protected class SingleClickListener
|
|
extends MouseAdapter
|
|
{
|
|
|
|
/** Stores instance of the list */
|
|
JList list;
|
|
|
|
/**
|
|
* Stores the current file that is being edited.
|
|
* It is null if nothing is currently being edited.
|
|
*/
|
|
File editFile;
|
|
|
|
/** The current file chooser. */
|
|
JFileChooser fc;
|
|
|
|
/** The last file selected. */
|
|
Object lastSelected;
|
|
|
|
/** The textfield used for editing. */
|
|
JTextField editField;
|
|
|
|
/**
|
|
* Creates a new listener.
|
|
*
|
|
* @param list the directory/file list.
|
|
*/
|
|
public SingleClickListener(JList list)
|
|
{
|
|
this.list = list;
|
|
editFile = null;
|
|
fc = getFileChooser();
|
|
lastSelected = null;
|
|
startEditing = false;
|
|
}
|
|
|
|
/**
|
|
* Receives notification of a mouse click event.
|
|
*
|
|
* @param e the event.
|
|
*/
|
|
public void mouseClicked(MouseEvent e)
|
|
{
|
|
if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON1)
|
|
{
|
|
int index = list.locationToIndex(e.getPoint());
|
|
File[] sf = fc.getSelectedFiles();
|
|
if ((!fc.isMultiSelectionEnabled() || (sf != null && sf.length <= 1))
|
|
&& index >= 0 && !startEditing && list.isSelectedIndex(index))
|
|
{
|
|
Object tmp = list.getModel().getElementAt(index);
|
|
if (lastSelected != null && lastSelected.equals(tmp))
|
|
editFile(index);
|
|
lastSelected = tmp;
|
|
}
|
|
else
|
|
completeEditing();
|
|
}
|
|
else
|
|
completeEditing();
|
|
}
|
|
|
|
/**
|
|
* Sets up the text editor for the current file.
|
|
*
|
|
* @param index -
|
|
* the current index of the item in the list to be edited.
|
|
*/
|
|
void editFile(int index)
|
|
{
|
|
Rectangle bounds = list.getCellBounds(index, index);
|
|
list.scrollRectToVisible(bounds);
|
|
editFile = (File) list.getModel().getElementAt(index);
|
|
if (editFile.canWrite())
|
|
{
|
|
startEditing = true;
|
|
editField = new JTextField(editFile.getName());
|
|
editField.addActionListener(new EditingActionListener());
|
|
|
|
Icon icon = getFileView(fc).getIcon(editFile);
|
|
if (icon != null)
|
|
{
|
|
int padding = icon.getIconWidth() + 4;
|
|
bounds.x += padding;
|
|
bounds.width -= padding;
|
|
}
|
|
editField.setBounds(bounds);
|
|
|
|
list.add(editField);
|
|
|
|
editField.requestFocus();
|
|
editField.selectAll();
|
|
}
|
|
else
|
|
completeEditing();
|
|
list.repaint();
|
|
}
|
|
|
|
/**
|
|
* Completes the editing.
|
|
*/
|
|
void completeEditing()
|
|
{
|
|
if (editField != null && editFile != null)
|
|
{
|
|
String text = editField.getText();
|
|
if (text != null && text != "" && !text.equals(fc.getName(editFile)))
|
|
{
|
|
File f = fc.getFileSystemView().
|
|
createFileObject(fc.getCurrentDirectory(), text);
|
|
if ( editFile.renameTo(f) )
|
|
rescanCurrentDirectory(fc);
|
|
}
|
|
list.remove(editField);
|
|
}
|
|
startEditing = false;
|
|
editFile = null;
|
|
lastSelected = null;
|
|
editField = null;
|
|
list.repaint();
|
|
}
|
|
|
|
/**
|
|
* ActionListener for the editing text field.
|
|
*/
|
|
class EditingActionListener implements ActionListener
|
|
{
|
|
|
|
/**
|
|
* This method is invoked when an action occurs.
|
|
*
|
|
* @param e -
|
|
* the <code>ActionEvent</code> that occurred
|
|
*/
|
|
public void actionPerformed(ActionEvent e)
|
|
{
|
|
if (editField != null)
|
|
completeEditing();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A mouse listener for the {@link JFileChooser}.
|
|
* This listener is used for the table
|
|
*/
|
|
private class TableClickListener extends MouseAdapter
|
|
{
|
|
|
|
/** Stores instance of the table */
|
|
JTable table;
|
|
|
|
/** Stores instance of the file chooser */
|
|
JFileChooser fc;
|
|
|
|
/** The last selected file. */
|
|
Object lastSelected;
|
|
|
|
/**
|
|
* Stores the current file that is being edited.
|
|
* It is null if nothing is currently being edited.
|
|
*/
|
|
File editFile;
|
|
|
|
/** The textfield used for editing. */
|
|
JTextField editField;
|
|
|
|
/**
|
|
* Creates a new listener.
|
|
*
|
|
* @param table the directory/file table
|
|
* @param fc the JFileChooser
|
|
*/
|
|
public TableClickListener(JTable table, JFileChooser fc)
|
|
{
|
|
this.table = table;
|
|
this.fc = fc;
|
|
lastSelected = fileList.getSelectedValue();
|
|
setDirectorySelected(false);
|
|
startEditing = false;
|
|
editFile = null;
|
|
editField = null;
|
|
}
|
|
|
|
/**
|
|
* Receives notification of a mouse click event.
|
|
*
|
|
* @param e the event.
|
|
*/
|
|
public void mouseClicked(MouseEvent e)
|
|
{
|
|
int row = table.getSelectedRow();
|
|
Object selVal = fileList.getModel().getElementAt(row);
|
|
if (selVal == null)
|
|
return;
|
|
FileSystemView fsv = fc.getFileSystemView();
|
|
if (e.getClickCount() == 1 &&
|
|
selVal.equals(lastSelected) &&
|
|
e.getButton() == MouseEvent.BUTTON1)
|
|
{
|
|
File[] sf = fc.getSelectedFiles();
|
|
if ((!fc.isMultiSelectionEnabled() || (sf != null && sf.length <= 1))
|
|
&& !startEditing)
|
|
{
|
|
editFile = (File) selVal;
|
|
editFile(row);
|
|
}
|
|
}
|
|
else if (e.getClickCount() >= 2 &&
|
|
selVal.equals(lastSelected))
|
|
{
|
|
if (startEditing)
|
|
completeEditing();
|
|
File f = fsv.createFileObject(lastSelected.toString());
|
|
if (fc.isTraversable(f))
|
|
{
|
|
fc.setCurrentDirectory(f);
|
|
fc.rescanCurrentDirectory();
|
|
}
|
|
else
|
|
{
|
|
fc.setSelectedFile(f);
|
|
fc.approveSelection();
|
|
closeDialog();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (startEditing)
|
|
completeEditing();
|
|
String path = selVal.toString();
|
|
File f = fsv.createFileObject(path);
|
|
fc.setSelectedFile(f);
|
|
if (fc.isTraversable(f))
|
|
{
|
|
setDirectorySelected(true);
|
|
setDirectory(f);
|
|
}
|
|
else
|
|
{
|
|
setDirectorySelected(false);
|
|
setDirectory(null);
|
|
}
|
|
lastSelected = selVal;
|
|
if (f.isFile())
|
|
setFileName(path.substring(path.lastIndexOf("/") + 1));
|
|
else if (fc.getFileSelectionMode() != JFileChooser.FILES_ONLY)
|
|
setFileName(path);
|
|
}
|
|
fileTable.repaint();
|
|
}
|
|
|
|
/**
|
|
* Sets up the text editor for the current file.
|
|
*
|
|
* @param row -
|
|
* the current row of the item in the list to be edited.
|
|
*/
|
|
void editFile(int row)
|
|
{
|
|
Rectangle bounds = table.getCellRect(row, 0, true);
|
|
table.scrollRectToVisible(bounds);
|
|
if (editFile.canWrite())
|
|
{
|
|
startEditing = true;
|
|
editField = new JTextField(editFile.getName());
|
|
editField.addActionListener(new EditingActionListener());
|
|
|
|
// Need to adjust y pos
|
|
bounds.y = row * table.getRowHeight();
|
|
editField.setBounds(bounds);
|
|
|
|
table.add(editField);
|
|
|
|
editField.requestFocus();
|
|
editField.selectAll();
|
|
}
|
|
else
|
|
completeEditing();
|
|
table.repaint();
|
|
}
|
|
|
|
/**
|
|
* Completes the editing.
|
|
*/
|
|
void completeEditing()
|
|
{
|
|
if (editField != null && editFile != null)
|
|
{
|
|
String text = editField.getText();
|
|
if (text != null && text != "" && !text.equals(fc.getName(editFile)))
|
|
if (editFile.renameTo(fc.getFileSystemView().createFileObject(
|
|
fc.getCurrentDirectory(), text)))
|
|
rescanCurrentDirectory(fc);
|
|
table.remove(editField);
|
|
}
|
|
startEditing = false;
|
|
editFile = null;
|
|
editField = null;
|
|
table.repaint();
|
|
}
|
|
|
|
/**
|
|
* ActionListener for the editing text field.
|
|
*/
|
|
class EditingActionListener implements ActionListener
|
|
{
|
|
|
|
/**
|
|
* This method is invoked when an action occurs.
|
|
*
|
|
* @param e -
|
|
* the <code>ActionEvent</code> that occurred
|
|
*/
|
|
public void actionPerformed(ActionEvent e)
|
|
{
|
|
if (editField != null)
|
|
completeEditing();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Closes the dialog.
|
|
*/
|
|
public void closeDialog()
|
|
{
|
|
Window owner = SwingUtilities.windowForComponent(fc);
|
|
if (owner instanceof JDialog)
|
|
((JDialog) owner).dispose();
|
|
}
|
|
}
|
|
|
|
/** The text for a label describing the directory combo box. */
|
|
private String directoryLabel;
|
|
|
|
private JComboBox directoryComboBox;
|
|
|
|
/** The model for the directory combo box. */
|
|
DirectoryComboBoxModel directoryModel;
|
|
|
|
/** The text for a label describing the file text field. */
|
|
private String fileLabel;
|
|
|
|
/** The file name text field. */
|
|
private JTextField fileTextField;
|
|
|
|
/** The text for a label describing the filter combo box. */
|
|
private String filterLabel;
|
|
|
|
/**
|
|
* The top panel (contains the directory combo box and the control buttons).
|
|
*/
|
|
private JPanel topPanel;
|
|
|
|
/** A panel containing the control buttons ('up', 'home' etc.). */
|
|
private JPanel controls;
|
|
|
|
/**
|
|
* The panel that contains the filename field and the filter combobox.
|
|
*/
|
|
private JPanel bottomPanel;
|
|
|
|
/**
|
|
* The panel that contains the 'Open' (or 'Save') and 'Cancel' buttons.
|
|
*/
|
|
private JPanel buttonPanel;
|
|
|
|
private JButton approveButton;
|
|
|
|
/** The file list. */
|
|
JList fileList;
|
|
|
|
/** The file table. */
|
|
JTable fileTable;
|
|
|
|
/** The panel containing the file list. */
|
|
JPanel fileListPanel;
|
|
|
|
/** The panel containing the file table. */
|
|
JPanel fileTablePanel;
|
|
|
|
/** The filter combo box model. */
|
|
private FilterComboBoxModel filterModel;
|
|
|
|
/** The action map. */
|
|
private ActionMap actionMap;
|
|
|
|
/** True if currently in list view. */
|
|
boolean listView;
|
|
|
|
/** True if we can or have started editing a cell. */
|
|
boolean startEditing;
|
|
|
|
/** The scrollpane used for the table and list. */
|
|
JScrollPane scrollPane;
|
|
|
|
/** The text for the label when saving. */
|
|
String save;
|
|
|
|
/** The text for the label when opening a directory. */
|
|
String look;
|
|
|
|
/** The label for the file combo box. */
|
|
JLabel dirLabel;
|
|
|
|
/** Listeners. */
|
|
ListSelectionListener listSelList;
|
|
MouseListener doubleClickList;
|
|
SingleClickListener singleClickList;
|
|
TableClickListener tableClickList;
|
|
|
|
/**
|
|
* A factory method that returns a UI delegate for the specified
|
|
* component.
|
|
*
|
|
* @param c the component (which should be a {@link JFileChooser}).
|
|
*/
|
|
public static ComponentUI createUI(JComponent c)
|
|
{
|
|
JFileChooser chooser = (JFileChooser) c;
|
|
return new MetalFileChooserUI(chooser);
|
|
}
|
|
|
|
/**
|
|
* Creates a new instance of this UI delegate.
|
|
*
|
|
* @param filechooser the file chooser component.
|
|
*/
|
|
public MetalFileChooserUI(JFileChooser filechooser)
|
|
{
|
|
super(filechooser);
|
|
bottomPanel = new JPanel(new GridLayout(3, 2));
|
|
buttonPanel = new JPanel();
|
|
}
|
|
|
|
public void installUI(JComponent c)
|
|
{
|
|
super.installUI(c);
|
|
actionMap = createActionMap();
|
|
}
|
|
|
|
public void uninstallUI(JComponent c)
|
|
{
|
|
super.uninstallUI(c);
|
|
actionMap = null;
|
|
}
|
|
|
|
/**
|
|
* Installs the sub-components of the file chooser.
|
|
*
|
|
* @param fc the file chooser component.
|
|
*/
|
|
public void installComponents(JFileChooser fc)
|
|
{
|
|
fc.setLayout(new BorderLayout());
|
|
topPanel = new JPanel(new BorderLayout());
|
|
dirLabel = new JLabel(directoryLabel);
|
|
topPanel.add(dirLabel, BorderLayout.WEST);
|
|
this.controls = new JPanel();
|
|
addControlButtons();
|
|
|
|
JPanel dirPanel = new JPanel(new VerticalMidLayout());
|
|
directoryModel = createDirectoryComboBoxModel(fc);
|
|
directoryComboBox = new JComboBox(directoryModel);
|
|
directoryComboBox.setRenderer(createDirectoryComboBoxRenderer(fc));
|
|
dirPanel.add(directoryComboBox);
|
|
topPanel.add(dirPanel);
|
|
topPanel.add(controls, BorderLayout.EAST);
|
|
topPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 0, 8));
|
|
fc.add(topPanel, BorderLayout.NORTH);
|
|
|
|
JPanel list = createList(fc);
|
|
list.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
|
|
fc.add(list, BorderLayout.CENTER);
|
|
|
|
JPanel bottomPanel = getBottomPanel();
|
|
filterModel = createFilterComboBoxModel();
|
|
JComboBox fileFilterCombo = new JComboBox(filterModel);
|
|
fileFilterCombo.setRenderer(createFilterComboBoxRenderer());
|
|
|
|
fileTextField = new JTextField();
|
|
JPanel fileNamePanel = new JPanel(new VerticalMidLayout());
|
|
fileNamePanel.setBorder(BorderFactory.createEmptyBorder(0, 20, 0, 5));
|
|
fileNamePanel.add(fileTextField);
|
|
JPanel row1 = new JPanel(new BorderLayout());
|
|
row1.add(new JLabel(this.fileLabel), BorderLayout.WEST);
|
|
row1.add(fileNamePanel);
|
|
bottomPanel.add(row1);
|
|
|
|
JPanel row2 = new JPanel(new BorderLayout());
|
|
row2.add(new JLabel(this.filterLabel), BorderLayout.WEST);
|
|
row2.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
|
|
row2.add(fileFilterCombo);
|
|
bottomPanel.add(row2);
|
|
JPanel buttonPanel = new JPanel(new ButtonLayout());
|
|
|
|
approveButton = new JButton(getApproveSelectionAction());
|
|
approveButton.setText(getApproveButtonText(fc));
|
|
approveButton.setToolTipText(getApproveButtonToolTipText(fc));
|
|
approveButton.setMnemonic(getApproveButtonMnemonic(fc));
|
|
buttonPanel.add(approveButton);
|
|
buttonPanel.setBorder(BorderFactory.createEmptyBorder(8, 0, 0, 0));
|
|
|
|
JButton cancelButton = new JButton(getCancelSelectionAction());
|
|
cancelButton.setText(cancelButtonText);
|
|
cancelButton.setToolTipText(cancelButtonToolTipText);
|
|
cancelButton.setMnemonic(cancelButtonMnemonic);
|
|
buttonPanel.add(cancelButton);
|
|
bottomPanel.add(buttonPanel, BorderLayout.SOUTH);
|
|
bottomPanel.setBorder(BorderFactory.createEmptyBorder(0, 8, 8, 8));
|
|
fc.add(bottomPanel, BorderLayout.SOUTH);
|
|
|
|
fc.add(getAccessoryPanel(), BorderLayout.EAST);
|
|
}
|
|
|
|
/**
|
|
* Uninstalls the components added by
|
|
* {@link #installComponents(JFileChooser)}.
|
|
*
|
|
* @param fc the file chooser.
|
|
*/
|
|
public void uninstallComponents(JFileChooser fc)
|
|
{
|
|
fc.remove(bottomPanel);
|
|
bottomPanel = null;
|
|
fc.remove(fileListPanel);
|
|
fc.remove(fileTablePanel);
|
|
fileTablePanel = null;
|
|
fileListPanel = null;
|
|
fc.remove(topPanel);
|
|
topPanel = null;
|
|
|
|
directoryModel = null;
|
|
fileTextField = null;
|
|
directoryComboBox = null;
|
|
}
|
|
|
|
/**
|
|
* Returns the panel that contains the 'Open' (or 'Save') and 'Cancel'
|
|
* buttons.
|
|
*
|
|
* @return The panel.
|
|
*/
|
|
protected JPanel getButtonPanel()
|
|
{
|
|
return buttonPanel;
|
|
}
|
|
|
|
/**
|
|
* Creates and returns a new panel that will be used for the controls at
|
|
* the bottom of the file chooser.
|
|
*
|
|
* @return A new panel.
|
|
*/
|
|
protected JPanel getBottomPanel()
|
|
{
|
|
if (bottomPanel == null)
|
|
bottomPanel = new JPanel(new GridLayout(3, 2));
|
|
return bottomPanel;
|
|
}
|
|
|
|
/**
|
|
* Fetches localised strings for use by the labels and buttons on the
|
|
* file chooser.
|
|
*
|
|
* @param fc the file chooser.
|
|
*/
|
|
protected void installStrings(JFileChooser fc)
|
|
{
|
|
super.installStrings(fc);
|
|
look = "Look In: ";
|
|
save = "Save In: ";
|
|
if (fc.getDialogType() == JFileChooser.SAVE_DIALOG)
|
|
directoryLabel = save;
|
|
else
|
|
directoryLabel = look;
|
|
|
|
fileLabel = "File Name: ";
|
|
filterLabel = "Files of Type: ";
|
|
|
|
this.cancelButtonMnemonic = 0;
|
|
this.cancelButtonText = "Cancel";
|
|
this.cancelButtonToolTipText = "Abort file chooser dialog";
|
|
|
|
this.directoryOpenButtonMnemonic = 0;
|
|
this.directoryOpenButtonText = "Open";
|
|
this.directoryOpenButtonToolTipText = "Open selected directory";
|
|
|
|
this.helpButtonMnemonic = 0;
|
|
this.helpButtonText = "Help";
|
|
this.helpButtonToolTipText = "Filechooser help";
|
|
|
|
this.openButtonMnemonic = 0;
|
|
this.openButtonText = "Open";
|
|
this.openButtonToolTipText = "Open selected file";
|
|
|
|
this.saveButtonMnemonic = 0;
|
|
this.saveButtonText = "Save";
|
|
this.saveButtonToolTipText = "Save selected file";
|
|
|
|
this.updateButtonMnemonic = 0;
|
|
this.updateButtonText = "Update";
|
|
this.updateButtonToolTipText = "Update directory listing";
|
|
}
|
|
|
|
/**
|
|
* Installs the listeners required.
|
|
*
|
|
* @param fc the file chooser.
|
|
*/
|
|
protected void installListeners(JFileChooser fc)
|
|
{
|
|
directoryComboBox.setAction(new DirectoryComboBoxAction());
|
|
fc.addPropertyChangeListener(filterModel);
|
|
listSelList = createListSelectionListener(fc);
|
|
doubleClickList = this.createDoubleClickListener(fc, fileList);
|
|
singleClickList = new SingleClickListener(fileList);
|
|
fileList.addListSelectionListener(listSelList);
|
|
fileList.addMouseListener(doubleClickList);
|
|
fileList.addMouseListener(singleClickList);
|
|
super.installListeners(fc);
|
|
}
|
|
|
|
protected void uninstallListeners(JFileChooser fc)
|
|
{
|
|
super.uninstallListeners(fc);
|
|
fc.removePropertyChangeListener(filterModel);
|
|
directoryComboBox.setAction(null);
|
|
fileList.removeListSelectionListener(listSelList);
|
|
fileList.removeMouseListener(doubleClickList);
|
|
fileList.removeMouseListener(singleClickList);
|
|
|
|
if (fileTable != null)
|
|
fileTable.removeMouseListener(tableClickList);
|
|
}
|
|
|
|
protected ActionMap getActionMap()
|
|
{
|
|
if (actionMap == null)
|
|
actionMap = createActionMap();
|
|
return actionMap;
|
|
}
|
|
|
|
/**
|
|
* Creates and returns an action map.
|
|
*
|
|
* @return The action map.
|
|
*/
|
|
protected ActionMap createActionMap()
|
|
{
|
|
ActionMap map = new ActionMap();
|
|
map.put("approveSelection", getApproveSelectionAction());
|
|
map.put("cancelSelection", getCancelSelectionAction());
|
|
map.put("Go Up", getChangeToParentDirectoryAction());
|
|
return map;
|
|
}
|
|
|
|
/**
|
|
* Creates a panel containing a list of files.
|
|
*
|
|
* @param fc the file chooser.
|
|
*
|
|
* @return A panel.
|
|
*/
|
|
protected JPanel createList(JFileChooser fc)
|
|
{
|
|
if (fileList == null)
|
|
{
|
|
fileListPanel = new JPanel(new BorderLayout());
|
|
fileList = new JList(getModel());
|
|
scrollPane = new JScrollPane(fileList);
|
|
fileList.setLayoutOrientation(JList.VERTICAL_WRAP);
|
|
fileList.setCellRenderer(new FileRenderer());
|
|
}
|
|
else
|
|
{
|
|
fileList.setModel(getModel());
|
|
fileListPanel.removeAll();
|
|
scrollPane.getViewport().setView(fileList);
|
|
}
|
|
fileListPanel.add(scrollPane);
|
|
// This size was determined using BeanShell and dumping the JFileChooser
|
|
// component hierarchy. Sun has an internal FilePane class in there, but
|
|
// that probably doesn't matter atm.
|
|
fileListPanel.setPreferredSize(new Dimension(405, 135));
|
|
return fileListPanel;
|
|
}
|
|
|
|
/**
|
|
* Creates a panel containing a table within a scroll pane.
|
|
*
|
|
* @param fc the file chooser.
|
|
*
|
|
* @return The details view.
|
|
*/
|
|
protected JPanel createDetailsView(JFileChooser fc)
|
|
{
|
|
fileTablePanel = new JPanel(new BorderLayout());
|
|
|
|
Object[] cols = new Object[] {"Name", "Size", "Modified"};
|
|
Object[][] rows = new Object[fileList.getModel().getSize()][3];
|
|
|
|
fileTable = new JTable(new DefaultTableModel(rows, cols));
|
|
|
|
if (fc.isMultiSelectionEnabled())
|
|
fileTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
|
else
|
|
fileTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
|
|
|
fileTable.setShowGrid(false);
|
|
fileTable.setColumnSelectionAllowed(false);
|
|
fileTable.setDefaultRenderer(Object.class, new TableFileRenderer());
|
|
|
|
tableClickList = new TableClickListener(fileTable, fc);
|
|
fileTable.addMouseListener(tableClickList);
|
|
|
|
return updateTable();
|
|
}
|
|
|
|
/**
|
|
* Sets the values in the table, and puts it in the panel.
|
|
*
|
|
* @return the panel containing the table.
|
|
*/
|
|
JPanel updateTable()
|
|
{
|
|
DefaultTableModel mod = (DefaultTableModel) fileTable.getModel();
|
|
ListModel lm = fileList.getModel();
|
|
DateFormat dt = DateFormat.getDateTimeInstance(DateFormat.SHORT,
|
|
DateFormat.SHORT);
|
|
File curr = null;
|
|
int size = lm.getSize();
|
|
int rc = mod.getRowCount();
|
|
|
|
// If there are not enough rows
|
|
for (int x = rc; x < size; x++)
|
|
mod.addRow(new Object[3]);
|
|
|
|
for (int i = 0; i < size; i++)
|
|
{
|
|
curr = (File) lm.getElementAt(i);
|
|
fileTable.setValueAt(curr.getName(), i, 0);
|
|
fileTable.setValueAt(formatSize(curr.length()), i, 1);
|
|
fileTable.setValueAt(dt.format(new Date(curr.lastModified())), i, 2);
|
|
}
|
|
|
|
// If there are too many rows
|
|
while (rc > size)
|
|
mod.removeRow(--rc);
|
|
|
|
scrollPane.getViewport().setView(fileTable);
|
|
scrollPane.setColumnHeaderView(fileTable.getTableHeader());
|
|
|
|
fileTablePanel.removeAll();
|
|
fileTablePanel.add(scrollPane);
|
|
|
|
return fileTablePanel;
|
|
}
|
|
|
|
/**
|
|
* Formats bytes into the appropriate size.
|
|
*
|
|
* @param bytes the number of bytes to convert
|
|
* @return a string representation of the size
|
|
*/
|
|
private String formatSize(long bytes)
|
|
{
|
|
NumberFormat nf = NumberFormat.getNumberInstance();
|
|
long mb = (long) Math.pow(2, 20);
|
|
long kb = (long) Math.pow(2, 10);
|
|
long gb = (long) Math.pow(2, 30);
|
|
double size = 0;
|
|
String id = "";
|
|
|
|
if ((bytes / gb) >= 1)
|
|
{
|
|
size = (double) bytes / (double) gb;
|
|
id = "GB";
|
|
}
|
|
else if ((bytes / mb) >= 1)
|
|
{
|
|
size = (double) bytes / (double) mb;
|
|
id = "MB";
|
|
}
|
|
else if ((bytes / kb) >= 1)
|
|
{
|
|
size = (double) bytes / (double) kb;
|
|
id = "KB";
|
|
}
|
|
else
|
|
{
|
|
size = bytes;
|
|
id = "Bytes";
|
|
}
|
|
|
|
return nf.format(size) + " " + id;
|
|
}
|
|
/**
|
|
* Creates a listener that monitors selections in the directory/file list
|
|
* and keeps the {@link JFileChooser} component up to date.
|
|
*
|
|
* @param fc the file chooser.
|
|
*
|
|
* @return The listener.
|
|
*
|
|
* @see #installListeners(JFileChooser)
|
|
*/
|
|
public ListSelectionListener createListSelectionListener(JFileChooser fc)
|
|
{
|
|
return new MetalFileChooserSelectionListener();
|
|
}
|
|
|
|
/**
|
|
* Returns the preferred size for the file chooser component.
|
|
*
|
|
* @return The preferred size.
|
|
*/
|
|
public Dimension getPreferredSize(JComponent c)
|
|
{
|
|
Dimension tp = topPanel.getPreferredSize();
|
|
Dimension bp = bottomPanel.getPreferredSize();
|
|
Dimension fl = fileListPanel.getPreferredSize();
|
|
return new Dimension(fl.width, tp.height + bp.height + fl.height);
|
|
}
|
|
|
|
/**
|
|
* Returns the minimum size for the file chooser component.
|
|
*
|
|
* @return The minimum size.
|
|
*/
|
|
public Dimension getMinimumSize(JComponent c)
|
|
{
|
|
Dimension tp = topPanel.getMinimumSize();
|
|
Dimension bp = bottomPanel.getMinimumSize();
|
|
Dimension fl = fileListPanel.getMinimumSize();
|
|
return new Dimension(fl.width, tp.height + bp.height + fl.height);
|
|
}
|
|
|
|
/**
|
|
* Returns the maximum size for the file chooser component.
|
|
*
|
|
* @return The maximum size.
|
|
*/
|
|
public Dimension getMaximumSize(JComponent c)
|
|
{
|
|
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
|
|
}
|
|
|
|
/**
|
|
* Creates a property change listener that monitors the {@link JFileChooser}
|
|
* for property change events and updates the component display accordingly.
|
|
*
|
|
* @param fc the file chooser.
|
|
*
|
|
* @return The property change listener.
|
|
*
|
|
* @see #installListeners(JFileChooser)
|
|
*/
|
|
public PropertyChangeListener createPropertyChangeListener(JFileChooser fc)
|
|
{
|
|
return new MetalFileChooserPropertyChangeListener();
|
|
}
|
|
|
|
/**
|
|
* Creates and returns a new instance of {@link DirectoryComboBoxModel}.
|
|
*
|
|
* @return A new instance of {@link DirectoryComboBoxModel}.
|
|
*/
|
|
protected MetalFileChooserUI.DirectoryComboBoxModel
|
|
createDirectoryComboBoxModel(JFileChooser fc)
|
|
{
|
|
return new DirectoryComboBoxModel();
|
|
}
|
|
|
|
/**
|
|
* Creates a new instance of the renderer used in the directory
|
|
* combo box.
|
|
*
|
|
* @param fc the file chooser.
|
|
*
|
|
* @return The renderer.
|
|
*/
|
|
protected DirectoryComboBoxRenderer createDirectoryComboBoxRenderer(
|
|
JFileChooser fc)
|
|
{
|
|
return new DirectoryComboBoxRenderer(fc);
|
|
}
|
|
|
|
/**
|
|
* Creates and returns a new instance of {@link FilterComboBoxModel}.
|
|
*
|
|
* @return A new instance of {@link FilterComboBoxModel}.
|
|
*/
|
|
protected FilterComboBoxModel createFilterComboBoxModel()
|
|
{
|
|
return new FilterComboBoxModel();
|
|
}
|
|
|
|
/**
|
|
* Creates and returns a new instance of {@link FilterComboBoxRenderer}.
|
|
*
|
|
* @return A new instance of {@link FilterComboBoxRenderer}.
|
|
*/
|
|
protected MetalFileChooserUI.FilterComboBoxRenderer
|
|
createFilterComboBoxRenderer()
|
|
{
|
|
return new FilterComboBoxRenderer();
|
|
}
|
|
|
|
/**
|
|
* Adds the control buttons ('up', 'home' etc.) to the panel.
|
|
*/
|
|
protected void addControlButtons()
|
|
{
|
|
JButton upButton = new JButton(getChangeToParentDirectoryAction());
|
|
upButton.setText(null);
|
|
upButton.setIcon(this.upFolderIcon);
|
|
upButton.setMargin(new Insets(0, 0, 0, 0));
|
|
controls.add(upButton);
|
|
|
|
JButton homeButton = new JButton(getGoHomeAction());
|
|
homeButton.setText(null);
|
|
homeButton.setIcon(this.homeFolderIcon);
|
|
homeButton.setMargin(new Insets(0, 0, 0, 0));
|
|
controls.add(homeButton);
|
|
|
|
JButton newFolderButton = new JButton(getNewFolderAction());
|
|
newFolderButton.setText(null);
|
|
newFolderButton.setIcon(this.newFolderIcon);
|
|
newFolderButton.setMargin(new Insets(0, 0, 0, 0));
|
|
controls.add(newFolderButton);
|
|
|
|
JToggleButton listButton = new JToggleButton(this.listViewIcon);
|
|
listButton.setMargin(new Insets(0, 0, 0, 0));
|
|
listButton.addActionListener(new ListViewActionListener());
|
|
listButton.setSelected(true);
|
|
listView = true;
|
|
controls.add(listButton);
|
|
|
|
JToggleButton detailButton = new JToggleButton(this.detailsViewIcon);
|
|
detailButton.setMargin(new Insets(0, 0, 0, 0));
|
|
detailButton.addActionListener(new DetailViewActionListener());
|
|
detailButton.setSelected(false);
|
|
controls.add(detailButton);
|
|
|
|
ButtonGroup buttonGroup = new ButtonGroup();
|
|
buttonGroup.add(listButton);
|
|
buttonGroup.add(detailButton);
|
|
}
|
|
|
|
/**
|
|
* Removes all the buttons from the control panel.
|
|
*/
|
|
protected void removeControlButtons()
|
|
{
|
|
controls.removeAll();
|
|
controls.revalidate();
|
|
controls.repaint();
|
|
}
|
|
|
|
/**
|
|
* Updates the current directory.
|
|
*
|
|
* @param fc the file chooser to update.
|
|
*/
|
|
public void rescanCurrentDirectory(JFileChooser fc)
|
|
{
|
|
directoryModel.setSelectedItem(fc.getCurrentDirectory());
|
|
getModel().validateFileCache();
|
|
if (!listView)
|
|
updateTable();
|
|
else
|
|
createList(fc);
|
|
}
|
|
|
|
/**
|
|
* Returns the file name in the text field.
|
|
*
|
|
* @return The file name.
|
|
*/
|
|
public String getFileName()
|
|
{
|
|
String result = null;
|
|
if (fileTextField != null)
|
|
result = fileTextField.getText();
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Sets the file name in the text field.
|
|
*
|
|
* @param filename the file name.
|
|
*/
|
|
public void setFileName(String filename)
|
|
{
|
|
fileTextField.setText(filename);
|
|
}
|
|
|
|
/**
|
|
* DOCUMENT ME!!
|
|
*
|
|
* @param e - DOCUMENT ME!
|
|
*/
|
|
public void valueChanged(ListSelectionEvent e)
|
|
{
|
|
// FIXME: Not sure what we should be doing here, if anything.
|
|
}
|
|
|
|
/**
|
|
* Returns the approve button.
|
|
*
|
|
* @return The approve button.
|
|
*/
|
|
protected JButton getApproveButton(JFileChooser fc)
|
|
{
|
|
return approveButton;
|
|
}
|
|
|
|
/**
|
|
* A layout manager that is used to arrange the subcomponents of the
|
|
* {@link JFileChooser}.
|
|
*/
|
|
class VerticalMidLayout implements LayoutManager
|
|
{
|
|
/**
|
|
* Performs the layout.
|
|
*
|
|
* @param parent the container.
|
|
*/
|
|
public void layoutContainer(Container parent)
|
|
{
|
|
int count = parent.getComponentCount();
|
|
if (count > 0)
|
|
{
|
|
Insets insets = parent.getInsets();
|
|
Component c = parent.getComponent(0);
|
|
Dimension prefSize = c.getPreferredSize();
|
|
int h = parent.getHeight() - insets.top - insets.bottom;
|
|
int adj = Math.max(0, (h - prefSize.height) / 2);
|
|
c.setBounds(insets.left, insets.top + adj, parent.getWidth()
|
|
- insets.left - insets.right,
|
|
(int) Math.min(prefSize.getHeight(), h));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the minimum layout size.
|
|
*
|
|
* @param parent the container.
|
|
*
|
|
* @return The minimum layout size.
|
|
*/
|
|
public Dimension minimumLayoutSize(Container parent)
|
|
{
|
|
return preferredLayoutSize(parent);
|
|
}
|
|
|
|
/**
|
|
* Returns the preferred layout size.
|
|
*
|
|
* @param parent the container.
|
|
*
|
|
* @return The preferred layout size.
|
|
*/
|
|
public Dimension preferredLayoutSize(Container parent)
|
|
{
|
|
if (parent.getComponentCount() > 0)
|
|
{
|
|
return parent.getComponent(0).getPreferredSize();
|
|
}
|
|
else return null;
|
|
}
|
|
|
|
/**
|
|
* This layout manager does not need to track components, so this
|
|
* method does nothing.
|
|
*
|
|
* @param name the name the component is associated with.
|
|
* @param component the component.
|
|
*/
|
|
public void addLayoutComponent(String name, Component component)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
/**
|
|
* This layout manager does not need to track components, so this
|
|
* method does nothing.
|
|
*
|
|
* @param component the component.
|
|
*/
|
|
public void removeLayoutComponent(Component component)
|
|
{
|
|
// do nothing
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A layout manager that is used to arrange buttons for the
|
|
* {@link JFileChooser}.
|
|
*/
|
|
class ButtonLayout implements LayoutManager
|
|
{
|
|
static final int GAP = 4;
|
|
|
|
/**
|
|
* Performs the layout.
|
|
*
|
|
* @param parent the container.
|
|
*/
|
|
public void layoutContainer(Container parent)
|
|
{
|
|
int count = parent.getComponentCount();
|
|
if (count > 0)
|
|
{
|
|
// first find the widest button
|
|
int maxW = 0;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
Component c = parent.getComponent(i);
|
|
Dimension prefSize = c.getPreferredSize();
|
|
maxW = Math.max(prefSize.width, maxW);
|
|
}
|
|
|
|
// then position the buttons
|
|
Insets insets = parent.getInsets();
|
|
int availableH = parent.getHeight() - insets.top - insets.bottom;
|
|
int currentX = parent.getWidth() - insets.right;
|
|
for (int i = count - 1; i >= 0; i--)
|
|
{
|
|
Component c = parent.getComponent(i);
|
|
Dimension prefSize = c.getPreferredSize();
|
|
int adj = Math.max(0, (availableH - prefSize.height) / 2);
|
|
currentX = currentX - prefSize.width;
|
|
c.setBounds(currentX, insets.top + adj, prefSize.width,
|
|
(int) Math.min(prefSize.getHeight(), availableH));
|
|
currentX = currentX - GAP;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the minimum layout size.
|
|
*
|
|
* @param parent the container.
|
|
*
|
|
* @return The minimum layout size.
|
|
*/
|
|
public Dimension minimumLayoutSize(Container parent)
|
|
{
|
|
return preferredLayoutSize(parent);
|
|
}
|
|
|
|
/**
|
|
* Returns the preferred layout size.
|
|
*
|
|
* @param parent the container.
|
|
*
|
|
* @return The preferred layout size.
|
|
*/
|
|
public Dimension preferredLayoutSize(Container parent)
|
|
{
|
|
Insets insets = parent.getInsets();
|
|
int maxW = 0;
|
|
int maxH = 0;
|
|
int count = parent.getComponentCount();
|
|
if (count > 0)
|
|
{
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
Component c = parent.getComponent(i);
|
|
Dimension d = c.getPreferredSize();
|
|
maxW = Math.max(d.width, maxW);
|
|
maxH = Math.max(d.height, maxH);
|
|
}
|
|
}
|
|
return new Dimension(maxW * count + GAP * (count - 1) + insets.left
|
|
+ insets.right, maxH + insets.top + insets.bottom);
|
|
}
|
|
|
|
/**
|
|
* This layout manager does not need to track components, so this
|
|
* method does nothing.
|
|
*
|
|
* @param name the name the component is associated with.
|
|
* @param component the component.
|
|
*/
|
|
public void addLayoutComponent(String name, Component component)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
/**
|
|
* This layout manager does not need to track components, so this
|
|
* method does nothing.
|
|
*
|
|
* @param component the component.
|
|
*/
|
|
public void removeLayoutComponent(Component component)
|
|
{
|
|
// do nothing
|
|
}
|
|
}
|
|
|
|
}
|