mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			1411 lines
		
	
	
		
			50 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			1411 lines
		
	
	
		
			50 KiB
		
	
	
	
		
			Java
		
	
	
	
/* BasicTableUI.java --
 | 
						|
   Copyright (C) 2004 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.basic;
 | 
						|
 | 
						|
import java.awt.Color;
 | 
						|
import java.awt.Component;
 | 
						|
import java.awt.ComponentOrientation;
 | 
						|
import java.awt.Dimension;
 | 
						|
import java.awt.Graphics;
 | 
						|
import java.awt.Point;
 | 
						|
import java.awt.Rectangle;
 | 
						|
import java.awt.event.ActionEvent;
 | 
						|
import java.awt.event.FocusEvent;
 | 
						|
import java.awt.event.FocusListener;
 | 
						|
import java.awt.event.KeyEvent;
 | 
						|
import java.awt.event.KeyListener;
 | 
						|
import java.awt.event.MouseEvent;
 | 
						|
import java.beans.PropertyChangeEvent;
 | 
						|
import java.beans.PropertyChangeListener;
 | 
						|
 | 
						|
import javax.swing.AbstractAction;
 | 
						|
import javax.swing.Action;
 | 
						|
import javax.swing.ActionMap;
 | 
						|
import javax.swing.CellRendererPane;
 | 
						|
import javax.swing.DefaultCellEditor;
 | 
						|
import javax.swing.DefaultListSelectionModel;
 | 
						|
import javax.swing.InputMap;
 | 
						|
import javax.swing.JComponent;
 | 
						|
import javax.swing.JTable;
 | 
						|
import javax.swing.ListSelectionModel;
 | 
						|
import javax.swing.LookAndFeel;
 | 
						|
import javax.swing.SwingUtilities;
 | 
						|
import javax.swing.TransferHandler;
 | 
						|
import javax.swing.UIManager;
 | 
						|
import javax.swing.border.Border;
 | 
						|
import javax.swing.event.ChangeEvent;
 | 
						|
import javax.swing.event.MouseInputListener;
 | 
						|
import javax.swing.plaf.ActionMapUIResource;
 | 
						|
import javax.swing.plaf.ComponentUI;
 | 
						|
import javax.swing.plaf.TableUI;
 | 
						|
import javax.swing.table.TableCellEditor;
 | 
						|
import javax.swing.table.TableCellRenderer;
 | 
						|
import javax.swing.table.TableColumn;
 | 
						|
import javax.swing.table.TableColumnModel;
 | 
						|
import javax.swing.table.TableModel;
 | 
						|
 | 
						|
public class BasicTableUI extends TableUI
 | 
						|
{
 | 
						|
  public static ComponentUI createUI(JComponent comp)
 | 
						|
  {
 | 
						|
    return new BasicTableUI();
 | 
						|
  }
 | 
						|
 | 
						|
  protected FocusListener focusListener;
 | 
						|
  protected KeyListener keyListener;
 | 
						|
  protected MouseInputListener  mouseInputListener;
 | 
						|
  protected CellRendererPane rendererPane;
 | 
						|
  protected JTable table;
 | 
						|
 | 
						|
  /** The normal cell border. */
 | 
						|
  Border cellBorder;
 | 
						|
 | 
						|
  /** The action bound to KeyStrokes. */
 | 
						|
  TableAction action;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Listens for changes to the tables properties.
 | 
						|
   */
 | 
						|
  private PropertyChangeListener propertyChangeListener;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Handles key events for the JTable. Key events should be handled through
 | 
						|
   * the InputMap/ActionMap mechanism since JDK1.3. This class is only there
 | 
						|
   * for backwards compatibility.
 | 
						|
   *
 | 
						|
   * @author Roman Kennke (kennke@aicas.com)
 | 
						|
   */
 | 
						|
  public class KeyHandler implements KeyListener
 | 
						|
  {
 | 
						|
 | 
						|
    /**
 | 
						|
     * Receives notification that a key has been pressed and released.
 | 
						|
     * Activates the editing session for the focused cell by pressing the
 | 
						|
     * character keys.
 | 
						|
     *
 | 
						|
     * @param event the key event
 | 
						|
     */
 | 
						|
    public void keyTyped(KeyEvent event)
 | 
						|
    {
 | 
						|
      // Key events should be handled through the InputMap/ActionMap mechanism
 | 
						|
      // since JDK1.3. This class is only there for backwards compatibility.
 | 
						|
 | 
						|
      // Editor activation is a specific kind of response to ''any''
 | 
						|
      // character key. Hence it is handled here.
 | 
						|
      if (!table.isEditing() && table.isEnabled())
 | 
						|
        {
 | 
						|
          int r = table.getSelectedRow();
 | 
						|
          int c = table.getSelectedColumn();
 | 
						|
          if (table.isCellEditable(r, c))
 | 
						|
            table.editCellAt(r, c);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Receives notification that a key has been pressed.
 | 
						|
     *
 | 
						|
     * @param event the key event
 | 
						|
     */
 | 
						|
    public void keyPressed(KeyEvent event)
 | 
						|
    {
 | 
						|
      // Key events should be handled through the InputMap/ActionMap mechanism
 | 
						|
      // since JDK1.3. This class is only there for backwards compatibility.
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Receives notification that a key has been released.
 | 
						|
     *
 | 
						|
     * @param event the key event
 | 
						|
     */
 | 
						|
    public void keyReleased(KeyEvent event)
 | 
						|
    {
 | 
						|
      // Key events should be handled through the InputMap/ActionMap mechanism
 | 
						|
      // since JDK1.3. This class is only there for backwards compatibility.
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  public class FocusHandler implements FocusListener
 | 
						|
  {
 | 
						|
    public void focusGained(FocusEvent e)
 | 
						|
    {
 | 
						|
      // The only thing that is affected by a focus change seems to be
 | 
						|
      // how the lead cell is painted. So we repaint this cell.
 | 
						|
      repaintLeadCell();
 | 
						|
    }
 | 
						|
 | 
						|
    public void focusLost(FocusEvent e)
 | 
						|
    {
 | 
						|
      // The only thing that is affected by a focus change seems to be
 | 
						|
      // how the lead cell is painted. So we repaint this cell.
 | 
						|
      repaintLeadCell();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Repaints the lead cell in response to a focus change, to refresh
 | 
						|
     * the display of the focus indicator.
 | 
						|
     */
 | 
						|
    private void repaintLeadCell()
 | 
						|
    {
 | 
						|
      int rowCount = table.getRowCount();
 | 
						|
      int columnCount = table.getColumnCount();
 | 
						|
      int rowLead = table.getSelectionModel().getLeadSelectionIndex();
 | 
						|
      int columnLead = table.getColumnModel().getSelectionModel().
 | 
						|
                                                       getLeadSelectionIndex();
 | 
						|
      if (rowLead >= 0 && rowLead < rowCount && columnLead >= 0
 | 
						|
          && columnLead < columnCount)
 | 
						|
        {
 | 
						|
          Rectangle dirtyRect = table.getCellRect(rowLead, columnLead, false);
 | 
						|
          table.repaint(dirtyRect);
 | 
						|
        }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  public class MouseInputHandler implements MouseInputListener
 | 
						|
  {
 | 
						|
    Point begin, curr;
 | 
						|
 | 
						|
    private void updateSelection(boolean controlPressed)
 | 
						|
    {
 | 
						|
      // Update the rows
 | 
						|
      int lo_row = table.rowAtPoint(begin);
 | 
						|
      int hi_row  = table.rowAtPoint(curr);
 | 
						|
      ListSelectionModel rowModel = table.getSelectionModel();
 | 
						|
      if (lo_row != -1 && hi_row != -1)
 | 
						|
        {
 | 
						|
          if (controlPressed && rowModel.getSelectionMode()
 | 
						|
              != ListSelectionModel.SINGLE_SELECTION)
 | 
						|
            rowModel.addSelectionInterval(lo_row, hi_row);
 | 
						|
          else
 | 
						|
            rowModel.setSelectionInterval(lo_row, hi_row);
 | 
						|
        }
 | 
						|
 | 
						|
      // Update the columns
 | 
						|
      int lo_col = table.columnAtPoint(begin);
 | 
						|
      int hi_col = table.columnAtPoint(curr);
 | 
						|
      ListSelectionModel colModel = table.getColumnModel().
 | 
						|
        getSelectionModel();
 | 
						|
      if (lo_col != -1 && hi_col != -1)
 | 
						|
        {
 | 
						|
          if (controlPressed && colModel.getSelectionMode() !=
 | 
						|
              ListSelectionModel.SINGLE_SELECTION)
 | 
						|
            colModel.addSelectionInterval(lo_col, hi_col);
 | 
						|
          else
 | 
						|
            colModel.setSelectionInterval(lo_col, hi_col);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * For the double click, start the cell editor.
 | 
						|
     */
 | 
						|
    public void mouseClicked(MouseEvent e)
 | 
						|
    {
 | 
						|
      Point p = e.getPoint();
 | 
						|
      int row = table.rowAtPoint(p);
 | 
						|
      int col = table.columnAtPoint(p);
 | 
						|
      if (table.isCellEditable(row, col))
 | 
						|
        {
 | 
						|
          // If the cell editor is the default editor, we request the
 | 
						|
          // number of the required clicks from it. Otherwise,
 | 
						|
          // require two clicks (double click).
 | 
						|
          TableCellEditor editor = table.getCellEditor(row, col);
 | 
						|
          if (editor instanceof DefaultCellEditor)
 | 
						|
            {
 | 
						|
              DefaultCellEditor ce = (DefaultCellEditor) editor;
 | 
						|
              if (e.getClickCount() < ce.getClickCountToStart())
 | 
						|
                return;
 | 
						|
            }
 | 
						|
          table.editCellAt(row, col);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public void mouseDragged(MouseEvent e)
 | 
						|
    {
 | 
						|
      if (table.isEnabled())
 | 
						|
        {
 | 
						|
          curr = new Point(e.getX(), e.getY());
 | 
						|
          updateSelection(e.isControlDown());
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public void mouseEntered(MouseEvent e)
 | 
						|
    {
 | 
						|
      // Nothing to do here.
 | 
						|
    }
 | 
						|
 | 
						|
    public void mouseExited(MouseEvent e)
 | 
						|
    {
 | 
						|
      // Nothing to do here.
 | 
						|
    }
 | 
						|
 | 
						|
    public void mouseMoved(MouseEvent e)
 | 
						|
    {
 | 
						|
      // Nothing to do here.
 | 
						|
    }
 | 
						|
 | 
						|
    public void mousePressed(MouseEvent e)
 | 
						|
    {
 | 
						|
      if (table.isEnabled())
 | 
						|
        {
 | 
						|
          ListSelectionModel rowModel = table.getSelectionModel();
 | 
						|
          ListSelectionModel colModel = table.getColumnModel().getSelectionModel();
 | 
						|
          int rowLead = rowModel.getLeadSelectionIndex();
 | 
						|
          int colLead = colModel.getLeadSelectionIndex();
 | 
						|
 | 
						|
          begin = new Point(e.getX(), e.getY());
 | 
						|
          curr = new Point(e.getX(), e.getY());
 | 
						|
          //if control is pressed and the cell is already selected, deselect it
 | 
						|
          if (e.isControlDown() && table.isCellSelected(
 | 
						|
              table.rowAtPoint(begin), table.columnAtPoint(begin)))
 | 
						|
            {
 | 
						|
              table.getSelectionModel().
 | 
						|
              removeSelectionInterval(table.rowAtPoint(begin),
 | 
						|
                                      table.rowAtPoint(begin));
 | 
						|
              table.getColumnModel().getSelectionModel().
 | 
						|
              removeSelectionInterval(table.columnAtPoint(begin),
 | 
						|
                                      table.columnAtPoint(begin));
 | 
						|
            }
 | 
						|
          else
 | 
						|
            updateSelection(e.isControlDown());
 | 
						|
 | 
						|
          // If we were editing, but the moved to another cell, stop editing
 | 
						|
          if (rowLead != rowModel.getLeadSelectionIndex() ||
 | 
						|
              colLead != colModel.getLeadSelectionIndex())
 | 
						|
            if (table.isEditing())
 | 
						|
              table.editingStopped(new ChangeEvent(e));
 | 
						|
 | 
						|
          // Must request focus explicitly.
 | 
						|
          table.requestFocusInWindow();
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public void mouseReleased(MouseEvent e)
 | 
						|
    {
 | 
						|
      if (table.isEnabled())
 | 
						|
        {
 | 
						|
          begin = null;
 | 
						|
          curr = null;
 | 
						|
        }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Listens for changes to the model property of the JTable and adjusts some
 | 
						|
   * settings.
 | 
						|
   *
 | 
						|
   * @author Roman Kennke (kennke@aicas.com)
 | 
						|
   */
 | 
						|
  private class PropertyChangeHandler implements PropertyChangeListener
 | 
						|
  {
 | 
						|
    /**
 | 
						|
     * Receives notification if one of the JTable's properties changes.
 | 
						|
     *
 | 
						|
     * @param ev the property change event
 | 
						|
     */
 | 
						|
    public void propertyChange(PropertyChangeEvent ev)
 | 
						|
    {
 | 
						|
      String propName = ev.getPropertyName();
 | 
						|
      if (propName.equals("model"))
 | 
						|
        {
 | 
						|
          ListSelectionModel rowSel = table.getSelectionModel();
 | 
						|
          rowSel.clearSelection();
 | 
						|
          ListSelectionModel colSel = table.getColumnModel().getSelectionModel();
 | 
						|
          colSel.clearSelection();
 | 
						|
          TableModel model = table.getModel();
 | 
						|
 | 
						|
          // Adjust lead and anchor selection indices of the row and column
 | 
						|
          // selection models.
 | 
						|
          if (model.getRowCount() > 0)
 | 
						|
            {
 | 
						|
              rowSel.setAnchorSelectionIndex(0);
 | 
						|
              rowSel.setLeadSelectionIndex(0);
 | 
						|
            }
 | 
						|
          else
 | 
						|
            {
 | 
						|
              rowSel.setAnchorSelectionIndex(-1);
 | 
						|
              rowSel.setLeadSelectionIndex(-1);
 | 
						|
            }
 | 
						|
          if (model.getColumnCount() > 0)
 | 
						|
            {
 | 
						|
              colSel.setAnchorSelectionIndex(0);
 | 
						|
              colSel.setLeadSelectionIndex(0);
 | 
						|
            }
 | 
						|
          else
 | 
						|
            {
 | 
						|
              colSel.setAnchorSelectionIndex(-1);
 | 
						|
              colSel.setLeadSelectionIndex(-1);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  protected FocusListener createFocusListener()
 | 
						|
  {
 | 
						|
    return new FocusHandler();
 | 
						|
  }
 | 
						|
 | 
						|
  protected MouseInputListener createMouseInputListener()
 | 
						|
  {
 | 
						|
    return new MouseInputHandler();
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  /**
 | 
						|
   * Creates and returns a key listener for the JTable.
 | 
						|
   *
 | 
						|
   * @return a key listener for the JTable
 | 
						|
   */
 | 
						|
  protected KeyListener createKeyListener()
 | 
						|
  {
 | 
						|
    return new KeyHandler();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Return the maximum size of the table. The maximum height is the row
 | 
						|
    * height times the number of rows. The maximum width is the sum of
 | 
						|
    * the maximum widths of each column.
 | 
						|
    *
 | 
						|
    *  @param comp the component whose maximum size is being queried,
 | 
						|
    *  this is ignored.
 | 
						|
    *  @return a Dimension object representing the maximum size of the table,
 | 
						|
    *  or null if the table has no elements.
 | 
						|
   */
 | 
						|
  public Dimension getMaximumSize(JComponent comp)
 | 
						|
  {
 | 
						|
    int maxTotalColumnWidth = 0;
 | 
						|
    for (int i = 0; i < table.getColumnCount(); i++)
 | 
						|
      maxTotalColumnWidth += table.getColumnModel().getColumn(i).getMaxWidth();
 | 
						|
 | 
						|
    return new Dimension(maxTotalColumnWidth, getHeight());
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Return the minimum size of the table. The minimum height is the row
 | 
						|
    * height times the number of rows. The minimum width is the sum of
 | 
						|
    * the minimum widths of each column.
 | 
						|
    *
 | 
						|
    *  @param comp the component whose minimum size is being queried,
 | 
						|
    *  this is ignored.
 | 
						|
    *  @return a Dimension object representing the minimum size of the table,
 | 
						|
    *  or null if the table has no elements.
 | 
						|
   */
 | 
						|
  public Dimension getMinimumSize(JComponent comp)
 | 
						|
  {
 | 
						|
    int minTotalColumnWidth = 0;
 | 
						|
    for (int i = 0; i < table.getColumnCount(); i++)
 | 
						|
      minTotalColumnWidth += table.getColumnModel().getColumn(i).getMinWidth();
 | 
						|
 | 
						|
    return new Dimension(minTotalColumnWidth, getHeight());
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the preferred size for the table of that UI.
 | 
						|
   *
 | 
						|
   * @param comp ignored, the <code>table</code> field is used instead
 | 
						|
   *
 | 
						|
   * @return the preferred size for the table of that UI
 | 
						|
   */
 | 
						|
  public Dimension getPreferredSize(JComponent comp)
 | 
						|
  {
 | 
						|
    int prefTotalColumnWidth = 0;
 | 
						|
    TableColumnModel tcm = table.getColumnModel();
 | 
						|
 | 
						|
    for (int i = 0; i < tcm.getColumnCount(); i++)
 | 
						|
      {
 | 
						|
        TableColumn col = tcm.getColumn(i);
 | 
						|
        prefTotalColumnWidth += col.getPreferredWidth();
 | 
						|
      }
 | 
						|
 | 
						|
    return new Dimension(prefTotalColumnWidth, getHeight());
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the table height. This helper method is used by
 | 
						|
   * {@link #getMinimumSize(JComponent)}, {@link #getPreferredSize(JComponent)}
 | 
						|
   * and {@link #getMaximumSize(JComponent)} to determine the table height.
 | 
						|
   *
 | 
						|
   * @return the table height
 | 
						|
   */
 | 
						|
  private int getHeight()
 | 
						|
  {
 | 
						|
    int height = 0;
 | 
						|
    int rowCount = table.getRowCount();
 | 
						|
    if (rowCount > 0 && table.getColumnCount() > 0)
 | 
						|
      {
 | 
						|
        Rectangle r = table.getCellRect(rowCount - 1, 0, true);
 | 
						|
        height = r.y + r.height;
 | 
						|
      }
 | 
						|
    return height;
 | 
						|
  }
 | 
						|
 | 
						|
  protected void installDefaults()
 | 
						|
  {
 | 
						|
    LookAndFeel.installColorsAndFont(table, "Table.background",
 | 
						|
                                     "Table.foreground", "Table.font");
 | 
						|
    table.setGridColor(UIManager.getColor("Table.gridColor"));
 | 
						|
    table.setSelectionForeground(UIManager.getColor("Table.selectionForeground"));
 | 
						|
    table.setSelectionBackground(UIManager.getColor("Table.selectionBackground"));
 | 
						|
    table.setOpaque(true);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Installs keyboard actions on the table.
 | 
						|
   */
 | 
						|
  protected void installKeyboardActions()
 | 
						|
  {
 | 
						|
    // Install the input map.
 | 
						|
    InputMap inputMap =
 | 
						|
      (InputMap) SharedUIDefaults.get("Table.ancestorInputMap");
 | 
						|
    SwingUtilities.replaceUIInputMap(table,
 | 
						|
                                 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
 | 
						|
                                 inputMap);
 | 
						|
 | 
						|
    // FIXME: The JDK uses a LazyActionMap for parentActionMap
 | 
						|
    SwingUtilities.replaceUIActionMap(table, getActionMap());
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Fetches the action map from  the UI defaults, or create a new one
 | 
						|
   * if the action map hasn't been initialized.
 | 
						|
   *
 | 
						|
   * @return the action map
 | 
						|
   */
 | 
						|
  private ActionMap getActionMap()
 | 
						|
  {
 | 
						|
    ActionMap am = (ActionMap) UIManager.get("Table.actionMap");
 | 
						|
    if (am == null)
 | 
						|
      {
 | 
						|
        am = createDefaultActions();
 | 
						|
        UIManager.getLookAndFeelDefaults().put("Table.actionMap", am);
 | 
						|
      }
 | 
						|
    return am;
 | 
						|
  }
 | 
						|
 | 
						|
  private ActionMap createDefaultActions()
 | 
						|
  {
 | 
						|
    ActionMapUIResource am = new ActionMapUIResource();
 | 
						|
    Action action = new TableAction();
 | 
						|
 | 
						|
    am.put("cut", TransferHandler.getCutAction());
 | 
						|
    am.put("copy", TransferHandler.getCopyAction());
 | 
						|
    am.put("paste", TransferHandler.getPasteAction());
 | 
						|
 | 
						|
    am.put("cancel", action);
 | 
						|
    am.put("selectAll", action);
 | 
						|
    am.put("clearSelection", action);
 | 
						|
    am.put("startEditing", action);
 | 
						|
 | 
						|
    am.put("selectNextRow", action);
 | 
						|
    am.put("selectNextRowCell", action);
 | 
						|
    am.put("selectNextRowExtendSelection", action);
 | 
						|
    am.put("selectNextRowChangeLead", action);
 | 
						|
 | 
						|
    am.put("selectPreviousRow", action);
 | 
						|
    am.put("selectPreviousRowCell", action);
 | 
						|
    am.put("selectPreviousRowExtendSelection", action);
 | 
						|
    am.put("selectPreviousRowChangeLead", action);
 | 
						|
 | 
						|
    am.put("selectNextColumn", action);
 | 
						|
    am.put("selectNextColumnCell", action);
 | 
						|
    am.put("selectNextColumnExtendSelection", action);
 | 
						|
    am.put("selectNextColumnChangeLead", action);
 | 
						|
 | 
						|
    am.put("selectPreviousColumn", action);
 | 
						|
    am.put("selectPreviousColumnCell", action);
 | 
						|
    am.put("selectPreviousColumnExtendSelection", action);
 | 
						|
    am.put("selectPreviousColumnChangeLead", action);
 | 
						|
 | 
						|
    am.put("scrollLeftChangeSelection", action);
 | 
						|
    am.put("scrollLeftExtendSelection", action);
 | 
						|
    am.put("scrollRightChangeSelection", action);
 | 
						|
    am.put("scrollRightExtendSelection", action);
 | 
						|
 | 
						|
    am.put("scrollUpChangeSelection", action);
 | 
						|
    am.put("scrollUpExtendSelection", action);
 | 
						|
    am.put("scrollDownChangeSelection", action);
 | 
						|
    am.put("scrolldownExtendSelection", action);
 | 
						|
 | 
						|
    am.put("selectFirstColumn", action);
 | 
						|
    am.put("selectFirstColumnExtendSelection", action);
 | 
						|
    am.put("selectLastColumn", action);
 | 
						|
    am.put("selectLastColumnExtendSelection", action);
 | 
						|
 | 
						|
    am.put("selectFirstRow", action);
 | 
						|
    am.put("selectFirstRowExtendSelection", action);
 | 
						|
    am.put("selectLastRow", action);
 | 
						|
    am.put("selectLastRowExtendSelection", action);
 | 
						|
 | 
						|
    am.put("addToSelection", action);
 | 
						|
    am.put("toggleAndAnchor", action);
 | 
						|
    am.put("extendTo", action);
 | 
						|
    am.put("moveSelectionTo", action);
 | 
						|
 | 
						|
    return am;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This class implements the actions that we want to happen
 | 
						|
   * when specific keys are pressed for the JTable.  The actionPerformed
 | 
						|
   * method is called when a key that has been registered for the JTable
 | 
						|
   * is received.
 | 
						|
   */
 | 
						|
  private static class TableAction
 | 
						|
    extends AbstractAction
 | 
						|
  {
 | 
						|
    /**
 | 
						|
     * What to do when this action is called.
 | 
						|
     *
 | 
						|
     * @param e the ActionEvent that caused this action.
 | 
						|
     */
 | 
						|
    public void actionPerformed(ActionEvent e)
 | 
						|
    {
 | 
						|
      JTable table = (JTable) e.getSource();
 | 
						|
 | 
						|
      DefaultListSelectionModel rowModel
 | 
						|
          = (DefaultListSelectionModel) table.getSelectionModel();
 | 
						|
      DefaultListSelectionModel colModel
 | 
						|
          = (DefaultListSelectionModel) table.getColumnModel().getSelectionModel();
 | 
						|
 | 
						|
      int rowLead = rowModel.getLeadSelectionIndex();
 | 
						|
      int rowMax = table.getModel().getRowCount() - 1;
 | 
						|
 | 
						|
      int colLead = colModel.getLeadSelectionIndex();
 | 
						|
      int colMax = table.getModel().getColumnCount() - 1;
 | 
						|
 | 
						|
      // The command with which the action has been called is stored
 | 
						|
      // in this undocumented action value. This allows us to have only
 | 
						|
      // one Action instance to serve all keyboard input for JTable.
 | 
						|
      String command = (String) getValue("__command__");
 | 
						|
      if (command.equals("selectPreviousRowExtendSelection"))
 | 
						|
        {
 | 
						|
          rowModel.setLeadSelectionIndex(Math.max(rowLead - 1, 0));
 | 
						|
        }
 | 
						|
      else if (command.equals("selectLastColumn"))
 | 
						|
        {
 | 
						|
          colModel.setSelectionInterval(colMax, colMax);
 | 
						|
        }
 | 
						|
      else if (command.equals("startEditing"))
 | 
						|
        {
 | 
						|
          if (table.isCellEditable(rowLead, colLead))
 | 
						|
            table.editCellAt(rowLead, colLead);
 | 
						|
        }
 | 
						|
      else if (command.equals("selectFirstRowExtendSelection"))
 | 
						|
        {
 | 
						|
          rowModel.setLeadSelectionIndex(0);
 | 
						|
        }
 | 
						|
      else if (command.equals("selectFirstColumn"))
 | 
						|
        {
 | 
						|
          colModel.setSelectionInterval(0, 0);
 | 
						|
        }
 | 
						|
      else if (command.equals("selectFirstColumnExtendSelection"))
 | 
						|
        {
 | 
						|
          colModel.setLeadSelectionIndex(0);
 | 
						|
        }
 | 
						|
      else if (command.equals("selectLastRow"))
 | 
						|
        {
 | 
						|
          rowModel.setSelectionInterval(rowMax, rowMax);
 | 
						|
        }
 | 
						|
      else if (command.equals("selectNextRowExtendSelection"))
 | 
						|
        {
 | 
						|
          rowModel.setLeadSelectionIndex(Math.min(rowLead + 1, rowMax));
 | 
						|
        }
 | 
						|
      else if (command.equals("selectFirstRow"))
 | 
						|
        {
 | 
						|
          rowModel.setSelectionInterval(0, 0);
 | 
						|
        }
 | 
						|
      else if (command.equals("selectNextColumnExtendSelection"))
 | 
						|
        {
 | 
						|
          colModel.setLeadSelectionIndex(Math.min(colLead + 1, colMax));
 | 
						|
        }
 | 
						|
      else if (command.equals("selectLastColumnExtendSelection"))
 | 
						|
        {
 | 
						|
          colModel.setLeadSelectionIndex(colMax);
 | 
						|
        }
 | 
						|
      else if (command.equals("selectPreviousColumnExtendSelection"))
 | 
						|
        {
 | 
						|
          colModel.setLeadSelectionIndex(Math.max(colLead - 1, 0));
 | 
						|
        }
 | 
						|
      else if (command.equals("selectNextRow"))
 | 
						|
        {
 | 
						|
          rowModel.setSelectionInterval(Math.min(rowLead + 1, rowMax),
 | 
						|
                                        Math.min(rowLead + 1, rowMax));
 | 
						|
        }
 | 
						|
      else if (command.equals("scrollUpExtendSelection"))
 | 
						|
        {
 | 
						|
          int target;
 | 
						|
          if (rowLead == getFirstVisibleRowIndex(table))
 | 
						|
            target = Math.max(0, rowLead - (getLastVisibleRowIndex(table)
 | 
						|
                - getFirstVisibleRowIndex(table) + 1));
 | 
						|
          else
 | 
						|
            target = getFirstVisibleRowIndex(table);
 | 
						|
 | 
						|
          rowModel.setLeadSelectionIndex(target);
 | 
						|
          colModel.setLeadSelectionIndex(colLead);
 | 
						|
        }
 | 
						|
      else if (command.equals("selectPreviousRow"))
 | 
						|
        {
 | 
						|
          rowModel.setSelectionInterval(Math.max(rowLead - 1, 0),
 | 
						|
                                        Math.max(rowLead - 1, 0));
 | 
						|
        }
 | 
						|
      else if (command.equals("scrollRightChangeSelection"))
 | 
						|
        {
 | 
						|
          int target;
 | 
						|
          if (colLead == getLastVisibleColumnIndex(table))
 | 
						|
            target = Math.min(colMax, colLead
 | 
						|
                              + (getLastVisibleColumnIndex(table)
 | 
						|
                              - getFirstVisibleColumnIndex(table) + 1));
 | 
						|
          else
 | 
						|
            target = getLastVisibleColumnIndex(table);
 | 
						|
 | 
						|
          colModel.setSelectionInterval(target, target);
 | 
						|
          rowModel.setSelectionInterval(rowLead, rowLead);
 | 
						|
        }
 | 
						|
      else if (command.equals("selectPreviousColumn"))
 | 
						|
        {
 | 
						|
          colModel.setSelectionInterval(Math.max(colLead - 1, 0),
 | 
						|
                                        Math.max(colLead - 1, 0));
 | 
						|
        }
 | 
						|
      else if (command.equals("scrollLeftChangeSelection"))
 | 
						|
        {
 | 
						|
          int target;
 | 
						|
          if (colLead == getFirstVisibleColumnIndex(table))
 | 
						|
            target = Math.max(0, colLead - (getLastVisibleColumnIndex(table)
 | 
						|
                                 - getFirstVisibleColumnIndex(table) + 1));
 | 
						|
          else
 | 
						|
            target = getFirstVisibleColumnIndex(table);
 | 
						|
 | 
						|
          colModel.setSelectionInterval(target, target);
 | 
						|
          rowModel.setSelectionInterval(rowLead, rowLead);
 | 
						|
        }
 | 
						|
      else if (command.equals("clearSelection"))
 | 
						|
        {
 | 
						|
          table.clearSelection();
 | 
						|
        }
 | 
						|
      else if (command.equals("cancel"))
 | 
						|
        {
 | 
						|
          // FIXME: implement other parts of "cancel" like undo-ing last
 | 
						|
          // selection.  Right now it just calls editingCancelled if
 | 
						|
          // we're currently editing.
 | 
						|
          if (table.isEditing())
 | 
						|
            table.editingCanceled(new ChangeEvent("cancel"));
 | 
						|
        }
 | 
						|
      else if (command.equals("selectNextRowCell")
 | 
						|
               || command.equals("selectPreviousRowCell")
 | 
						|
               || command.equals("selectNextColumnCell")
 | 
						|
               || command.equals("selectPreviousColumnCell"))
 | 
						|
        {
 | 
						|
          // If nothing is selected, select the first cell in the table
 | 
						|
          if (table.getSelectedRowCount() == 0 &&
 | 
						|
              table.getSelectedColumnCount() == 0)
 | 
						|
            {
 | 
						|
              rowModel.setSelectionInterval(0, 0);
 | 
						|
              colModel.setSelectionInterval(0, 0);
 | 
						|
              return;
 | 
						|
            }
 | 
						|
 | 
						|
          // If the lead selection index isn't selected (ie a remove operation
 | 
						|
          // happened, then set the lead to the first selected cell in the
 | 
						|
          // table
 | 
						|
          if (!table.isCellSelected(rowLead, colLead))
 | 
						|
            {
 | 
						|
              rowModel.addSelectionInterval(rowModel.getMinSelectionIndex(),
 | 
						|
                                            rowModel.getMinSelectionIndex());
 | 
						|
              colModel.addSelectionInterval(colModel.getMinSelectionIndex(),
 | 
						|
                                            colModel.getMinSelectionIndex());
 | 
						|
              return;
 | 
						|
            }
 | 
						|
 | 
						|
          // multRowsSelected and multColsSelected tell us if multiple rows or
 | 
						|
          // columns are selected, respectively
 | 
						|
          boolean multRowsSelected, multColsSelected;
 | 
						|
          multRowsSelected = table.getSelectedRowCount() > 1 &&
 | 
						|
            table.getRowSelectionAllowed();
 | 
						|
 | 
						|
          multColsSelected = table.getSelectedColumnCount() > 1 &&
 | 
						|
            table.getColumnSelectionAllowed();
 | 
						|
 | 
						|
          // If there is just one selection, select the next cell, and wrap
 | 
						|
          // when you get to the edges of the table.
 | 
						|
          if (!multColsSelected && !multRowsSelected)
 | 
						|
            {
 | 
						|
              if (command.indexOf("Column") != -1)
 | 
						|
                advanceSingleSelection(colModel, colMax, rowModel, rowMax,
 | 
						|
                    command.equals("selectPreviousColumnCell"));
 | 
						|
              else
 | 
						|
                advanceSingleSelection(rowModel, rowMax, colModel, colMax,
 | 
						|
                    command.equals("selectPreviousRowCell"));
 | 
						|
              return;
 | 
						|
            }
 | 
						|
 | 
						|
 | 
						|
          // rowMinSelected and rowMaxSelected are the minimum and maximum
 | 
						|
          // values respectively of selected cells in the row selection model
 | 
						|
          // Similarly for colMinSelected and colMaxSelected.
 | 
						|
          int rowMaxSelected = table.getRowSelectionAllowed() ?
 | 
						|
            rowModel.getMaxSelectionIndex() : table.getModel().getRowCount() - 1;
 | 
						|
          int rowMinSelected = table.getRowSelectionAllowed() ?
 | 
						|
            rowModel.getMinSelectionIndex() : 0;
 | 
						|
          int colMaxSelected = table.getColumnSelectionAllowed() ?
 | 
						|
            colModel.getMaxSelectionIndex() :
 | 
						|
            table.getModel().getColumnCount() - 1;
 | 
						|
          int colMinSelected = table.getColumnSelectionAllowed() ?
 | 
						|
            colModel.getMinSelectionIndex() : 0;
 | 
						|
 | 
						|
          // If there are multiple rows and columns selected, select the next
 | 
						|
          // cell and wrap at the edges of the selection.
 | 
						|
          if (command.indexOf("Column") != -1)
 | 
						|
            advanceMultipleSelection(table, colModel, colMinSelected,
 | 
						|
                                     colMaxSelected, rowModel, rowMinSelected,
 | 
						|
                                     rowMaxSelected,
 | 
						|
                                    command.equals("selectPreviousColumnCell"),
 | 
						|
                                    true);
 | 
						|
 | 
						|
          else
 | 
						|
            advanceMultipleSelection(table, rowModel, rowMinSelected,
 | 
						|
                                     rowMaxSelected, colModel, colMinSelected,
 | 
						|
                                     colMaxSelected,
 | 
						|
                                     command.equals("selectPreviousRowCell"),
 | 
						|
                                     false);
 | 
						|
        }
 | 
						|
      else if (command.equals("selectNextColumn"))
 | 
						|
        {
 | 
						|
          colModel.setSelectionInterval(Math.min(colLead + 1, colMax),
 | 
						|
                                        Math.min(colLead + 1, colMax));
 | 
						|
        }
 | 
						|
      else if (command.equals("scrollLeftExtendSelection"))
 | 
						|
        {
 | 
						|
          int target;
 | 
						|
          if (colLead == getFirstVisibleColumnIndex(table))
 | 
						|
            target = Math.max(0, colLead - (getLastVisibleColumnIndex(table)
 | 
						|
                                 - getFirstVisibleColumnIndex(table) + 1));
 | 
						|
          else
 | 
						|
            target = getFirstVisibleColumnIndex(table);
 | 
						|
 | 
						|
          colModel.setLeadSelectionIndex(target);
 | 
						|
          rowModel.setLeadSelectionIndex(rowLead);
 | 
						|
        }
 | 
						|
      else if (command.equals("scrollDownChangeSelection"))
 | 
						|
        {
 | 
						|
          int target;
 | 
						|
          if (rowLead == getLastVisibleRowIndex(table))
 | 
						|
            target = Math.min(rowMax, rowLead + (getLastVisibleRowIndex(table)
 | 
						|
                                      - getFirstVisibleRowIndex(table) + 1));
 | 
						|
          else
 | 
						|
            target = getLastVisibleRowIndex(table);
 | 
						|
 | 
						|
          rowModel.setSelectionInterval(target, target);
 | 
						|
          colModel.setSelectionInterval(colLead, colLead);
 | 
						|
        }
 | 
						|
      else if (command.equals("scrollRightExtendSelection"))
 | 
						|
        {
 | 
						|
          int target;
 | 
						|
          if (colLead == getLastVisibleColumnIndex(table))
 | 
						|
            target = Math.min(colMax, colLead + (getLastVisibleColumnIndex(table)
 | 
						|
                - getFirstVisibleColumnIndex(table) + 1));
 | 
						|
          else
 | 
						|
            target = getLastVisibleColumnIndex(table);
 | 
						|
 | 
						|
          colModel.setLeadSelectionIndex(target);
 | 
						|
          rowModel.setLeadSelectionIndex(rowLead);
 | 
						|
        }
 | 
						|
      else if (command.equals("selectAll"))
 | 
						|
        {
 | 
						|
          table.selectAll();
 | 
						|
        }
 | 
						|
      else if (command.equals("selectLastRowExtendSelection"))
 | 
						|
        {
 | 
						|
          rowModel.setLeadSelectionIndex(rowMax);
 | 
						|
          colModel.setLeadSelectionIndex(colLead);
 | 
						|
        }
 | 
						|
      else if (command.equals("scrollDownExtendSelection"))
 | 
						|
        {
 | 
						|
          int target;
 | 
						|
          if (rowLead == getLastVisibleRowIndex(table))
 | 
						|
            target = Math.min(rowMax, rowLead + (getLastVisibleRowIndex(table)
 | 
						|
                - getFirstVisibleRowIndex(table) + 1));
 | 
						|
          else
 | 
						|
            target = getLastVisibleRowIndex(table);
 | 
						|
 | 
						|
          rowModel.setLeadSelectionIndex(target);
 | 
						|
          colModel.setLeadSelectionIndex(colLead);
 | 
						|
        }
 | 
						|
      else if (command.equals("scrollUpChangeSelection"))
 | 
						|
        {
 | 
						|
          int target;
 | 
						|
          if (rowLead == getFirstVisibleRowIndex(table))
 | 
						|
            target = Math.max(0, rowLead - (getLastVisibleRowIndex(table)
 | 
						|
                - getFirstVisibleRowIndex(table) + 1));
 | 
						|
          else
 | 
						|
            target = getFirstVisibleRowIndex(table);
 | 
						|
 | 
						|
          rowModel.setSelectionInterval(target, target);
 | 
						|
          colModel.setSelectionInterval(colLead, colLead);
 | 
						|
        }
 | 
						|
      else if (command.equals("selectNextRowChangeLead"))
 | 
						|
          {
 | 
						|
            if (rowModel.getSelectionMode()
 | 
						|
                != ListSelectionModel.MULTIPLE_INTERVAL_SELECTION)
 | 
						|
              {
 | 
						|
                // just "selectNextRow"
 | 
						|
                rowModel.setSelectionInterval(Math.min(rowLead + 1, rowMax),
 | 
						|
                                              Math.min(rowLead + 1, rowMax));
 | 
						|
                colModel.setSelectionInterval(colLead, colLead);
 | 
						|
              }
 | 
						|
            else
 | 
						|
              rowModel.moveLeadSelectionIndex(Math.min(rowLead + 1, rowMax));
 | 
						|
          }
 | 
						|
      else if (command.equals("selectPreviousRowChangeLead"))
 | 
						|
        {
 | 
						|
          if (rowModel.getSelectionMode()
 | 
						|
              != ListSelectionModel.MULTIPLE_INTERVAL_SELECTION)
 | 
						|
            {
 | 
						|
              // just selectPreviousRow
 | 
						|
              rowModel.setSelectionInterval(Math.max(rowLead - 1, 0),
 | 
						|
                                            Math.min(rowLead - 1, 0));
 | 
						|
              colModel.setSelectionInterval(colLead, colLead);
 | 
						|
            }
 | 
						|
          else
 | 
						|
            rowModel.moveLeadSelectionIndex(Math.max(rowLead - 1, 0));
 | 
						|
        }
 | 
						|
      else if (command.equals("selectNextColumnChangeLead"))
 | 
						|
        {
 | 
						|
          if (colModel.getSelectionMode()
 | 
						|
              != ListSelectionModel.MULTIPLE_INTERVAL_SELECTION)
 | 
						|
            {
 | 
						|
              // just selectNextColumn
 | 
						|
              rowModel.setSelectionInterval(rowLead, rowLead);
 | 
						|
              colModel.setSelectionInterval(Math.min(colLead + 1, colMax),
 | 
						|
                                            Math.min(colLead + 1, colMax));
 | 
						|
            }
 | 
						|
          else
 | 
						|
            colModel.moveLeadSelectionIndex(Math.min(colLead + 1, colMax));
 | 
						|
        }
 | 
						|
      else if (command.equals("selectPreviousColumnChangeLead"))
 | 
						|
        {
 | 
						|
          if (colModel.getSelectionMode()
 | 
						|
              != ListSelectionModel.MULTIPLE_INTERVAL_SELECTION)
 | 
						|
            {
 | 
						|
              // just selectPreviousColumn
 | 
						|
              rowModel.setSelectionInterval(rowLead, rowLead);
 | 
						|
              colModel.setSelectionInterval(Math.max(colLead - 1, 0),
 | 
						|
                                            Math.max(colLead - 1, 0));
 | 
						|
 | 
						|
            }
 | 
						|
          else
 | 
						|
            colModel.moveLeadSelectionIndex(Math.max(colLead - 1, 0));
 | 
						|
        }
 | 
						|
      else if (command.equals("addToSelection"))
 | 
						|
          {
 | 
						|
            if (!table.isEditing())
 | 
						|
              {
 | 
						|
                int oldRowAnchor = rowModel.getAnchorSelectionIndex();
 | 
						|
                int oldColAnchor = colModel.getAnchorSelectionIndex();
 | 
						|
                rowModel.addSelectionInterval(rowLead, rowLead);
 | 
						|
                colModel.addSelectionInterval(colLead, colLead);
 | 
						|
                rowModel.setAnchorSelectionIndex(oldRowAnchor);
 | 
						|
                colModel.setAnchorSelectionIndex(oldColAnchor);
 | 
						|
              }
 | 
						|
          }
 | 
						|
      else if (command.equals("extendTo"))
 | 
						|
        {
 | 
						|
          rowModel.setSelectionInterval(rowModel.getAnchorSelectionIndex(),
 | 
						|
                                        rowLead);
 | 
						|
          colModel.setSelectionInterval(colModel.getAnchorSelectionIndex(),
 | 
						|
                                        colLead);
 | 
						|
        }
 | 
						|
      else if (command.equals("toggleAndAnchor"))
 | 
						|
        {
 | 
						|
          if (rowModel.isSelectedIndex(rowLead))
 | 
						|
            rowModel.removeSelectionInterval(rowLead, rowLead);
 | 
						|
          else
 | 
						|
            rowModel.addSelectionInterval(rowLead, rowLead);
 | 
						|
 | 
						|
          if (colModel.isSelectedIndex(colLead))
 | 
						|
            colModel.removeSelectionInterval(colLead, colLead);
 | 
						|
          else
 | 
						|
            colModel.addSelectionInterval(colLead, colLead);
 | 
						|
 | 
						|
          rowModel.setAnchorSelectionIndex(rowLead);
 | 
						|
          colModel.setAnchorSelectionIndex(colLead);
 | 
						|
        }
 | 
						|
      else if (command.equals("stopEditing"))
 | 
						|
        {
 | 
						|
          table.editingStopped(new ChangeEvent(command));
 | 
						|
        }
 | 
						|
      else
 | 
						|
        {
 | 
						|
          // If we're here that means we bound this TableAction class
 | 
						|
          // to a keyboard input but we either want to ignore that input
 | 
						|
          // or we just haven't implemented its action yet.
 | 
						|
 | 
						|
          // Uncomment the following line to print the names of unused bindings
 | 
						|
          // when their keys are pressed
 | 
						|
 | 
						|
          // System.out.println ("not implemented: "+e.getActionCommand());
 | 
						|
        }
 | 
						|
 | 
						|
      // Any commands whose keyStrokes should be used by the Editor should not
 | 
						|
      // cause editing to be stopped: ie, the SPACE sends "addToSelection" but
 | 
						|
      // if the table is in editing mode, the space should not cause us to stop
 | 
						|
      // editing because it should be used by the Editor.
 | 
						|
      if (table.isEditing() && command != "startEditing"
 | 
						|
          && command != "addToSelection")
 | 
						|
        table.editingStopped(new ChangeEvent("update"));
 | 
						|
 | 
						|
      table.scrollRectToVisible(table.getCellRect(
 | 
						|
          rowModel.getLeadSelectionIndex(), colModel.getLeadSelectionIndex(),
 | 
						|
          false));
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the column index of the first visible column.
 | 
						|
     * @return the column index of the first visible column.
 | 
						|
     */
 | 
						|
    int getFirstVisibleColumnIndex(JTable table)
 | 
						|
    {
 | 
						|
      ComponentOrientation or = table.getComponentOrientation();
 | 
						|
      Rectangle r = table.getVisibleRect();
 | 
						|
      if (!or.isLeftToRight())
 | 
						|
        r.translate((int) r.getWidth() - 1, 0);
 | 
						|
      return table.columnAtPoint(r.getLocation());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the column index of the last visible column.
 | 
						|
     *
 | 
						|
     */
 | 
						|
    int getLastVisibleColumnIndex(JTable table)
 | 
						|
    {
 | 
						|
      ComponentOrientation or = table.getComponentOrientation();
 | 
						|
      Rectangle r = table.getVisibleRect();
 | 
						|
      if (or.isLeftToRight())
 | 
						|
        r.translate((int) r.getWidth() - 1, 0);
 | 
						|
      return table.columnAtPoint(r.getLocation());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the row index of the first visible row.
 | 
						|
     *
 | 
						|
     */
 | 
						|
    int getFirstVisibleRowIndex(JTable table)
 | 
						|
    {
 | 
						|
      ComponentOrientation or = table.getComponentOrientation();
 | 
						|
      Rectangle r = table.getVisibleRect();
 | 
						|
      if (!or.isLeftToRight())
 | 
						|
        r.translate((int) r.getWidth() - 1, 0);
 | 
						|
      return table.rowAtPoint(r.getLocation());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns the row index of the last visible row.
 | 
						|
     *
 | 
						|
     */
 | 
						|
    int getLastVisibleRowIndex(JTable table)
 | 
						|
    {
 | 
						|
      ComponentOrientation or = table.getComponentOrientation();
 | 
						|
      Rectangle r = table.getVisibleRect();
 | 
						|
      r.translate(0, (int) r.getHeight() - 1);
 | 
						|
      if (or.isLeftToRight())
 | 
						|
        r.translate((int) r.getWidth() - 1, 0);
 | 
						|
      // The next if makes sure that we don't return -1 simply because
 | 
						|
      // there is white space at the bottom of the table (ie, the display
 | 
						|
      // area is larger than the table)
 | 
						|
      if (table.rowAtPoint(r.getLocation()) == -1)
 | 
						|
        {
 | 
						|
          if (getFirstVisibleRowIndex(table) == -1)
 | 
						|
            return -1;
 | 
						|
          else
 | 
						|
            return table.getModel().getRowCount() - 1;
 | 
						|
        }
 | 
						|
      return table.rowAtPoint(r.getLocation());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * A helper method for the key bindings.  Used because the actions
 | 
						|
     * for TAB, SHIFT-TAB, ENTER, and SHIFT-ENTER are very similar.
 | 
						|
     *
 | 
						|
     * Selects the next (previous if SHIFT pressed) column for TAB, or row for
 | 
						|
     * ENTER from within the currently selected cells.
 | 
						|
     *
 | 
						|
     * @param firstModel the ListSelectionModel for columns (TAB) or
 | 
						|
     * rows (ENTER)
 | 
						|
     * @param firstMin the first selected index in firstModel
 | 
						|
     * @param firstMax the last selected index in firstModel
 | 
						|
     * @param secondModel the ListSelectionModel for rows (TAB) or
 | 
						|
     * columns (ENTER)
 | 
						|
     * @param secondMin the first selected index in secondModel
 | 
						|
     * @param secondMax the last selected index in secondModel
 | 
						|
     * @param reverse true if shift was held for the event
 | 
						|
     * @param eventIsTab true if TAB was pressed, false if ENTER pressed
 | 
						|
     */
 | 
						|
    void advanceMultipleSelection(JTable table, ListSelectionModel firstModel,
 | 
						|
                                  int firstMin,
 | 
						|
                                  int firstMax, ListSelectionModel secondModel,
 | 
						|
                                  int secondMin, int secondMax, boolean reverse,
 | 
						|
                                  boolean eventIsTab)
 | 
						|
    {
 | 
						|
      // If eventIsTab, all the "firsts" correspond to columns, otherwise, to
 | 
						|
      // rows "seconds" correspond to the opposite
 | 
						|
      int firstLead = firstModel.getLeadSelectionIndex();
 | 
						|
      int secondLead = secondModel.getLeadSelectionIndex();
 | 
						|
      int numFirsts = eventIsTab ?
 | 
						|
        table.getModel().getColumnCount() : table.getModel().getRowCount();
 | 
						|
      int numSeconds = eventIsTab ?
 | 
						|
        table.getModel().getRowCount() : table.getModel().getColumnCount();
 | 
						|
 | 
						|
      // check if we have to wrap the "firsts" around, going to the other side
 | 
						|
      if ((firstLead == firstMax && !reverse) ||
 | 
						|
          (reverse && firstLead == firstMin))
 | 
						|
        {
 | 
						|
          firstModel.addSelectionInterval(reverse ? firstMax : firstMin,
 | 
						|
                                          reverse ? firstMax : firstMin);
 | 
						|
 | 
						|
          // check if we have to wrap the "seconds"
 | 
						|
          if ((secondLead == secondMax && !reverse) ||
 | 
						|
              (reverse && secondLead == secondMin))
 | 
						|
            secondModel.addSelectionInterval(reverse ? secondMax : secondMin,
 | 
						|
                                             reverse ? secondMax : secondMin);
 | 
						|
 | 
						|
          // if we're not wrapping the seconds, we have to find out where we
 | 
						|
          // are within the secondModel and advance to the next cell (or
 | 
						|
          // go back to the previous cell if reverse == true)
 | 
						|
          else
 | 
						|
            {
 | 
						|
              int[] secondsSelected;
 | 
						|
              if (eventIsTab && table.getRowSelectionAllowed() ||
 | 
						|
                  !eventIsTab && table.getColumnSelectionAllowed())
 | 
						|
                secondsSelected = eventIsTab ?
 | 
						|
                  table.getSelectedRows() : table.getSelectedColumns();
 | 
						|
              else
 | 
						|
                {
 | 
						|
                  // if row selection is not allowed, then the entire column gets
 | 
						|
                  // selected when you click on it, so consider ALL rows selected
 | 
						|
                  secondsSelected = new int[numSeconds];
 | 
						|
                  for (int i = 0; i < numSeconds; i++)
 | 
						|
                  secondsSelected[i] = i;
 | 
						|
                }
 | 
						|
 | 
						|
              // and now find the "next" index within the model
 | 
						|
              int secondIndex = reverse ? secondsSelected.length - 1 : 0;
 | 
						|
              if (!reverse)
 | 
						|
                while (secondsSelected[secondIndex] <= secondLead)
 | 
						|
                  secondIndex++;
 | 
						|
              else
 | 
						|
                while (secondsSelected[secondIndex] >= secondLead)
 | 
						|
                  secondIndex--;
 | 
						|
 | 
						|
              // and select it - updating the lead selection index
 | 
						|
              secondModel.addSelectionInterval(secondsSelected[secondIndex],
 | 
						|
                                               secondsSelected[secondIndex]);
 | 
						|
            }
 | 
						|
        }
 | 
						|
      // We didn't have to wrap the firsts, so just find the "next" first
 | 
						|
      // and select it, we don't have to change "seconds"
 | 
						|
      else
 | 
						|
        {
 | 
						|
          int[] firstsSelected;
 | 
						|
          if (eventIsTab && table.getColumnSelectionAllowed() ||
 | 
						|
              !eventIsTab && table.getRowSelectionAllowed())
 | 
						|
            firstsSelected = eventIsTab ?
 | 
						|
              table.getSelectedColumns() : table.getSelectedRows();
 | 
						|
          else
 | 
						|
            {
 | 
						|
              // if selection not allowed, consider ALL firsts to be selected
 | 
						|
              firstsSelected = new int[numFirsts];
 | 
						|
              for (int i = 0; i < numFirsts; i++)
 | 
						|
                firstsSelected[i] = i;
 | 
						|
            }
 | 
						|
          int firstIndex = reverse ? firstsSelected.length - 1 : 0;
 | 
						|
          if (!reverse)
 | 
						|
            while (firstsSelected[firstIndex] <= firstLead)
 | 
						|
              firstIndex++;
 | 
						|
          else
 | 
						|
            while (firstsSelected[firstIndex] >= firstLead)
 | 
						|
              firstIndex--;
 | 
						|
          firstModel.addSelectionInterval(firstsSelected[firstIndex],
 | 
						|
                                          firstsSelected[firstIndex]);
 | 
						|
          secondModel.addSelectionInterval(secondLead, secondLead);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * A helper method for the key  bindings. Used because the actions
 | 
						|
     * for TAB, SHIFT-TAB, ENTER, and SHIFT-ENTER are very similar.
 | 
						|
     *
 | 
						|
     * Selects the next (previous if SHIFT pressed) column (TAB) or row (ENTER)
 | 
						|
     * in the table, changing the current selection.  All cells in the table
 | 
						|
     * are eligible, not just the ones that are currently selected.
 | 
						|
     * @param firstModel the ListSelectionModel for columns (TAB) or rows
 | 
						|
     * (ENTER)
 | 
						|
     * @param firstMax the last index in firstModel
 | 
						|
     * @param secondModel the ListSelectionModel for rows (TAB) or columns
 | 
						|
     * (ENTER)
 | 
						|
     * @param secondMax the last index in secondModel
 | 
						|
     * @param reverse true if SHIFT was pressed for the event
 | 
						|
     */
 | 
						|
 | 
						|
    void advanceSingleSelection(ListSelectionModel firstModel, int firstMax,
 | 
						|
                                ListSelectionModel secondModel, int secondMax,
 | 
						|
                                boolean reverse)
 | 
						|
    {
 | 
						|
      // for TABs, "first" corresponds to columns and "seconds" to rows.
 | 
						|
      // the opposite is true for ENTERs
 | 
						|
      int firstLead = firstModel.getLeadSelectionIndex();
 | 
						|
      int secondLead = secondModel.getLeadSelectionIndex();
 | 
						|
 | 
						|
      // if we are going backwards subtract 2 because we later add 1
 | 
						|
      // for a net change of -1
 | 
						|
      if (reverse && (firstLead == 0))
 | 
						|
        {
 | 
						|
          // check if we have to wrap around
 | 
						|
          if (secondLead == 0)
 | 
						|
            secondLead += secondMax + 1;
 | 
						|
          secondLead -= 2;
 | 
						|
        }
 | 
						|
 | 
						|
      // do we have to wrap the "seconds"?
 | 
						|
      if (reverse && (firstLead == 0) || !reverse && (firstLead == firstMax))
 | 
						|
        secondModel.setSelectionInterval((secondLead + 1) % (secondMax + 1),
 | 
						|
                                         (secondLead + 1) % (secondMax + 1));
 | 
						|
      // if not, just reselect the current lead
 | 
						|
      else
 | 
						|
        secondModel.setSelectionInterval(secondLead, secondLead);
 | 
						|
 | 
						|
      // if we are going backwards, subtract 2  because we add 1 later
 | 
						|
      // for net change of -1
 | 
						|
      if (reverse)
 | 
						|
        {
 | 
						|
          // check for wraparound
 | 
						|
          if (firstLead == 0)
 | 
						|
            firstLead += firstMax + 1;
 | 
						|
          firstLead -= 2;
 | 
						|
        }
 | 
						|
      // select the next "first"
 | 
						|
      firstModel.setSelectionInterval((firstLead + 1) % (firstMax + 1),
 | 
						|
                                      (firstLead + 1) % (firstMax + 1));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  protected void installListeners()
 | 
						|
  {
 | 
						|
    if (focusListener == null)
 | 
						|
      focusListener = createFocusListener();
 | 
						|
    table.addFocusListener(focusListener);
 | 
						|
    if (keyListener == null)
 | 
						|
      keyListener = createKeyListener();
 | 
						|
    table.addKeyListener(keyListener);
 | 
						|
    if (mouseInputListener == null)
 | 
						|
      mouseInputListener = createMouseInputListener();
 | 
						|
    table.addMouseListener(mouseInputListener);
 | 
						|
    table.addMouseMotionListener(mouseInputListener);
 | 
						|
    if (propertyChangeListener == null)
 | 
						|
      propertyChangeListener = new PropertyChangeHandler();
 | 
						|
    table.addPropertyChangeListener(propertyChangeListener);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Uninstalls UI defaults that have been installed by
 | 
						|
   * {@link #installDefaults()}.
 | 
						|
   */
 | 
						|
  protected void uninstallDefaults()
 | 
						|
  {
 | 
						|
    // Nothing to do here for now.
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Uninstalls the keyboard actions that have been installed by
 | 
						|
   * {@link #installKeyboardActions()}.
 | 
						|
   */
 | 
						|
  protected void uninstallKeyboardActions()
 | 
						|
  {
 | 
						|
    SwingUtilities.replaceUIInputMap(table, JComponent.
 | 
						|
                                     WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
 | 
						|
    SwingUtilities.replaceUIActionMap(table, null);
 | 
						|
  }
 | 
						|
 | 
						|
  protected void uninstallListeners()
 | 
						|
  {
 | 
						|
    table.removeFocusListener(focusListener);
 | 
						|
    table.removeKeyListener(keyListener);
 | 
						|
    table.removeMouseListener(mouseInputListener);
 | 
						|
    table.removeMouseMotionListener(mouseInputListener);
 | 
						|
    table.removePropertyChangeListener(propertyChangeListener);
 | 
						|
    propertyChangeListener = null;
 | 
						|
  }
 | 
						|
 | 
						|
  public void installUI(JComponent comp)
 | 
						|
  {
 | 
						|
    table = (JTable) comp;
 | 
						|
    rendererPane = new CellRendererPane();
 | 
						|
    table.add(rendererPane);
 | 
						|
 | 
						|
    installDefaults();
 | 
						|
    installKeyboardActions();
 | 
						|
    installListeners();
 | 
						|
  }
 | 
						|
 | 
						|
  public void uninstallUI(JComponent c)
 | 
						|
  {
 | 
						|
    uninstallListeners();
 | 
						|
    uninstallKeyboardActions();
 | 
						|
    uninstallDefaults();
 | 
						|
 | 
						|
    table.remove(rendererPane);
 | 
						|
    rendererPane = null;
 | 
						|
    table = null;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Paints a single cell in the table.
 | 
						|
   *
 | 
						|
   * @param g The graphics context to paint in
 | 
						|
   * @param row The row number to paint
 | 
						|
   * @param col The column number to paint
 | 
						|
   * @param bounds The bounds of the cell to paint, assuming a coordinate
 | 
						|
   * system beginning at <code>(0,0)</code> in the upper left corner of the
 | 
						|
   * table
 | 
						|
   * @param rend A cell renderer to paint with
 | 
						|
   */
 | 
						|
  void paintCell(Graphics g, int row, int col, Rectangle bounds,
 | 
						|
                 TableCellRenderer rend)
 | 
						|
  {
 | 
						|
    Component comp = table.prepareRenderer(rend, row, col);
 | 
						|
    rendererPane.paintComponent(g, comp, table, bounds);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Paint the associated table.
 | 
						|
   */
 | 
						|
  public void paint(Graphics gfx, JComponent ignored)
 | 
						|
  {
 | 
						|
    int ncols = table.getColumnCount();
 | 
						|
    int nrows = table.getRowCount();
 | 
						|
    if (nrows == 0 || ncols == 0)
 | 
						|
      return;
 | 
						|
 | 
						|
    Rectangle clip = gfx.getClipBounds();
 | 
						|
 | 
						|
    // Determine the range of cells that are within the clip bounds.
 | 
						|
    Point p1 = new Point(clip.x, clip.y);
 | 
						|
    int c0 = table.columnAtPoint(p1);
 | 
						|
    if (c0 == -1)
 | 
						|
      c0 = 0;
 | 
						|
    int r0 = table.rowAtPoint(p1);
 | 
						|
    if (r0 == -1)
 | 
						|
      r0 = 0;
 | 
						|
    Point p2 = new Point(clip.x + clip.width, clip.y + clip.height);
 | 
						|
    int cn = table.columnAtPoint(p2);
 | 
						|
    if (cn == -1)
 | 
						|
      cn = table.getColumnCount() - 1;
 | 
						|
    int rn = table.rowAtPoint(p2);
 | 
						|
    if (rn == -1)
 | 
						|
      rn = table.getRowCount() - 1;
 | 
						|
 | 
						|
    int columnMargin = table.getColumnModel().getColumnMargin();
 | 
						|
    int rowMargin = table.getRowMargin();
 | 
						|
 | 
						|
    TableColumnModel cmodel = table.getColumnModel();
 | 
						|
    int[] widths = new int[cn + 1];
 | 
						|
    for (int i = c0; i <= cn; i++)
 | 
						|
      {
 | 
						|
        widths[i] = cmodel.getColumn(i).getWidth() - columnMargin;
 | 
						|
      }
 | 
						|
 | 
						|
    Rectangle bounds = table.getCellRect(r0, c0, false);
 | 
						|
    // The left boundary of the area being repainted.
 | 
						|
    int left = bounds.x;
 | 
						|
 | 
						|
    // The top boundary of the area being repainted.
 | 
						|
    int top = bounds.y;
 | 
						|
 | 
						|
    // The bottom boundary of the area being repainted.
 | 
						|
    int bottom;
 | 
						|
 | 
						|
    // paint the cell contents
 | 
						|
    Color grid = table.getGridColor();
 | 
						|
    for (int r = r0; r <= rn; ++r)
 | 
						|
      {
 | 
						|
        for (int c = c0; c <= cn; ++c)
 | 
						|
          {
 | 
						|
            bounds.width = widths[c];
 | 
						|
            paintCell(gfx, r, c, bounds, table.getCellRenderer(r, c));
 | 
						|
            bounds.x += widths[c] + columnMargin;
 | 
						|
          }
 | 
						|
        bounds.x = left;
 | 
						|
        bounds.y += table.getRowHeight(r);
 | 
						|
        // Update row height for tables with custom heights.
 | 
						|
        bounds.height = table.getRowHeight(r + 1) - rowMargin;
 | 
						|
      }
 | 
						|
 | 
						|
    bottom = bounds.y - rowMargin;
 | 
						|
 | 
						|
    // paint vertical grid lines
 | 
						|
    if (grid != null && table.getShowVerticalLines())
 | 
						|
      {
 | 
						|
        Color save = gfx.getColor();
 | 
						|
        gfx.setColor(grid);
 | 
						|
        int x = left - columnMargin;
 | 
						|
        for (int c = c0; c <= cn; ++c)
 | 
						|
          {
 | 
						|
            // The vertical grid is draw right from the cells, so we
 | 
						|
            // add before drawing.
 | 
						|
            x += widths[c] + columnMargin;
 | 
						|
            gfx.drawLine(x, top, x, bottom);
 | 
						|
          }
 | 
						|
        gfx.setColor(save);
 | 
						|
      }
 | 
						|
 | 
						|
    // paint horizontal grid lines
 | 
						|
    if (grid != null && table.getShowHorizontalLines())
 | 
						|
      {
 | 
						|
        Color save = gfx.getColor();
 | 
						|
        gfx.setColor(grid);
 | 
						|
        int y = top - rowMargin;
 | 
						|
        for (int r = r0; r <= rn; ++r)
 | 
						|
          {
 | 
						|
            // The horizontal grid is draw below the cells, so we
 | 
						|
            // add before drawing.
 | 
						|
            y += table.getRowHeight(r);
 | 
						|
            gfx.drawLine(left, y, p2.x, y);
 | 
						|
          }
 | 
						|
        gfx.setColor(save);
 | 
						|
      }
 | 
						|
  }
 | 
						|
}
 |