summaryrefslogtreecommitdiff
path: root/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java')
-rw-r--r--libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java2120
1 files changed, 2120 insertions, 0 deletions
diff --git a/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java b/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java
new file mode 100644
index 000000000..df49edf61
--- /dev/null
+++ b/libjava/classpath/javax/swing/plaf/metal/MetalFileChooserUI.java
@@ -0,0 +1,2120 @@
+/* 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
+ }
+ }
+
+}