/* * ListView.java * * Created on April 24, 2002, 10:05 AM */ package kiyut.swing.shell.shelllistview; import java.applet.Applet; import java.awt.*; import java.awt.event.*; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; import java.io.File; import java.io.IOException; import java.util.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.filechooser.FileSystemView; import kiyut.swing.shell.event.*; import kiyut.swing.shell.util.*; /** <code>ListView</code> is a view for <code>ShellListView</code> which display * the <code>ShellListViewModel</code> in a list like view. * * @author tonny */ public class ListView extends JList implements ViewComponent { /** editor remover */ private PropertyChangeListener editorRemover = null; /** the component use for editing cells */ private Component editorComp; /** the editor for the cells */ protected ListCellEditor cellEditor; /** Identifies the index of the cell being edited. */ protected int editingIndex = -1; /** Constructs a <code>ListView</code> using the given data model * @param dataModel data model for this component */ public ListView(ShellListViewModel dataModel) { super(dataModel); ListCellRenderer cellRenderer = new ListCellRenderer(dataModel.getFileSystemView()); cellEditor = new ListCellEditor(); cellEditor.addCellEditorListener(new javax.swing.event.CellEditorListener() { public void editingCanceled(ChangeEvent evt) { ListView.this.editingCanceled(evt); } public void editingStopped(ChangeEvent evt) { ListView.this.editingStopped(evt); } }); addListSelectionListener(new javax.swing.event.ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { onListSelectionChanged(e); } }); addComponentListener(new java.awt.event.ComponentAdapter() { public void componentResized(ComponentEvent evt) { onComponentResized(evt); } }); setFont(UIManager.getFont("Table.font")); setLayoutOrientation(JList.VERTICAL_WRAP); setCellRenderer(cellRenderer); } /** {@inheritDoc} */ public ShellListViewModel getViewModel() { return (ShellListViewModel)getModel(); } /** set editing index *@param index the editing index */ private void setEditingIndex(int index) { editingIndex = index; } /** Returns the index of the model that contains the cell currently being edited. * If nothing is being edited, returns -1. * @return index or -1 */ public int getEditingIndex() { return editingIndex; } /** Returns the <code>ListCellEditor</code> used by this component to edit values for the cells. * @return <code>ListCellEditor</code> used to edit values for the cells */ public ListCellEditor getCellEditor() { return cellEditor; } /** Discards the editor object and frees the real estate it used for * cell rendering. */ private void removeEditor() { KeyboardFocusManager.getCurrentKeyboardFocusManager(). removePropertyChangeListener("permanentFocusOwner", editorRemover); editorRemover = null; ListCellEditor editor = getCellEditor(); if(editor != null) { //editor.removeCellEditorListener(this); if (editorComp != null) { remove(editorComp); } int index = getEditingIndex(); Rectangle cellRect = getCellBounds(index,index); setEditingIndex(-1); editorComp = null; if (cellRect != null) { repaint(cellRect); } } } /** Returns true if a cell is being edited. * @return true if editing a cell */ public boolean isEditing() { boolean b = false; ShellListViewModel dataModel = (ShellListViewModel)getModel(); if (dataModel.getState() == ShellListViewModel.EDIT) { b = true; } return b; } /** start editing cell programatically * @param index the index of data model to be edited * @return true if editing is started; false otherwise * @throws IndexOutOfBoundsException if an invalid index was given */ public boolean editCellAt(int index) { boolean b = false; if (editorRemover == null) { KeyboardFocusManager fm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); editorRemover = new CellEditorRemover(fm); fm.addPropertyChangeListener("permanentFocusOwner", editorRemover); } ShellListViewModel dataModel = (ShellListViewModel)getModel(); if ( (index < 0) || (index >= dataModel.getRowCount()) ) { throw new IndexOutOfBoundsException("invalid index"); } ListSelectionModel selectionModel = getSelectionModel(); selectionModel.clearSelection(); selectionModel.setSelectionInterval(index,index); setEditingIndex(index); Object value = dataModel.getFile(index); editorComp = cellEditor.getListCellEditorComponent(this, value, true, index); editorComp.setBounds(getCellBounds(index,index)); add(editorComp); editorComp.validate(); editorComp.repaint(); editorComp.requestFocusInWindow(); b = true; return b; } /** Invoked when editing is canceled. * @param evt the event received * @see DetailView#editingCanceled(ChangeEvent) */ public void editingCanceled(ChangeEvent evt) { ShellListViewModel dataModel = (ShellListViewModel)getModel(); dataModel.setState(ShellListViewModel.BROWSE); removeEditor(); } /** Invoked when editing is stopped. * @param evt the event received * @see DetailView#editingStopped(ChangeEvent) */ public void editingStopped(ChangeEvent evt) { ShellListViewModel dataModel = (ShellListViewModel)getModel(); dataModel.setState(ShellListViewModel.BROWSE); removeEditor(); } ////////////////////////// // event handling ///////////////////////// /** Invoked when the component's size changes. * @param e a <code>ComponentEvent</code> object */ private void onComponentResized(ComponentEvent evt) { if (getModel().getSize() <= 0) { return; } int rowCount = 8; // 8 as default Rectangle rect = getCellBounds(0,0); Rectangle size = getVisibleRect(); double d = size.getHeight()/rect.getHeight(); if (d > rowCount) { rowCount = (int)d; rowCount = rowCount - 1; } setVisibleRowCount(rowCount); } /** Called whenever the value of the selection changes. * @param e the event that characterizes the change. */ private void onListSelectionChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()) { return; } getCellEditor().cancelCellEditing(); } // This class tracks changes in the keyboard focus state. It is used // when the ListView is editing to determine when to cancel the edit. // If focus switches to a component outside of the ListView, but in the // same window, this will cancel editing. public class CellEditorRemover implements PropertyChangeListener { KeyboardFocusManager focusManager; public CellEditorRemover(KeyboardFocusManager fm) { this.focusManager = fm; } /** {@inheritDoc} */ public void propertyChange(PropertyChangeEvent evt) { if (!isEditing() || getClientProperty("terminateEditOnFocusLost") != Boolean.TRUE) { return; } Component c = focusManager.getPermanentFocusOwner(); while (c != null) { if (c == ListView.this) { // focus remains inside the list return; } else if ((c instanceof Window) || (c instanceof Applet && c.getParent() == null)) { if (c == SwingUtilities.getRoot(ListView.this)) { if (!getCellEditor().stopCellEditing()) { getCellEditor().cancelCellEditing(); } } break; } c = c.getParent(); } } } }