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);
 | |
|       }
 | |
|   }
 | |
| }
 |