Home » openjdk-7 » javax » swing » plaf » basic » [javadoc | source]

    1   /*
    2    * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package javax.swing.plaf.basic;
   27   
   28   import java.awt;
   29   import java.awt.datatransfer;
   30   import java.awt.dnd;
   31   import java.awt.event;
   32   import java.util.Enumeration;
   33   import java.util.EventObject;
   34   import java.util.Hashtable;
   35   import java.util.TooManyListenersException;
   36   import javax.swing;
   37   import javax.swing.event;
   38   import javax.swing.plaf;
   39   import javax.swing.text;
   40   import javax.swing.table;
   41   import javax.swing.plaf.basic.DragRecognitionSupport.BeforeDrag;
   42   import sun.swing.SwingUtilities2;
   43   
   44   
   45   import java.beans.PropertyChangeEvent;
   46   import java.beans.PropertyChangeListener;
   47   
   48   import sun.swing.DefaultLookup;
   49   import sun.swing.UIAction;
   50   
   51   /**
   52    * BasicTableUI implementation
   53    *
   54    * @author Philip Milne
   55    * @author Shannon Hickey (drag and drop)
   56    */
   57   public class BasicTableUI extends TableUI
   58   {
   59       private static final StringBuilder BASELINE_COMPONENT_KEY =
   60           new StringBuilder("Table.baselineComponent");
   61   
   62   //
   63   // Instance Variables
   64   //
   65   
   66       // The JTable that is delegating the painting to this UI.
   67       protected JTable table;
   68       protected CellRendererPane rendererPane;
   69   
   70       // Listeners that are attached to the JTable
   71       protected KeyListener keyListener;
   72       protected FocusListener focusListener;
   73       protected MouseInputListener mouseInputListener;
   74   
   75       private Handler handler;
   76   
   77       /**
   78        * Local cache of Table's client property "Table.isFileList"
   79        */
   80       private boolean isFileList = false;
   81   
   82   //
   83   //  Helper class for keyboard actions
   84   //
   85   
   86       private static class Actions extends UIAction {
   87           private static final String CANCEL_EDITING = "cancel";
   88           private static final String SELECT_ALL = "selectAll";
   89           private static final String CLEAR_SELECTION = "clearSelection";
   90           private static final String START_EDITING = "startEditing";
   91   
   92           private static final String NEXT_ROW = "selectNextRow";
   93           private static final String NEXT_ROW_CELL = "selectNextRowCell";
   94           private static final String NEXT_ROW_EXTEND_SELECTION =
   95                   "selectNextRowExtendSelection";
   96           private static final String NEXT_ROW_CHANGE_LEAD =
   97                   "selectNextRowChangeLead";
   98           private static final String PREVIOUS_ROW = "selectPreviousRow";
   99           private static final String PREVIOUS_ROW_CELL = "selectPreviousRowCell";
  100           private static final String PREVIOUS_ROW_EXTEND_SELECTION =
  101                   "selectPreviousRowExtendSelection";
  102           private static final String PREVIOUS_ROW_CHANGE_LEAD =
  103                   "selectPreviousRowChangeLead";
  104   
  105           private static final String NEXT_COLUMN = "selectNextColumn";
  106           private static final String NEXT_COLUMN_CELL = "selectNextColumnCell";
  107           private static final String NEXT_COLUMN_EXTEND_SELECTION =
  108                   "selectNextColumnExtendSelection";
  109           private static final String NEXT_COLUMN_CHANGE_LEAD =
  110                   "selectNextColumnChangeLead";
  111           private static final String PREVIOUS_COLUMN = "selectPreviousColumn";
  112           private static final String PREVIOUS_COLUMN_CELL =
  113                   "selectPreviousColumnCell";
  114           private static final String PREVIOUS_COLUMN_EXTEND_SELECTION =
  115                   "selectPreviousColumnExtendSelection";
  116           private static final String PREVIOUS_COLUMN_CHANGE_LEAD =
  117                   "selectPreviousColumnChangeLead";
  118   
  119           private static final String SCROLL_LEFT_CHANGE_SELECTION =
  120                   "scrollLeftChangeSelection";
  121           private static final String SCROLL_LEFT_EXTEND_SELECTION =
  122                   "scrollLeftExtendSelection";
  123           private static final String SCROLL_RIGHT_CHANGE_SELECTION =
  124                   "scrollRightChangeSelection";
  125           private static final String SCROLL_RIGHT_EXTEND_SELECTION =
  126                   "scrollRightExtendSelection";
  127   
  128           private static final String SCROLL_UP_CHANGE_SELECTION =
  129                   "scrollUpChangeSelection";
  130           private static final String SCROLL_UP_EXTEND_SELECTION =
  131                   "scrollUpExtendSelection";
  132           private static final String SCROLL_DOWN_CHANGE_SELECTION =
  133                   "scrollDownChangeSelection";
  134           private static final String SCROLL_DOWN_EXTEND_SELECTION =
  135                   "scrollDownExtendSelection";
  136   
  137           private static final String FIRST_COLUMN =
  138                   "selectFirstColumn";
  139           private static final String FIRST_COLUMN_EXTEND_SELECTION =
  140                   "selectFirstColumnExtendSelection";
  141           private static final String LAST_COLUMN =
  142                   "selectLastColumn";
  143           private static final String LAST_COLUMN_EXTEND_SELECTION =
  144                   "selectLastColumnExtendSelection";
  145   
  146           private static final String FIRST_ROW =
  147                   "selectFirstRow";
  148           private static final String FIRST_ROW_EXTEND_SELECTION =
  149                   "selectFirstRowExtendSelection";
  150           private static final String LAST_ROW =
  151                   "selectLastRow";
  152           private static final String LAST_ROW_EXTEND_SELECTION =
  153                   "selectLastRowExtendSelection";
  154   
  155           // add the lead item to the selection without changing lead or anchor
  156           private static final String ADD_TO_SELECTION = "addToSelection";
  157   
  158           // toggle the selected state of the lead item and move the anchor to it
  159           private static final String TOGGLE_AND_ANCHOR = "toggleAndAnchor";
  160   
  161           // extend the selection to the lead item
  162           private static final String EXTEND_TO = "extendTo";
  163   
  164           // move the anchor to the lead and ensure only that item is selected
  165           private static final String MOVE_SELECTION_TO = "moveSelectionTo";
  166   
  167           // give focus to the JTableHeader, if one exists
  168           private static final String FOCUS_HEADER = "focusHeader";
  169   
  170           protected int dx;
  171           protected int dy;
  172           protected boolean extend;
  173           protected boolean inSelection;
  174   
  175           // horizontally, forwards always means right,
  176           // regardless of component orientation
  177           protected boolean forwards;
  178           protected boolean vertically;
  179           protected boolean toLimit;
  180   
  181           protected int leadRow;
  182           protected int leadColumn;
  183   
  184           Actions(String name) {
  185               super(name);
  186           }
  187   
  188           Actions(String name, int dx, int dy, boolean extend,
  189                   boolean inSelection) {
  190               super(name);
  191   
  192               // Actions spcifying true for "inSelection" are
  193               // fairly sensitive to bad parameter values. They require
  194               // that one of dx and dy be 0 and the other be -1 or 1.
  195               // Bogus parameter values could cause an infinite loop.
  196               // To prevent any problems we massage the params here
  197               // and complain if we get something we can't deal with.
  198               if (inSelection) {
  199                   this.inSelection = true;
  200   
  201                   // look at the sign of dx and dy only
  202                   dx = sign(dx);
  203                   dy = sign(dy);
  204   
  205                   // make sure one is zero, but not both
  206                   assert (dx == 0 || dy == 0) && !(dx == 0 && dy == 0);
  207               }
  208   
  209               this.dx = dx;
  210               this.dy = dy;
  211               this.extend = extend;
  212           }
  213   
  214           Actions(String name, boolean extend, boolean forwards,
  215                   boolean vertically, boolean toLimit) {
  216               this(name, 0, 0, extend, false);
  217               this.forwards = forwards;
  218               this.vertically = vertically;
  219               this.toLimit = toLimit;
  220           }
  221   
  222           private static int clipToRange(int i, int a, int b) {
  223               return Math.min(Math.max(i, a), b-1);
  224           }
  225   
  226           private void moveWithinTableRange(JTable table, int dx, int dy) {
  227               leadRow = clipToRange(leadRow+dy, 0, table.getRowCount());
  228               leadColumn = clipToRange(leadColumn+dx, 0, table.getColumnCount());
  229           }
  230   
  231           private static int sign(int num) {
  232               return (num < 0) ? -1 : ((num == 0) ? 0 : 1);
  233           }
  234   
  235           /**
  236            * Called to move within the selected range of the given JTable.
  237            * This method uses the table's notion of selection, which is
  238            * important to allow the user to navigate between items visually
  239            * selected on screen. This notion may or may not be the same as
  240            * what could be determined by directly querying the selection models.
  241            * It depends on certain table properties (such as whether or not
  242            * row or column selection is allowed). When performing modifications,
  243            * it is recommended that caution be taken in order to preserve
  244            * the intent of this method, especially when deciding whether to
  245            * query the selection models or interact with JTable directly.
  246            */
  247           private boolean moveWithinSelectedRange(JTable table, int dx, int dy,
  248                   ListSelectionModel rsm, ListSelectionModel csm) {
  249   
  250               // Note: The Actions constructor ensures that only one of
  251               // dx and dy is 0, and the other is either -1 or 1
  252   
  253               // find out how many items the table is showing as selected
  254               // and the range of items to navigate through
  255               int totalCount;
  256               int minX, maxX, minY, maxY;
  257   
  258               boolean rs = table.getRowSelectionAllowed();
  259               boolean cs = table.getColumnSelectionAllowed();
  260   
  261               // both column and row selection
  262               if (rs && cs) {
  263                   totalCount = table.getSelectedRowCount() * table.getSelectedColumnCount();
  264                   minX = csm.getMinSelectionIndex();
  265                   maxX = csm.getMaxSelectionIndex();
  266                   minY = rsm.getMinSelectionIndex();
  267                   maxY = rsm.getMaxSelectionIndex();
  268               // row selection only
  269               } else if (rs) {
  270                   totalCount = table.getSelectedRowCount();
  271                   minX = 0;
  272                   maxX = table.getColumnCount() - 1;
  273                   minY = rsm.getMinSelectionIndex();
  274                   maxY = rsm.getMaxSelectionIndex();
  275               // column selection only
  276               } else if (cs) {
  277                   totalCount = table.getSelectedColumnCount();
  278                   minX = csm.getMinSelectionIndex();
  279                   maxX = csm.getMaxSelectionIndex();
  280                   minY = 0;
  281                   maxY = table.getRowCount() - 1;
  282               // no selection allowed
  283               } else {
  284                   totalCount = 0;
  285                   // A bogus assignment to stop javac from complaining
  286                   // about unitialized values. In this case, these
  287                   // won't even be used.
  288                   minX = maxX = minY = maxY = 0;
  289               }
  290   
  291               // For some cases, there is no point in trying to stay within the
  292               // selected area. Instead, move outside the selection, wrapping at
  293               // the table boundaries. The cases are:
  294               boolean stayInSelection;
  295   
  296               // - nothing selected
  297               if (totalCount == 0 ||
  298                       // - one item selected, and the lead is already selected
  299                       (totalCount == 1 && table.isCellSelected(leadRow, leadColumn))) {
  300   
  301                   stayInSelection = false;
  302   
  303                   maxX = table.getColumnCount() - 1;
  304                   maxY = table.getRowCount() - 1;
  305   
  306                   // the mins are calculated like this in case the max is -1
  307                   minX = Math.min(0, maxX);
  308                   minY = Math.min(0, maxY);
  309               } else {
  310                   stayInSelection = true;
  311               }
  312   
  313               // the algorithm below isn't prepared to deal with -1 lead/anchor
  314               // so massage appropriately here first
  315               if (dy == 1 && leadColumn == -1) {
  316                   leadColumn = minX;
  317                   leadRow = -1;
  318               } else if (dx == 1 && leadRow == -1) {
  319                   leadRow = minY;
  320                   leadColumn = -1;
  321               } else if (dy == -1 && leadColumn == -1) {
  322                   leadColumn = maxX;
  323                   leadRow = maxY + 1;
  324               } else if (dx == -1 && leadRow == -1) {
  325                   leadRow = maxY;
  326                   leadColumn = maxX + 1;
  327               }
  328   
  329               // In cases where the lead is not within the search range,
  330               // we need to bring it within one cell for the the search
  331               // to work properly. Check these here.
  332               leadRow = Math.min(Math.max(leadRow, minY - 1), maxY + 1);
  333               leadColumn = Math.min(Math.max(leadColumn, minX - 1), maxX + 1);
  334   
  335               // find the next position, possibly looping until it is selected
  336               do {
  337                   calcNextPos(dx, minX, maxX, dy, minY, maxY);
  338               } while (stayInSelection && !table.isCellSelected(leadRow, leadColumn));
  339   
  340               return stayInSelection;
  341           }
  342   
  343           /**
  344            * Find the next lead row and column based on the given
  345            * dx/dy and max/min values.
  346            */
  347           private void calcNextPos(int dx, int minX, int maxX,
  348                                    int dy, int minY, int maxY) {
  349   
  350               if (dx != 0) {
  351                   leadColumn += dx;
  352                   if (leadColumn > maxX) {
  353                       leadColumn = minX;
  354                       leadRow++;
  355                       if (leadRow > maxY) {
  356                           leadRow = minY;
  357                       }
  358                   } else if (leadColumn < minX) {
  359                       leadColumn = maxX;
  360                       leadRow--;
  361                       if (leadRow < minY) {
  362                           leadRow = maxY;
  363                       }
  364                   }
  365               } else {
  366                   leadRow += dy;
  367                   if (leadRow > maxY) {
  368                       leadRow = minY;
  369                       leadColumn++;
  370                       if (leadColumn > maxX) {
  371                           leadColumn = minX;
  372                       }
  373                   } else if (leadRow < minY) {
  374                       leadRow = maxY;
  375                       leadColumn--;
  376                       if (leadColumn < minX) {
  377                           leadColumn = maxX;
  378                       }
  379                   }
  380               }
  381           }
  382   
  383           public void actionPerformed(ActionEvent e) {
  384               String key = getName();
  385               JTable table = (JTable)e.getSource();
  386   
  387               ListSelectionModel rsm = table.getSelectionModel();
  388               leadRow = getAdjustedLead(table, true, rsm);
  389   
  390               ListSelectionModel csm = table.getColumnModel().getSelectionModel();
  391               leadColumn = getAdjustedLead(table, false, csm);
  392   
  393               if (key == SCROLL_LEFT_CHANGE_SELECTION ||        // Paging Actions
  394                       key == SCROLL_LEFT_EXTEND_SELECTION ||
  395                       key == SCROLL_RIGHT_CHANGE_SELECTION ||
  396                       key == SCROLL_RIGHT_EXTEND_SELECTION ||
  397                       key == SCROLL_UP_CHANGE_SELECTION ||
  398                       key == SCROLL_UP_EXTEND_SELECTION ||
  399                       key == SCROLL_DOWN_CHANGE_SELECTION ||
  400                       key == SCROLL_DOWN_EXTEND_SELECTION ||
  401                       key == FIRST_COLUMN ||
  402                       key == FIRST_COLUMN_EXTEND_SELECTION ||
  403                       key == FIRST_ROW ||
  404                       key == FIRST_ROW_EXTEND_SELECTION ||
  405                       key == LAST_COLUMN ||
  406                       key == LAST_COLUMN_EXTEND_SELECTION ||
  407                       key == LAST_ROW ||
  408                       key == LAST_ROW_EXTEND_SELECTION) {
  409                   if (toLimit) {
  410                       if (vertically) {
  411                           int rowCount = table.getRowCount();
  412                           this.dx = 0;
  413                           this.dy = forwards ? rowCount : -rowCount;
  414                       }
  415                       else {
  416                           int colCount = table.getColumnCount();
  417                           this.dx = forwards ? colCount : -colCount;
  418                           this.dy = 0;
  419                       }
  420                   }
  421                   else {
  422                       if (!(table.getParent().getParent() instanceof
  423                               JScrollPane)) {
  424                           return;
  425                       }
  426   
  427                       Dimension delta = table.getParent().getSize();
  428   
  429                       if (vertically) {
  430                           Rectangle r = table.getCellRect(leadRow, 0, true);
  431                           if (forwards) {
  432                               // scroll by at least one cell
  433                               r.y += Math.max(delta.height, r.height);
  434                           } else {
  435                               r.y -= delta.height;
  436                           }
  437   
  438                           this.dx = 0;
  439                           int newRow = table.rowAtPoint(r.getLocation());
  440                           if (newRow == -1 && forwards) {
  441                               newRow = table.getRowCount();
  442                           }
  443                           this.dy = newRow - leadRow;
  444                       }
  445                       else {
  446                           Rectangle r = table.getCellRect(0, leadColumn, true);
  447   
  448                           if (forwards) {
  449                               // scroll by at least one cell
  450                               r.x += Math.max(delta.width, r.width);
  451                           } else {
  452                               r.x -= delta.width;
  453                           }
  454   
  455                           int newColumn = table.columnAtPoint(r.getLocation());
  456                           if (newColumn == -1) {
  457                               boolean ltr = table.getComponentOrientation().isLeftToRight();
  458   
  459                               newColumn = forwards ? (ltr ? table.getColumnCount() : 0)
  460                                                    : (ltr ? 0 : table.getColumnCount());
  461   
  462                           }
  463                           this.dx = newColumn - leadColumn;
  464                           this.dy = 0;
  465                       }
  466                   }
  467               }
  468               if (key == NEXT_ROW ||  // Navigate Actions
  469                       key == NEXT_ROW_CELL ||
  470                       key == NEXT_ROW_EXTEND_SELECTION ||
  471                       key == NEXT_ROW_CHANGE_LEAD ||
  472                       key == NEXT_COLUMN ||
  473                       key == NEXT_COLUMN_CELL ||
  474                       key == NEXT_COLUMN_EXTEND_SELECTION ||
  475                       key == NEXT_COLUMN_CHANGE_LEAD ||
  476                       key == PREVIOUS_ROW ||
  477                       key == PREVIOUS_ROW_CELL ||
  478                       key == PREVIOUS_ROW_EXTEND_SELECTION ||
  479                       key == PREVIOUS_ROW_CHANGE_LEAD ||
  480                       key == PREVIOUS_COLUMN ||
  481                       key == PREVIOUS_COLUMN_CELL ||
  482                       key == PREVIOUS_COLUMN_EXTEND_SELECTION ||
  483                       key == PREVIOUS_COLUMN_CHANGE_LEAD ||
  484                       // Paging Actions.
  485                       key == SCROLL_LEFT_CHANGE_SELECTION ||
  486                       key == SCROLL_LEFT_EXTEND_SELECTION ||
  487                       key == SCROLL_RIGHT_CHANGE_SELECTION ||
  488                       key == SCROLL_RIGHT_EXTEND_SELECTION ||
  489                       key == SCROLL_UP_CHANGE_SELECTION ||
  490                       key == SCROLL_UP_EXTEND_SELECTION ||
  491                       key == SCROLL_DOWN_CHANGE_SELECTION ||
  492                       key == SCROLL_DOWN_EXTEND_SELECTION ||
  493                       key == FIRST_COLUMN ||
  494                       key == FIRST_COLUMN_EXTEND_SELECTION ||
  495                       key == FIRST_ROW ||
  496                       key == FIRST_ROW_EXTEND_SELECTION ||
  497                       key == LAST_COLUMN ||
  498                       key == LAST_COLUMN_EXTEND_SELECTION ||
  499                       key == LAST_ROW ||
  500                       key == LAST_ROW_EXTEND_SELECTION) {
  501   
  502                   if (table.isEditing() &&
  503                           !table.getCellEditor().stopCellEditing()) {
  504                       return;
  505                   }
  506   
  507                   // Unfortunately, this strategy introduces bugs because
  508                   // of the asynchronous nature of requestFocus() call below.
  509                   // Introducing a delay with invokeLater() makes this work
  510                   // in the typical case though race conditions then allow
  511                   // focus to disappear altogether. The right solution appears
  512                   // to be to fix requestFocus() so that it queues a request
  513                   // for the focus regardless of who owns the focus at the
  514                   // time the call to requestFocus() is made. The optimisation
  515                   // to ignore the call to requestFocus() when the component
  516                   // already has focus may ligitimately be made as the
  517                   // request focus event is dequeued, not before.
  518   
  519                   // boolean wasEditingWithFocus = table.isEditing() &&
  520                   // table.getEditorComponent().isFocusOwner();
  521   
  522                   boolean changeLead = false;
  523                   if (key == NEXT_ROW_CHANGE_LEAD || key == PREVIOUS_ROW_CHANGE_LEAD) {
  524                       changeLead = (rsm.getSelectionMode()
  525                                        == ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
  526                   } else if (key == NEXT_COLUMN_CHANGE_LEAD || key == PREVIOUS_COLUMN_CHANGE_LEAD) {
  527                       changeLead = (csm.getSelectionMode()
  528                                        == ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
  529                   }
  530   
  531                   if (changeLead) {
  532                       moveWithinTableRange(table, dx, dy);
  533                       if (dy != 0) {
  534                           // casting should be safe since the action is only enabled
  535                           // for DefaultListSelectionModel
  536                           ((DefaultListSelectionModel)rsm).moveLeadSelectionIndex(leadRow);
  537                           if (getAdjustedLead(table, false, csm) == -1
  538                                   && table.getColumnCount() > 0) {
  539   
  540                               ((DefaultListSelectionModel)csm).moveLeadSelectionIndex(0);
  541                           }
  542                       } else {
  543                           // casting should be safe since the action is only enabled
  544                           // for DefaultListSelectionModel
  545                           ((DefaultListSelectionModel)csm).moveLeadSelectionIndex(leadColumn);
  546                           if (getAdjustedLead(table, true, rsm) == -1
  547                                   && table.getRowCount() > 0) {
  548   
  549                               ((DefaultListSelectionModel)rsm).moveLeadSelectionIndex(0);
  550                           }
  551                       }
  552   
  553                       Rectangle cellRect = table.getCellRect(leadRow, leadColumn, false);
  554                       if (cellRect != null) {
  555                           table.scrollRectToVisible(cellRect);
  556                       }
  557                   } else if (!inSelection) {
  558                       moveWithinTableRange(table, dx, dy);
  559                       table.changeSelection(leadRow, leadColumn, false, extend);
  560                   }
  561                   else {
  562                       if (table.getRowCount() <= 0 || table.getColumnCount() <= 0) {
  563                           // bail - don't try to move selection on an empty table
  564                           return;
  565                       }
  566   
  567                       if (moveWithinSelectedRange(table, dx, dy, rsm, csm)) {
  568                           // this is the only way we have to set both the lead
  569                           // and the anchor without changing the selection
  570                           if (rsm.isSelectedIndex(leadRow)) {
  571                               rsm.addSelectionInterval(leadRow, leadRow);
  572                           } else {
  573                               rsm.removeSelectionInterval(leadRow, leadRow);
  574                           }
  575   
  576                           if (csm.isSelectedIndex(leadColumn)) {
  577                               csm.addSelectionInterval(leadColumn, leadColumn);
  578                           } else {
  579                               csm.removeSelectionInterval(leadColumn, leadColumn);
  580                           }
  581   
  582                           Rectangle cellRect = table.getCellRect(leadRow, leadColumn, false);
  583                           if (cellRect != null) {
  584                               table.scrollRectToVisible(cellRect);
  585                           }
  586                       }
  587                       else {
  588                           table.changeSelection(leadRow, leadColumn,
  589                                   false, false);
  590                       }
  591                   }
  592   
  593                   /*
  594                   if (wasEditingWithFocus) {
  595                       table.editCellAt(leadRow, leadColumn);
  596                       final Component editorComp = table.getEditorComponent();
  597                       if (editorComp != null) {
  598                           SwingUtilities.invokeLater(new Runnable() {
  599                               public void run() {
  600                                   editorComp.requestFocus();
  601                               }
  602                           });
  603                       }
  604                   }
  605                   */
  606               } else if (key == CANCEL_EDITING) {
  607                   table.removeEditor();
  608               } else if (key == SELECT_ALL) {
  609                   table.selectAll();
  610               } else if (key == CLEAR_SELECTION) {
  611                   table.clearSelection();
  612               } else if (key == START_EDITING) {
  613                   if (!table.hasFocus()) {
  614                       CellEditor cellEditor = table.getCellEditor();
  615                       if (cellEditor != null && !cellEditor.stopCellEditing()) {
  616                           return;
  617                       }
  618                       table.requestFocus();
  619                       return;
  620                   }
  621                   table.editCellAt(leadRow, leadColumn, e);
  622                   Component editorComp = table.getEditorComponent();
  623                   if (editorComp != null) {
  624                       editorComp.requestFocus();
  625                   }
  626               } else if (key == ADD_TO_SELECTION) {
  627                   if (!table.isCellSelected(leadRow, leadColumn)) {
  628                       int oldAnchorRow = rsm.getAnchorSelectionIndex();
  629                       int oldAnchorColumn = csm.getAnchorSelectionIndex();
  630                       rsm.setValueIsAdjusting(true);
  631                       csm.setValueIsAdjusting(true);
  632                       table.changeSelection(leadRow, leadColumn, true, false);
  633                       rsm.setAnchorSelectionIndex(oldAnchorRow);
  634                       csm.setAnchorSelectionIndex(oldAnchorColumn);
  635                       rsm.setValueIsAdjusting(false);
  636                       csm.setValueIsAdjusting(false);
  637                   }
  638               } else if (key == TOGGLE_AND_ANCHOR) {
  639                   table.changeSelection(leadRow, leadColumn, true, false);
  640               } else if (key == EXTEND_TO) {
  641                   table.changeSelection(leadRow, leadColumn, false, true);
  642               } else if (key == MOVE_SELECTION_TO) {
  643                   table.changeSelection(leadRow, leadColumn, false, false);
  644               } else if (key == FOCUS_HEADER) {
  645                   JTableHeader th = table.getTableHeader();
  646                   if (th != null) {
  647                       //Set the header's selected column to match the table.
  648                       int col = table.getSelectedColumn();
  649                       if (col >= 0) {
  650                           TableHeaderUI thUI = th.getUI();
  651                           if (thUI instanceof BasicTableHeaderUI) {
  652                               ((BasicTableHeaderUI)thUI).selectColumn(col);
  653                           }
  654                       }
  655   
  656                       //Then give the header the focus.
  657                       th.requestFocusInWindow();
  658                   }
  659               }
  660           }
  661   
  662           public boolean isEnabled(Object sender) {
  663               String key = getName();
  664   
  665               if (sender instanceof JTable &&
  666                   Boolean.TRUE.equals(((JTable)sender).getClientProperty("Table.isFileList"))) {
  667                   if (key == NEXT_COLUMN ||
  668                           key == NEXT_COLUMN_CELL ||
  669                           key == NEXT_COLUMN_EXTEND_SELECTION ||
  670                           key == NEXT_COLUMN_CHANGE_LEAD ||
  671                           key == PREVIOUS_COLUMN ||
  672                           key == PREVIOUS_COLUMN_CELL ||
  673                           key == PREVIOUS_COLUMN_EXTEND_SELECTION ||
  674                           key == PREVIOUS_COLUMN_CHANGE_LEAD ||
  675                           key == SCROLL_LEFT_CHANGE_SELECTION ||
  676                           key == SCROLL_LEFT_EXTEND_SELECTION ||
  677                           key == SCROLL_RIGHT_CHANGE_SELECTION ||
  678                           key == SCROLL_RIGHT_EXTEND_SELECTION ||
  679                           key == FIRST_COLUMN ||
  680                           key == FIRST_COLUMN_EXTEND_SELECTION ||
  681                           key == LAST_COLUMN ||
  682                           key == LAST_COLUMN_EXTEND_SELECTION ||
  683                           key == NEXT_ROW_CELL ||
  684                           key == PREVIOUS_ROW_CELL) {
  685   
  686                       return false;
  687                   }
  688               }
  689   
  690               if (key == CANCEL_EDITING && sender instanceof JTable) {
  691                   return ((JTable)sender).isEditing();
  692               } else if (key == NEXT_ROW_CHANGE_LEAD ||
  693                          key == PREVIOUS_ROW_CHANGE_LEAD) {
  694                   // discontinuous selection actions are only enabled for
  695                   // DefaultListSelectionModel
  696                   return sender != null &&
  697                          ((JTable)sender).getSelectionModel()
  698                              instanceof DefaultListSelectionModel;
  699               } else if (key == NEXT_COLUMN_CHANGE_LEAD ||
  700                          key == PREVIOUS_COLUMN_CHANGE_LEAD) {
  701                   // discontinuous selection actions are only enabled for
  702                   // DefaultListSelectionModel
  703                   return sender != null &&
  704                          ((JTable)sender).getColumnModel().getSelectionModel()
  705                              instanceof DefaultListSelectionModel;
  706               } else if (key == ADD_TO_SELECTION && sender instanceof JTable) {
  707                   // This action is typically bound to SPACE.
  708                   // If the table is already in an editing mode, SPACE should
  709                   // simply enter a space character into the table, and not
  710                   // select a cell. Likewise, if the lead cell is already selected
  711                   // then hitting SPACE should just enter a space character
  712                   // into the cell and begin editing. In both of these cases
  713                   // this action will be disabled.
  714                   JTable table = (JTable)sender;
  715                   int leadRow = getAdjustedLead(table, true);
  716                   int leadCol = getAdjustedLead(table, false);
  717                   return !(table.isEditing() || table.isCellSelected(leadRow, leadCol));
  718               } else if (key == FOCUS_HEADER && sender instanceof JTable) {
  719                   JTable table = (JTable)sender;
  720                   return table.getTableHeader() != null;
  721               }
  722   
  723               return true;
  724           }
  725       }
  726   
  727   
  728   //
  729   //  The Table's Key listener
  730   //
  731   
  732       /**
  733        * This class should be treated as a &quot;protected&quot; inner class.
  734        * Instantiate it only within subclasses of {@code BasicTableUI}.
  735        * <p>As of Java 2 platform v1.3 this class is no longer used.
  736        * Instead <code>JTable</code>
  737        * overrides <code>processKeyBinding</code> to dispatch the event to
  738        * the current <code>TableCellEditor</code>.
  739        */
  740        public class KeyHandler implements KeyListener {
  741           // NOTE: This class exists only for backward compatability. All
  742           // its functionality has been moved into Handler. If you need to add
  743           // new functionality add it to the Handler, but make sure this
  744           // class calls into the Handler.
  745           public void keyPressed(KeyEvent e) {
  746               getHandler().keyPressed(e);
  747           }
  748   
  749           public void keyReleased(KeyEvent e) {
  750               getHandler().keyReleased(e);
  751           }
  752   
  753           public void keyTyped(KeyEvent e) {
  754               getHandler().keyTyped(e);
  755           }
  756       }
  757   
  758   //
  759   //  The Table's focus listener
  760   //
  761   
  762       /**
  763        * This class should be treated as a &quot;protected&quot; inner class.
  764        * Instantiate it only within subclasses of {@code BasicTableUI}.
  765        */
  766       public class FocusHandler implements FocusListener {
  767           // NOTE: This class exists only for backward compatability. All
  768           // its functionality has been moved into Handler. If you need to add
  769           // new functionality add it to the Handler, but make sure this
  770           // class calls into the Handler.
  771           public void focusGained(FocusEvent e) {
  772               getHandler().focusGained(e);
  773           }
  774   
  775           public void focusLost(FocusEvent e) {
  776               getHandler().focusLost(e);
  777           }
  778       }
  779   
  780   //
  781   //  The Table's mouse and mouse motion listeners
  782   //
  783   
  784       /**
  785        * This class should be treated as a &quot;protected&quot; inner class.
  786        * Instantiate it only within subclasses of BasicTableUI.
  787        */
  788       public class MouseInputHandler implements MouseInputListener {
  789           // NOTE: This class exists only for backward compatability. All
  790           // its functionality has been moved into Handler. If you need to add
  791           // new functionality add it to the Handler, but make sure this
  792           // class calls into the Handler.
  793           public void mouseClicked(MouseEvent e) {
  794               getHandler().mouseClicked(e);
  795           }
  796   
  797           public void mousePressed(MouseEvent e) {
  798               getHandler().mousePressed(e);
  799           }
  800   
  801           public void mouseReleased(MouseEvent e) {
  802               getHandler().mouseReleased(e);
  803           }
  804   
  805           public void mouseEntered(MouseEvent e) {
  806               getHandler().mouseEntered(e);
  807           }
  808   
  809           public void mouseExited(MouseEvent e) {
  810               getHandler().mouseExited(e);
  811           }
  812   
  813           public void mouseMoved(MouseEvent e) {
  814               getHandler().mouseMoved(e);
  815           }
  816   
  817           public void mouseDragged(MouseEvent e) {
  818               getHandler().mouseDragged(e);
  819           }
  820       }
  821   
  822       private class Handler implements FocusListener, MouseInputListener,
  823               PropertyChangeListener, ListSelectionListener, ActionListener,
  824               BeforeDrag {
  825   
  826           // FocusListener
  827           private void repaintLeadCell( ) {
  828               int lr = getAdjustedLead(table, true);
  829               int lc = getAdjustedLead(table, false);
  830   
  831               if (lr < 0 || lc < 0) {
  832                   return;
  833               }
  834   
  835               Rectangle dirtyRect = table.getCellRect(lr, lc, false);
  836               table.repaint(dirtyRect);
  837           }
  838   
  839           public void focusGained(FocusEvent e) {
  840               repaintLeadCell();
  841           }
  842   
  843           public void focusLost(FocusEvent e) {
  844               repaintLeadCell();
  845           }
  846   
  847   
  848           // KeyListener
  849           public void keyPressed(KeyEvent e) { }
  850   
  851           public void keyReleased(KeyEvent e) { }
  852   
  853           public void keyTyped(KeyEvent e) {
  854               KeyStroke keyStroke = KeyStroke.getKeyStroke(e.getKeyChar(),
  855                       e.getModifiers());
  856   
  857               // We register all actions using ANCESTOR_OF_FOCUSED_COMPONENT
  858               // which means that we might perform the appropriate action
  859               // in the table and then forward it to the editor if the editor
  860               // had focus. Make sure this doesn't happen by checking our
  861               // InputMaps.
  862               InputMap map = table.getInputMap(JComponent.WHEN_FOCUSED);
  863               if (map != null && map.get(keyStroke) != null) {
  864                   return;
  865               }
  866               map = table.getInputMap(JComponent.
  867                                     WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  868               if (map != null && map.get(keyStroke) != null) {
  869                   return;
  870               }
  871   
  872               keyStroke = KeyStroke.getKeyStrokeForEvent(e);
  873   
  874               // The AWT seems to generate an unconsumed \r event when
  875               // ENTER (\n) is pressed.
  876               if (e.getKeyChar() == '\r') {
  877                   return;
  878               }
  879   
  880               int leadRow = getAdjustedLead(table, true);
  881               int leadColumn = getAdjustedLead(table, false);
  882               if (leadRow != -1 && leadColumn != -1 && !table.isEditing()) {
  883                   if (!table.editCellAt(leadRow, leadColumn)) {
  884                       return;
  885                   }
  886               }
  887   
  888               // Forwarding events this way seems to put the component
  889               // in a state where it believes it has focus. In reality
  890               // the table retains focus - though it is difficult for
  891               // a user to tell, since the caret is visible and flashing.
  892   
  893               // Calling table.requestFocus() here, to get the focus back to
  894               // the table, seems to have no effect.
  895   
  896               Component editorComp = table.getEditorComponent();
  897               if (table.isEditing() && editorComp != null) {
  898                   if (editorComp instanceof JComponent) {
  899                       JComponent component = (JComponent)editorComp;
  900                       map = component.getInputMap(JComponent.WHEN_FOCUSED);
  901                       Object binding = (map != null) ? map.get(keyStroke) : null;
  902                       if (binding == null) {
  903                           map = component.getInputMap(JComponent.
  904                                            WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  905                           binding = (map != null) ? map.get(keyStroke) : null;
  906                       }
  907                       if (binding != null) {
  908                           ActionMap am = component.getActionMap();
  909                           Action action = (am != null) ? am.get(binding) : null;
  910                           if (action != null && SwingUtilities.
  911                               notifyAction(action, keyStroke, e, component,
  912                                            e.getModifiers())) {
  913                               e.consume();
  914                           }
  915                       }
  916                   }
  917               }
  918           }
  919   
  920   
  921           // MouseInputListener
  922   
  923           // Component receiving mouse events during editing.
  924           // May not be editorComponent.
  925           private Component dispatchComponent;
  926   
  927           public void mouseClicked(MouseEvent e) {}
  928   
  929           private void setDispatchComponent(MouseEvent e) {
  930               Component editorComponent = table.getEditorComponent();
  931               Point p = e.getPoint();
  932               Point p2 = SwingUtilities.convertPoint(table, p, editorComponent);
  933               dispatchComponent =
  934                       SwingUtilities.getDeepestComponentAt(editorComponent,
  935                               p2.x, p2.y);
  936               SwingUtilities2.setSkipClickCount(dispatchComponent,
  937                                                 e.getClickCount() - 1);
  938           }
  939   
  940           private boolean repostEvent(MouseEvent e) {
  941               // Check for isEditing() in case another event has
  942               // caused the editor to be removed. See bug #4306499.
  943               if (dispatchComponent == null || !table.isEditing()) {
  944                   return false;
  945               }
  946               MouseEvent e2 = SwingUtilities.convertMouseEvent(table, e,
  947                       dispatchComponent);
  948               dispatchComponent.dispatchEvent(e2);
  949               return true;
  950           }
  951   
  952           private void setValueIsAdjusting(boolean flag) {
  953               table.getSelectionModel().setValueIsAdjusting(flag);
  954               table.getColumnModel().getSelectionModel().
  955                       setValueIsAdjusting(flag);
  956           }
  957   
  958           // The row and column where the press occurred and the
  959           // press event itself
  960           private int pressedRow;
  961           private int pressedCol;
  962           private MouseEvent pressedEvent;
  963   
  964           // Whether or not the mouse press (which is being considered as part
  965           // of a drag sequence) also caused the selection change to be fully
  966           // processed.
  967           private boolean dragPressDidSelection;
  968   
  969           // Set to true when a drag gesture has been fully recognized and DnD
  970           // begins. Use this to ignore further mouse events which could be
  971           // delivered if DnD is cancelled (via ESCAPE for example)
  972           private boolean dragStarted;
  973   
  974           // Whether or not we should start the editing timer on release
  975           private boolean shouldStartTimer;
  976   
  977           // To cache the return value of pointOutsidePrefSize since we use
  978           // it multiple times.
  979           private boolean outsidePrefSize;
  980   
  981           // Used to delay the start of editing.
  982           private Timer timer = null;
  983   
  984           private boolean canStartDrag() {
  985               if (pressedRow == -1 || pressedCol == -1) {
  986                   return false;
  987               }
  988   
  989               if (isFileList) {
  990                   return !outsidePrefSize;
  991               }
  992   
  993               // if this is a single selection table
  994               if ((table.getSelectionModel().getSelectionMode() ==
  995                        ListSelectionModel.SINGLE_SELECTION) &&
  996                   (table.getColumnModel().getSelectionModel().getSelectionMode() ==
  997                        ListSelectionModel.SINGLE_SELECTION)) {
  998   
  999                   return true;
 1000               }
 1001   
 1002               return table.isCellSelected(pressedRow, pressedCol);
 1003           }
 1004   
 1005           public void mousePressed(MouseEvent e) {
 1006               if (SwingUtilities2.shouldIgnore(e, table)) {
 1007                   return;
 1008               }
 1009   
 1010               if (table.isEditing() && !table.getCellEditor().stopCellEditing()) {
 1011                   Component editorComponent = table.getEditorComponent();
 1012                   if (editorComponent != null && !editorComponent.hasFocus()) {
 1013                       SwingUtilities2.compositeRequestFocus(editorComponent);
 1014                   }
 1015                   return;
 1016               }
 1017   
 1018               Point p = e.getPoint();
 1019               pressedRow = table.rowAtPoint(p);
 1020               pressedCol = table.columnAtPoint(p);
 1021               outsidePrefSize = pointOutsidePrefSize(pressedRow, pressedCol, p);
 1022   
 1023               if (isFileList) {
 1024                   shouldStartTimer =
 1025                       table.isCellSelected(pressedRow, pressedCol) &&
 1026                       !e.isShiftDown() &&
 1027                       !BasicGraphicsUtils.isMenuShortcutKeyDown(e) &&
 1028                       !outsidePrefSize;
 1029               }
 1030   
 1031               if (table.getDragEnabled()) {
 1032                   mousePressedDND(e);
 1033               } else {
 1034                   SwingUtilities2.adjustFocus(table);
 1035                   if (!isFileList) {
 1036                       setValueIsAdjusting(true);
 1037                   }
 1038                   adjustSelection(e);
 1039               }
 1040           }
 1041   
 1042           private void mousePressedDND(MouseEvent e) {
 1043               pressedEvent = e;
 1044               boolean grabFocus = true;
 1045               dragStarted = false;
 1046   
 1047               if (canStartDrag() && DragRecognitionSupport.mousePressed(e)) {
 1048   
 1049                   dragPressDidSelection = false;
 1050   
 1051                   if (BasicGraphicsUtils.isMenuShortcutKeyDown(e) && isFileList) {
 1052                       // do nothing for control - will be handled on release
 1053                       // or when drag starts
 1054                       return;
 1055                   } else if (!e.isShiftDown() && table.isCellSelected(pressedRow, pressedCol)) {
 1056                       // clicking on something that's already selected
 1057                       // and need to make it the lead now
 1058                       table.getSelectionModel().addSelectionInterval(pressedRow,
 1059                                                                      pressedRow);
 1060                       table.getColumnModel().getSelectionModel().
 1061                           addSelectionInterval(pressedCol, pressedCol);
 1062   
 1063                       return;
 1064                   }
 1065   
 1066                   dragPressDidSelection = true;
 1067   
 1068                   // could be a drag initiating event - don't grab focus
 1069                   grabFocus = false;
 1070               } else if (!isFileList) {
 1071                   // When drag can't happen, mouse drags might change the selection in the table
 1072                   // so we want the isAdjusting flag to be set
 1073                   setValueIsAdjusting(true);
 1074               }
 1075   
 1076               if (grabFocus) {
 1077                   SwingUtilities2.adjustFocus(table);
 1078               }
 1079   
 1080               adjustSelection(e);
 1081           }
 1082   
 1083           private void adjustSelection(MouseEvent e) {
 1084               // Fix for 4835633
 1085               if (outsidePrefSize) {
 1086                   // If shift is down in multi-select, we should just return.
 1087                   // For single select or non-shift-click, clear the selection
 1088                   if (e.getID() ==  MouseEvent.MOUSE_PRESSED &&
 1089                       (!e.isShiftDown() ||
 1090                        table.getSelectionModel().getSelectionMode() ==
 1091                        ListSelectionModel.SINGLE_SELECTION)) {
 1092                       table.clearSelection();
 1093                       TableCellEditor tce = table.getCellEditor();
 1094                       if (tce != null) {
 1095                           tce.stopCellEditing();
 1096                       }
 1097                   }
 1098                   return;
 1099               }
 1100               // The autoscroller can generate drag events outside the
 1101               // table's range.
 1102               if ((pressedCol == -1) || (pressedRow == -1)) {
 1103                   return;
 1104               }
 1105   
 1106               boolean dragEnabled = table.getDragEnabled();
 1107   
 1108               if (!dragEnabled && !isFileList && table.editCellAt(pressedRow, pressedCol, e)) {
 1109                   setDispatchComponent(e);
 1110                   repostEvent(e);
 1111               }
 1112   
 1113               CellEditor editor = table.getCellEditor();
 1114               if (dragEnabled || editor == null || editor.shouldSelectCell(e)) {
 1115                   table.changeSelection(pressedRow, pressedCol,
 1116                           BasicGraphicsUtils.isMenuShortcutKeyDown(e),
 1117                           e.isShiftDown());
 1118               }
 1119           }
 1120   
 1121           public void valueChanged(ListSelectionEvent e) {
 1122               if (timer != null) {
 1123                   timer.stop();
 1124                   timer = null;
 1125               }
 1126           }
 1127   
 1128           public void actionPerformed(ActionEvent ae) {
 1129               table.editCellAt(pressedRow, pressedCol, null);
 1130               Component editorComponent = table.getEditorComponent();
 1131               if (editorComponent != null && !editorComponent.hasFocus()) {
 1132                   SwingUtilities2.compositeRequestFocus(editorComponent);
 1133               }
 1134               return;
 1135           }
 1136   
 1137           private void maybeStartTimer() {
 1138               if (!shouldStartTimer) {
 1139                   return;
 1140               }
 1141   
 1142               if (timer == null) {
 1143                   timer = new Timer(1200, this);
 1144                   timer.setRepeats(false);
 1145               }
 1146   
 1147               timer.start();
 1148           }
 1149   
 1150           public void mouseReleased(MouseEvent e) {
 1151               if (SwingUtilities2.shouldIgnore(e, table)) {
 1152                   return;
 1153               }
 1154   
 1155               if (table.getDragEnabled()) {
 1156                   mouseReleasedDND(e);
 1157               } else {
 1158                   if (isFileList) {
 1159                       maybeStartTimer();
 1160                   }
 1161               }
 1162   
 1163               pressedEvent = null;
 1164               repostEvent(e);
 1165               dispatchComponent = null;
 1166               setValueIsAdjusting(false);
 1167           }
 1168   
 1169           private void mouseReleasedDND(MouseEvent e) {
 1170               MouseEvent me = DragRecognitionSupport.mouseReleased(e);
 1171               if (me != null) {
 1172                   SwingUtilities2.adjustFocus(table);
 1173                   if (!dragPressDidSelection) {
 1174                       adjustSelection(me);
 1175                   }
 1176               }
 1177   
 1178               if (!dragStarted) {
 1179                   if (isFileList) {
 1180                       maybeStartTimer();
 1181                       return;
 1182                   }
 1183   
 1184                   Point p = e.getPoint();
 1185   
 1186                   if (pressedEvent != null &&
 1187                           table.rowAtPoint(p) == pressedRow &&
 1188                           table.columnAtPoint(p) == pressedCol &&
 1189                           table.editCellAt(pressedRow, pressedCol, pressedEvent)) {
 1190   
 1191                       setDispatchComponent(pressedEvent);
 1192                       repostEvent(pressedEvent);
 1193   
 1194                       // This may appear completely odd, but must be done for backward
 1195                       // compatibility reasons. Developers have been known to rely on
 1196                       // a call to shouldSelectCell after editing has begun.
 1197                       CellEditor ce = table.getCellEditor();
 1198                       if (ce != null) {
 1199                           ce.shouldSelectCell(pressedEvent);
 1200                       }
 1201                   }
 1202               }
 1203           }
 1204   
 1205           public void mouseEntered(MouseEvent e) {}
 1206   
 1207           public void mouseExited(MouseEvent e) {}
 1208   
 1209           public void mouseMoved(MouseEvent e) {}
 1210   
 1211           public void dragStarting(MouseEvent me) {
 1212               dragStarted = true;
 1213   
 1214               if (BasicGraphicsUtils.isMenuShortcutKeyDown(me) && isFileList) {
 1215                   table.getSelectionModel().addSelectionInterval(pressedRow,
 1216                                                                  pressedRow);
 1217                   table.getColumnModel().getSelectionModel().
 1218                       addSelectionInterval(pressedCol, pressedCol);
 1219               }
 1220   
 1221               pressedEvent = null;
 1222           }
 1223   
 1224           public void mouseDragged(MouseEvent e) {
 1225               if (SwingUtilities2.shouldIgnore(e, table)) {
 1226                   return;
 1227               }
 1228   
 1229               if (table.getDragEnabled() &&
 1230                       (DragRecognitionSupport.mouseDragged(e, this) || dragStarted)) {
 1231   
 1232                   return;
 1233               }
 1234   
 1235               repostEvent(e);
 1236   
 1237               // Check isFileList:
 1238               // Until we support drag-selection, dragging should not change
 1239               // the selection (act like single-select).
 1240               if (isFileList || table.isEditing()) {
 1241                   return;
 1242               }
 1243   
 1244               Point p = e.getPoint();
 1245               int row = table.rowAtPoint(p);
 1246               int column = table.columnAtPoint(p);
 1247               // The autoscroller can generate drag events outside the
 1248               // table's range.
 1249               if ((column == -1) || (row == -1)) {
 1250                   return;
 1251               }
 1252   
 1253               table.changeSelection(row, column,
 1254                       BasicGraphicsUtils.isMenuShortcutKeyDown(e), true);
 1255           }
 1256   
 1257   
 1258           // PropertyChangeListener
 1259           public void propertyChange(PropertyChangeEvent event) {
 1260               String changeName = event.getPropertyName();
 1261   
 1262               if ("componentOrientation" == changeName) {
 1263                   InputMap inputMap = getInputMap(
 1264                       JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
 1265   
 1266                   SwingUtilities.replaceUIInputMap(table,
 1267                       JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
 1268                       inputMap);
 1269   
 1270                   JTableHeader header = table.getTableHeader();
 1271                   if (header != null) {
 1272                       header.setComponentOrientation(
 1273                               (ComponentOrientation)event.getNewValue());
 1274                   }
 1275               } else if ("dropLocation" == changeName) {
 1276                   JTable.DropLocation oldValue = (JTable.DropLocation)event.getOldValue();
 1277                   repaintDropLocation(oldValue);
 1278                   repaintDropLocation(table.getDropLocation());
 1279               } else if ("Table.isFileList" == changeName) {
 1280                   isFileList = Boolean.TRUE.equals(table.getClientProperty("Table.isFileList"));
 1281                   table.revalidate();
 1282                   table.repaint();
 1283                   if (isFileList) {
 1284                       table.getSelectionModel().addListSelectionListener(getHandler());
 1285                   } else {
 1286                       table.getSelectionModel().removeListSelectionListener(getHandler());
 1287                       timer = null;
 1288                   }
 1289               } else if ("selectionModel" == changeName) {
 1290                   if (isFileList) {
 1291                       ListSelectionModel old = (ListSelectionModel)event.getOldValue();
 1292                       old.removeListSelectionListener(getHandler());
 1293                       table.getSelectionModel().addListSelectionListener(getHandler());
 1294                   }
 1295               }
 1296           }
 1297   
 1298           private void repaintDropLocation(JTable.DropLocation loc) {
 1299               if (loc == null) {
 1300                   return;
 1301               }
 1302   
 1303               if (!loc.isInsertRow() && !loc.isInsertColumn()) {
 1304                   Rectangle rect = table.getCellRect(loc.getRow(), loc.getColumn(), false);
 1305                   if (rect != null) {
 1306                       table.repaint(rect);
 1307                   }
 1308                   return;
 1309               }
 1310   
 1311               if (loc.isInsertRow()) {
 1312                   Rectangle rect = extendRect(getHDropLineRect(loc), true);
 1313                   if (rect != null) {
 1314                       table.repaint(rect);
 1315                   }
 1316               }
 1317   
 1318               if (loc.isInsertColumn()) {
 1319                   Rectangle rect = extendRect(getVDropLineRect(loc), false);
 1320                   if (rect != null) {
 1321                       table.repaint(rect);
 1322                   }
 1323               }
 1324           }
 1325       }
 1326   
 1327   
 1328       /*
 1329        * Returns true if the given point is outside the preferredSize of the
 1330        * item at the given row of the table.  (Column must be 0).
 1331        * Returns false if the "Table.isFileList" client property is not set.
 1332        */
 1333       private boolean pointOutsidePrefSize(int row, int column, Point p) {
 1334           if (!isFileList) {
 1335               return false;
 1336           }
 1337   
 1338           return SwingUtilities2.pointOutsidePrefSize(table, row, column, p);
 1339       }
 1340   
 1341   //
 1342   //  Factory methods for the Listeners
 1343   //
 1344   
 1345       private Handler getHandler() {
 1346           if (handler == null) {
 1347               handler = new Handler();
 1348           }
 1349           return handler;
 1350       }
 1351   
 1352       /**
 1353        * Creates the key listener for handling keyboard navigation in the JTable.
 1354        */
 1355       protected KeyListener createKeyListener() {
 1356           return null;
 1357       }
 1358   
 1359       /**
 1360        * Creates the focus listener for handling keyboard navigation in the JTable.
 1361        */
 1362       protected FocusListener createFocusListener() {
 1363           return getHandler();
 1364       }
 1365   
 1366       /**
 1367        * Creates the mouse listener for the JTable.
 1368        */
 1369       protected MouseInputListener createMouseInputListener() {
 1370           return getHandler();
 1371       }
 1372   
 1373   //
 1374   //  The installation/uninstall procedures and support
 1375   //
 1376   
 1377       public static ComponentUI createUI(JComponent c) {
 1378           return new BasicTableUI();
 1379       }
 1380   
 1381   //  Installation
 1382   
 1383       public void installUI(JComponent c) {
 1384           table = (JTable)c;
 1385   
 1386           rendererPane = new CellRendererPane();
 1387           table.add(rendererPane);
 1388           installDefaults();
 1389           installDefaults2();
 1390           installListeners();
 1391           installKeyboardActions();
 1392       }
 1393   
 1394       /**
 1395        * Initialize JTable properties, e.g. font, foreground, and background.
 1396        * The font, foreground, and background properties are only set if their
 1397        * current value is either null or a UIResource, other properties are set
 1398        * if the current value is null.
 1399        *
 1400        * @see #installUI
 1401        */
 1402       protected void installDefaults() {
 1403           LookAndFeel.installColorsAndFont(table, "Table.background",
 1404                                            "Table.foreground", "Table.font");
 1405           // JTable's original row height is 16.  To correctly display the
 1406           // contents on Linux we should have set it to 18, Windows 19 and
 1407           // Solaris 20.  As these values vary so much it's too hard to
 1408           // be backward compatable and try to update the row height, we're
 1409           // therefor NOT going to adjust the row height based on font.  If the
 1410           // developer changes the font, it's there responsability to update
 1411           // the row height.
 1412   
 1413           LookAndFeel.installProperty(table, "opaque", Boolean.TRUE);
 1414   
 1415           Color sbg = table.getSelectionBackground();
 1416           if (sbg == null || sbg instanceof UIResource) {
 1417               sbg = UIManager.getColor("Table.selectionBackground");
 1418               table.setSelectionBackground(sbg != null ? sbg : UIManager.getColor("textHighlight"));
 1419           }
 1420   
 1421           Color sfg = table.getSelectionForeground();
 1422           if (sfg == null || sfg instanceof UIResource) {
 1423               sfg = UIManager.getColor("Table.selectionForeground");
 1424               table.setSelectionForeground(sfg != null ? sfg : UIManager.getColor("textHighlightText"));
 1425           }
 1426   
 1427           Color gridColor = table.getGridColor();
 1428           if (gridColor == null || gridColor instanceof UIResource) {
 1429               gridColor = UIManager.getColor("Table.gridColor");
 1430               table.setGridColor(gridColor != null ? gridColor : Color.GRAY);
 1431           }
 1432   
 1433           // install the scrollpane border
 1434           Container parent = table.getParent();  // should be viewport
 1435           if (parent != null) {
 1436               parent = parent.getParent();  // should be the scrollpane
 1437               if (parent != null && parent instanceof JScrollPane) {
 1438                   LookAndFeel.installBorder((JScrollPane)parent, "Table.scrollPaneBorder");
 1439               }
 1440           }
 1441   
 1442           isFileList = Boolean.TRUE.equals(table.getClientProperty("Table.isFileList"));
 1443       }
 1444   
 1445       private void installDefaults2() {
 1446           TransferHandler th = table.getTransferHandler();
 1447           if (th == null || th instanceof UIResource) {
 1448               table.setTransferHandler(defaultTransferHandler);
 1449               // default TransferHandler doesn't support drop
 1450               // so we don't want drop handling
 1451               if (table.getDropTarget() instanceof UIResource) {
 1452                   table.setDropTarget(null);
 1453               }
 1454           }
 1455       }
 1456   
 1457       /**
 1458        * Attaches listeners to the JTable.
 1459        */
 1460       protected void installListeners() {
 1461           focusListener = createFocusListener();
 1462           keyListener = createKeyListener();
 1463           mouseInputListener = createMouseInputListener();
 1464   
 1465           table.addFocusListener(focusListener);
 1466           table.addKeyListener(keyListener);
 1467           table.addMouseListener(mouseInputListener);
 1468           table.addMouseMotionListener(mouseInputListener);
 1469           table.addPropertyChangeListener(getHandler());
 1470           if (isFileList) {
 1471               table.getSelectionModel().addListSelectionListener(getHandler());
 1472           }
 1473       }
 1474   
 1475       /**
 1476        * Register all keyboard actions on the JTable.
 1477        */
 1478       protected void installKeyboardActions() {
 1479           LazyActionMap.installLazyActionMap(table, BasicTableUI.class,
 1480                   "Table.actionMap");
 1481   
 1482           InputMap inputMap = getInputMap(JComponent.
 1483                                           WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
 1484           SwingUtilities.replaceUIInputMap(table,
 1485                                   JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
 1486                                   inputMap);
 1487       }
 1488   
 1489       InputMap getInputMap(int condition) {
 1490           if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
 1491               InputMap keyMap =
 1492                   (InputMap)DefaultLookup.get(table, this,
 1493                                               "Table.ancestorInputMap");
 1494               InputMap rtlKeyMap;
 1495   
 1496               if (table.getComponentOrientation().isLeftToRight() ||
 1497                   ((rtlKeyMap = (InputMap)DefaultLookup.get(table, this,
 1498                                               "Table.ancestorInputMap.RightToLeft")) == null)) {
 1499                   return keyMap;
 1500               } else {
 1501                   rtlKeyMap.setParent(keyMap);
 1502                   return rtlKeyMap;
 1503               }
 1504           }
 1505           return null;
 1506       }
 1507   
 1508       static void loadActionMap(LazyActionMap map) {
 1509           // IMPORTANT: There is a very close coupling between the parameters
 1510           // passed to the Actions constructor. Only certain parameter
 1511           // combinations are supported. For example, the following Action would
 1512           // not work as expected:
 1513           //     new Actions(Actions.NEXT_ROW_CELL, 1, 4, false, true)
 1514           // Actions which move within the selection only (having a true
 1515           // inSelection parameter) require that one of dx or dy be
 1516           // zero and the other be -1 or 1. The point of this warning is
 1517           // that you should be very careful about making sure a particular
 1518           // combination of parameters is supported before changing or
 1519           // adding anything here.
 1520   
 1521           map.put(new Actions(Actions.NEXT_COLUMN, 1, 0,
 1522                   false, false));
 1523           map.put(new Actions(Actions.NEXT_COLUMN_CHANGE_LEAD, 1, 0,
 1524                   false, false));
 1525           map.put(new Actions(Actions.PREVIOUS_COLUMN, -1, 0,
 1526                   false, false));
 1527           map.put(new Actions(Actions.PREVIOUS_COLUMN_CHANGE_LEAD, -1, 0,
 1528                   false, false));
 1529           map.put(new Actions(Actions.NEXT_ROW, 0, 1,
 1530                   false, false));
 1531           map.put(new Actions(Actions.NEXT_ROW_CHANGE_LEAD, 0, 1,
 1532                   false, false));
 1533           map.put(new Actions(Actions.PREVIOUS_ROW, 0, -1,
 1534                   false, false));
 1535           map.put(new Actions(Actions.PREVIOUS_ROW_CHANGE_LEAD, 0, -1,
 1536                   false, false));
 1537           map.put(new Actions(Actions.NEXT_COLUMN_EXTEND_SELECTION,
 1538                   1, 0, true, false));
 1539           map.put(new Actions(Actions.PREVIOUS_COLUMN_EXTEND_SELECTION,
 1540                   -1, 0, true, false));
 1541           map.put(new Actions(Actions.NEXT_ROW_EXTEND_SELECTION,
 1542                   0, 1, true, false));
 1543           map.put(new Actions(Actions.PREVIOUS_ROW_EXTEND_SELECTION,
 1544                   0, -1, true, false));
 1545           map.put(new Actions(Actions.SCROLL_UP_CHANGE_SELECTION,
 1546                   false, false, true, false));
 1547           map.put(new Actions(Actions.SCROLL_DOWN_CHANGE_SELECTION,
 1548                   false, true, true, false));
 1549           map.put(new Actions(Actions.FIRST_COLUMN,
 1550                   false, false, false, true));
 1551           map.put(new Actions(Actions.LAST_COLUMN,
 1552                   false, true, false, true));
 1553   
 1554           map.put(new Actions(Actions.SCROLL_UP_EXTEND_SELECTION,
 1555                   true, false, true, false));
 1556           map.put(new Actions(Actions.SCROLL_DOWN_EXTEND_SELECTION,
 1557                   true, true, true, false));
 1558           map.put(new Actions(Actions.FIRST_COLUMN_EXTEND_SELECTION,
 1559                   true, false, false, true));
 1560           map.put(new Actions(Actions.LAST_COLUMN_EXTEND_SELECTION,
 1561                   true, true, false, true));
 1562   
 1563           map.put(new Actions(Actions.FIRST_ROW, false, false, true, true));
 1564           map.put(new Actions(Actions.LAST_ROW, false, true, true, true));
 1565   
 1566           map.put(new Actions(Actions.FIRST_ROW_EXTEND_SELECTION,
 1567                   true, false, true, true));
 1568           map.put(new Actions(Actions.LAST_ROW_EXTEND_SELECTION,
 1569                   true, true, true, true));
 1570   
 1571           map.put(new Actions(Actions.NEXT_COLUMN_CELL,
 1572                   1, 0, false, true));
 1573           map.put(new Actions(Actions.PREVIOUS_COLUMN_CELL,
 1574                   -1, 0, false, true));
 1575           map.put(new Actions(Actions.NEXT_ROW_CELL, 0, 1, false, true));
 1576           map.put(new Actions(Actions.PREVIOUS_ROW_CELL,
 1577                   0, -1, false, true));
 1578   
 1579           map.put(new Actions(Actions.SELECT_ALL));
 1580           map.put(new Actions(Actions.CLEAR_SELECTION));
 1581           map.put(new Actions(Actions.CANCEL_EDITING));
 1582           map.put(new Actions(Actions.START_EDITING));
 1583   
 1584           map.put(TransferHandler.getCutAction().getValue(Action.NAME),
 1585                   TransferHandler.getCutAction());
 1586           map.put(TransferHandler.getCopyAction().getValue(Action.NAME),
 1587                   TransferHandler.getCopyAction());
 1588           map.put(TransferHandler.getPasteAction().getValue(Action.NAME),
 1589                   TransferHandler.getPasteAction());
 1590   
 1591           map.put(new Actions(Actions.SCROLL_LEFT_CHANGE_SELECTION,
 1592                   false, false, false, false));
 1593           map.put(new Actions(Actions.SCROLL_RIGHT_CHANGE_SELECTION,
 1594                   false, true, false, false));
 1595           map.put(new Actions(Actions.SCROLL_LEFT_EXTEND_SELECTION,
 1596                   true, false, false, false));
 1597           map.put(new Actions(Actions.SCROLL_RIGHT_EXTEND_SELECTION,
 1598                   true, true, false, false));
 1599   
 1600           map.put(new Actions(Actions.ADD_TO_SELECTION));
 1601           map.put(new Actions(Actions.TOGGLE_AND_ANCHOR));
 1602           map.put(new Actions(Actions.EXTEND_TO));
 1603           map.put(new Actions(Actions.MOVE_SELECTION_TO));
 1604           map.put(new Actions(Actions.FOCUS_HEADER));
 1605       }
 1606   
 1607   //  Uninstallation
 1608   
 1609       public void uninstallUI(JComponent c) {
 1610           uninstallDefaults();
 1611           uninstallListeners();
 1612           uninstallKeyboardActions();
 1613   
 1614           table.remove(rendererPane);
 1615           rendererPane = null;
 1616           table = null;
 1617       }
 1618   
 1619       protected void uninstallDefaults() {
 1620           if (table.getTransferHandler() instanceof UIResource) {
 1621               table.setTransferHandler(null);
 1622           }
 1623       }
 1624   
 1625       protected void uninstallListeners() {
 1626           table.removeFocusListener(focusListener);
 1627           table.removeKeyListener(keyListener);
 1628           table.removeMouseListener(mouseInputListener);
 1629           table.removeMouseMotionListener(mouseInputListener);
 1630           table.removePropertyChangeListener(getHandler());
 1631           if (isFileList) {
 1632               table.getSelectionModel().removeListSelectionListener(getHandler());
 1633           }
 1634   
 1635           focusListener = null;
 1636           keyListener = null;
 1637           mouseInputListener = null;
 1638           handler = null;
 1639       }
 1640   
 1641       protected void uninstallKeyboardActions() {
 1642           SwingUtilities.replaceUIInputMap(table, JComponent.
 1643                                      WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
 1644           SwingUtilities.replaceUIActionMap(table, null);
 1645       }
 1646   
 1647       /**
 1648        * Returns the baseline.
 1649        *
 1650        * @throws NullPointerException {@inheritDoc}
 1651        * @throws IllegalArgumentException {@inheritDoc}
 1652        * @see javax.swing.JComponent#getBaseline(int, int)
 1653        * @since 1.6
 1654        */
 1655       public int getBaseline(JComponent c, int width, int height) {
 1656           super.getBaseline(c, width, height);
 1657           UIDefaults lafDefaults = UIManager.getLookAndFeelDefaults();
 1658           Component renderer = (Component)lafDefaults.get(
 1659                   BASELINE_COMPONENT_KEY);
 1660           if (renderer == null) {
 1661               DefaultTableCellRenderer tcr = new DefaultTableCellRenderer();
 1662               renderer = tcr.getTableCellRendererComponent(
 1663                       table, "a", false, false, -1, -1);
 1664               lafDefaults.put(BASELINE_COMPONENT_KEY, renderer);
 1665           }
 1666           renderer.setFont(table.getFont());
 1667           int rowMargin = table.getRowMargin();
 1668           return renderer.getBaseline(Integer.MAX_VALUE, table.getRowHeight() -
 1669                                       rowMargin) + rowMargin / 2;
 1670       }
 1671   
 1672       /**
 1673        * Returns an enum indicating how the baseline of the component
 1674        * changes as the size changes.
 1675        *
 1676        * @throws NullPointerException {@inheritDoc}
 1677        * @see javax.swing.JComponent#getBaseline(int, int)
 1678        * @since 1.6
 1679        */
 1680       public Component.BaselineResizeBehavior getBaselineResizeBehavior(
 1681               JComponent c) {
 1682           super.getBaselineResizeBehavior(c);
 1683           return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
 1684       }
 1685   
 1686   //
 1687   // Size Methods
 1688   //
 1689   
 1690       private Dimension createTableSize(long width) {
 1691           int height = 0;
 1692           int rowCount = table.getRowCount();
 1693           if (rowCount > 0 && table.getColumnCount() > 0) {
 1694               Rectangle r = table.getCellRect(rowCount-1, 0, true);
 1695               height = r.y + r.height;
 1696           }
 1697           // Width is always positive. The call to abs() is a workaround for
 1698           // a bug in the 1.1.6 JIT on Windows.
 1699           long tmp = Math.abs(width);
 1700           if (tmp > Integer.MAX_VALUE) {
 1701               tmp = Integer.MAX_VALUE;
 1702           }
 1703           return new Dimension((int)tmp, height);
 1704       }
 1705   
 1706       /**
 1707        * Return the minimum size of the table. The minimum height is the
 1708        * row height times the number of rows.
 1709        * The minimum width is the sum of the minimum widths of each column.
 1710        */
 1711       public Dimension getMinimumSize(JComponent c) {
 1712           long width = 0;
 1713           Enumeration enumeration = table.getColumnModel().getColumns();
 1714           while (enumeration.hasMoreElements()) {
 1715               TableColumn aColumn = (TableColumn)enumeration.nextElement();
 1716               width = width + aColumn.getMinWidth();
 1717           }
 1718           return createTableSize(width);
 1719       }
 1720   
 1721       /**
 1722        * Return the preferred size of the table. The preferred height is the
 1723        * row height times the number of rows.
 1724        * The preferred width is the sum of the preferred widths of each column.
 1725        */
 1726       public Dimension getPreferredSize(JComponent c) {
 1727           long width = 0;
 1728           Enumeration enumeration = table.getColumnModel().getColumns();
 1729           while (enumeration.hasMoreElements()) {
 1730               TableColumn aColumn = (TableColumn)enumeration.nextElement();
 1731               width = width + aColumn.getPreferredWidth();
 1732           }
 1733           return createTableSize(width);
 1734       }
 1735   
 1736       /**
 1737        * Return the maximum size of the table. The maximum height is the
 1738        * row heighttimes the number of rows.
 1739        * The maximum width is the sum of the maximum widths of each column.
 1740        */
 1741       public Dimension getMaximumSize(JComponent c) {
 1742           long width = 0;
 1743           Enumeration enumeration = table.getColumnModel().getColumns();
 1744           while (enumeration.hasMoreElements()) {
 1745               TableColumn aColumn = (TableColumn)enumeration.nextElement();
 1746               width = width + aColumn.getMaxWidth();
 1747           }
 1748           return createTableSize(width);
 1749       }
 1750   
 1751   //
 1752   //  Paint methods and support
 1753   //
 1754   
 1755       /** Paint a representation of the <code>table</code> instance
 1756        * that was set in installUI().
 1757        */
 1758       public void paint(Graphics g, JComponent c) {
 1759           Rectangle clip = g.getClipBounds();
 1760   
 1761           Rectangle bounds = table.getBounds();
 1762           // account for the fact that the graphics has already been translated
 1763           // into the table's bounds
 1764           bounds.x = bounds.y = 0;
 1765   
 1766           if (table.getRowCount() <= 0 || table.getColumnCount() <= 0 ||
 1767                   // this check prevents us from painting the entire table
 1768                   // when the clip doesn't intersect our bounds at all
 1769                   !bounds.intersects(clip)) {
 1770   
 1771               paintDropLines(g);
 1772               return;
 1773           }
 1774   
 1775           boolean ltr = table.getComponentOrientation().isLeftToRight();
 1776   
 1777           Point upperLeft = clip.getLocation();
 1778           Point lowerRight = new Point(clip.x + clip.width - 1,
 1779                                        clip.y + clip.height - 1);
 1780   
 1781           int rMin = table.rowAtPoint(upperLeft);
 1782           int rMax = table.rowAtPoint(lowerRight);
 1783           // This should never happen (as long as our bounds intersect the clip,
 1784           // which is why we bail above if that is the case).
 1785           if (rMin == -1) {
 1786               rMin = 0;
 1787           }
 1788           // If the table does not have enough rows to fill the view we'll get -1.
 1789           // (We could also get -1 if our bounds don't intersect the clip,
 1790           // which is why we bail above if that is the case).
 1791           // Replace this with the index of the last row.
 1792           if (rMax == -1) {
 1793               rMax = table.getRowCount()-1;
 1794           }
 1795   
 1796           int cMin = table.columnAtPoint(ltr ? upperLeft : lowerRight);
 1797           int cMax = table.columnAtPoint(ltr ? lowerRight : upperLeft);
 1798           // This should never happen.
 1799           if (cMin == -1) {
 1800               cMin = 0;
 1801           }
 1802           // If the table does not have enough columns to fill the view we'll get -1.
 1803           // Replace this with the index of the last column.
 1804           if (cMax == -1) {
 1805               cMax = table.getColumnCount()-1;
 1806           }
 1807   
 1808           // Paint the grid.
 1809           paintGrid(g, rMin, rMax, cMin, cMax);
 1810   
 1811           // Paint the cells.
 1812           paintCells(g, rMin, rMax, cMin, cMax);
 1813   
 1814           paintDropLines(g);
 1815       }
 1816   
 1817       private void paintDropLines(Graphics g) {
 1818           JTable.DropLocation loc = table.getDropLocation();
 1819           if (loc == null) {
 1820               return;
 1821           }
 1822   
 1823           Color color = UIManager.getColor("Table.dropLineColor");
 1824           Color shortColor = UIManager.getColor("Table.dropLineShortColor");
 1825           if (color == null && shortColor == null) {
 1826               return;
 1827           }
 1828   
 1829           Rectangle rect;
 1830   
 1831           rect = getHDropLineRect(loc);
 1832           if (rect != null) {
 1833               int x = rect.x;
 1834               int w = rect.width;
 1835               if (color != null) {
 1836                   extendRect(rect, true);
 1837                   g.setColor(color);
 1838                   g.fillRect(rect.x, rect.y, rect.width, rect.height);
 1839               }
 1840               if (!loc.isInsertColumn() && shortColor != null) {
 1841                   g.setColor(shortColor);
 1842                   g.fillRect(x, rect.y, w, rect.height);
 1843               }
 1844           }
 1845   
 1846           rect = getVDropLineRect(loc);
 1847           if (rect != null) {
 1848               int y = rect.y;
 1849               int h = rect.height;
 1850               if (color != null) {
 1851                   extendRect(rect, false);
 1852                   g.setColor(color);
 1853                   g.fillRect(rect.x, rect.y, rect.width, rect.height);
 1854               }
 1855               if (!loc.isInsertRow() && shortColor != null) {
 1856                   g.setColor(shortColor);
 1857                   g.fillRect(rect.x, y, rect.width, h);
 1858               }
 1859           }
 1860       }
 1861   
 1862       private Rectangle getHDropLineRect(JTable.DropLocation loc) {
 1863           if (!loc.isInsertRow()) {
 1864               return null;
 1865           }
 1866   
 1867           int row = loc.getRow();
 1868           int col = loc.getColumn();
 1869           if (col >= table.getColumnCount()) {
 1870               col--;
 1871           }
 1872   
 1873           Rectangle rect = table.getCellRect(row, col, true);
 1874   
 1875           if (row >= table.getRowCount()) {
 1876               row--;
 1877               Rectangle prevRect = table.getCellRect(row, col, true);
 1878               rect.y = prevRect.y + prevRect.height;
 1879           }
 1880   
 1881           if (rect.y == 0) {
 1882               rect.y = -1;
 1883           } else {
 1884               rect.y -= 2;
 1885           }
 1886   
 1887           rect.height = 3;
 1888   
 1889           return rect;
 1890       }
 1891   
 1892       private Rectangle getVDropLineRect(JTable.DropLocation loc) {
 1893           if (!loc.isInsertColumn()) {
 1894               return null;
 1895           }
 1896   
 1897           boolean ltr = table.getComponentOrientation().isLeftToRight();
 1898           int col = loc.getColumn();
 1899           Rectangle rect = table.getCellRect(loc.getRow(), col, true);
 1900   
 1901           if (col >= table.getColumnCount()) {
 1902               col--;
 1903               rect = table.getCellRect(loc.getRow(), col, true);
 1904               if (ltr) {
 1905                   rect.x = rect.x + rect.width;
 1906               }
 1907           } else if (!ltr) {
 1908               rect.x = rect.x + rect.width;
 1909           }
 1910   
 1911           if (rect.x == 0) {
 1912               rect.x = -1;
 1913           } else {
 1914               rect.x -= 2;
 1915           }
 1916   
 1917           rect.width = 3;
 1918   
 1919           return rect;
 1920       }
 1921   
 1922       private Rectangle extendRect(Rectangle rect, boolean horizontal) {
 1923           if (rect == null) {
 1924               return rect;
 1925           }
 1926   
 1927           if (horizontal) {
 1928               rect.x = 0;
 1929               rect.width = table.getWidth();
 1930           } else {
 1931               rect.y = 0;
 1932   
 1933               if (table.getRowCount() != 0) {
 1934                   Rectangle lastRect = table.getCellRect(table.getRowCount() - 1, 0, true);
 1935                   rect.height = lastRect.y + lastRect.height;
 1936               } else {
 1937                   rect.height = table.getHeight();
 1938               }
 1939           }
 1940   
 1941           return rect;
 1942       }
 1943   
 1944       /*
 1945        * Paints the grid lines within <I>aRect</I>, using the grid
 1946        * color set with <I>setGridColor</I>. Paints vertical lines
 1947        * if <code>getShowVerticalLines()</code> returns true and paints
 1948        * horizontal lines if <code>getShowHorizontalLines()</code>
 1949        * returns true.
 1950        */
 1951       private void paintGrid(Graphics g, int rMin, int rMax, int cMin, int cMax) {
 1952           g.setColor(table.getGridColor());
 1953   
 1954           Rectangle minCell = table.getCellRect(rMin, cMin, true);
 1955           Rectangle maxCell = table.getCellRect(rMax, cMax, true);
 1956           Rectangle damagedArea = minCell.union( maxCell );
 1957   
 1958           if (table.getShowHorizontalLines()) {
 1959               int tableWidth = damagedArea.x + damagedArea.width;
 1960               int y = damagedArea.y;
 1961               for (int row = rMin; row <= rMax; row++) {
 1962                   y += table.getRowHeight(row);
 1963                   g.drawLine(damagedArea.x, y - 1, tableWidth - 1, y - 1);
 1964               }
 1965           }
 1966           if (table.getShowVerticalLines()) {
 1967               TableColumnModel cm = table.getColumnModel();
 1968               int tableHeight = damagedArea.y + damagedArea.height;
 1969               int x;
 1970               if (table.getComponentOrientation().isLeftToRight()) {
 1971                   x = damagedArea.x;
 1972                   for (int column = cMin; column <= cMax; column++) {
 1973                       int w = cm.getColumn(column).getWidth();
 1974                       x += w;
 1975                       g.drawLine(x - 1, 0, x - 1, tableHeight - 1);
 1976                   }
 1977               } else {
 1978                   x = damagedArea.x;
 1979                   for (int column = cMax; column >= cMin; column--) {
 1980                       int w = cm.getColumn(column).getWidth();
 1981                       x += w;
 1982                       g.drawLine(x - 1, 0, x - 1, tableHeight - 1);
 1983                   }
 1984               }
 1985           }
 1986       }
 1987   
 1988       private int viewIndexForColumn(TableColumn aColumn) {
 1989           TableColumnModel cm = table.getColumnModel();
 1990           for (int column = 0; column < cm.getColumnCount(); column++) {
 1991               if (cm.getColumn(column) == aColumn) {
 1992                   return column;
 1993               }
 1994           }
 1995           return -1;
 1996       }
 1997   
 1998       private void paintCells(Graphics g, int rMin, int rMax, int cMin, int cMax) {
 1999           JTableHeader header = table.getTableHeader();
 2000           TableColumn draggedColumn = (header == null) ? null : header.getDraggedColumn();
 2001   
 2002           TableColumnModel cm = table.getColumnModel();
 2003           int columnMargin = cm.getColumnMargin();
 2004   
 2005           Rectangle cellRect;
 2006           TableColumn aColumn;
 2007           int columnWidth;
 2008           if (table.getComponentOrientation().isLeftToRight()) {
 2009               for(int row = rMin; row <= rMax; row++) {
 2010                   cellRect = table.getCellRect(row, cMin, false);
 2011                   for(int column = cMin; column <= cMax; column++) {
 2012                       aColumn = cm.getColumn(column);
 2013                       columnWidth = aColumn.getWidth();
 2014                       cellRect.width = columnWidth - columnMargin;
 2015                       if (aColumn != draggedColumn) {
 2016                           paintCell(g, cellRect, row, column);
 2017                       }
 2018                       cellRect.x += columnWidth;
 2019                   }
 2020               }
 2021           } else {
 2022               for(int row = rMin; row <= rMax; row++) {
 2023                   cellRect = table.getCellRect(row, cMin, false);
 2024                   aColumn = cm.getColumn(cMin);
 2025                   if (aColumn != draggedColumn) {
 2026                       columnWidth = aColumn.getWidth();
 2027                       cellRect.width = columnWidth - columnMargin;
 2028                       paintCell(g, cellRect, row, cMin);
 2029                   }
 2030                   for(int column = cMin+1; column <= cMax; column++) {
 2031                       aColumn = cm.getColumn(column);
 2032                       columnWidth = aColumn.getWidth();
 2033                       cellRect.width = columnWidth - columnMargin;
 2034                       cellRect.x -= columnWidth;
 2035                       if (aColumn != draggedColumn) {
 2036                           paintCell(g, cellRect, row, column);
 2037                       }
 2038                   }
 2039               }
 2040           }
 2041   
 2042           // Paint the dragged column if we are dragging.
 2043           if (draggedColumn != null) {
 2044               paintDraggedArea(g, rMin, rMax, draggedColumn, header.getDraggedDistance());
 2045           }
 2046   
 2047           // Remove any renderers that may be left in the rendererPane.
 2048           rendererPane.removeAll();
 2049       }
 2050   
 2051       private void paintDraggedArea(Graphics g, int rMin, int rMax, TableColumn draggedColumn, int distance) {
 2052           int draggedColumnIndex = viewIndexForColumn(draggedColumn);
 2053   
 2054           Rectangle minCell = table.getCellRect(rMin, draggedColumnIndex, true);
 2055           Rectangle maxCell = table.getCellRect(rMax, draggedColumnIndex, true);
 2056   
 2057           Rectangle vacatedColumnRect = minCell.union(maxCell);
 2058   
 2059           // Paint a gray well in place of the moving column.
 2060           g.setColor(table.getParent().getBackground());
 2061           g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,
 2062                      vacatedColumnRect.width, vacatedColumnRect.height);
 2063   
 2064           // Move to the where the cell has been dragged.
 2065           vacatedColumnRect.x += distance;
 2066   
 2067           // Fill the background.
 2068           g.setColor(table.getBackground());
 2069           g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,
 2070                      vacatedColumnRect.width, vacatedColumnRect.height);
 2071   
 2072           // Paint the vertical grid lines if necessary.
 2073           if (table.getShowVerticalLines()) {
 2074               g.setColor(table.getGridColor());
 2075               int x1 = vacatedColumnRect.x;
 2076               int y1 = vacatedColumnRect.y;
 2077               int x2 = x1 + vacatedColumnRect.width - 1;
 2078               int y2 = y1 + vacatedColumnRect.height - 1;
 2079               // Left
 2080               g.drawLine(x1-1, y1, x1-1, y2);
 2081               // Right
 2082               g.drawLine(x2, y1, x2, y2);
 2083           }
 2084   
 2085           for(int row = rMin; row <= rMax; row++) {
 2086               // Render the cell value
 2087               Rectangle r = table.getCellRect(row, draggedColumnIndex, false);
 2088               r.x += distance;
 2089               paintCell(g, r, row, draggedColumnIndex);
 2090   
 2091               // Paint the (lower) horizontal grid line if necessary.
 2092               if (table.getShowHorizontalLines()) {
 2093                   g.setColor(table.getGridColor());
 2094                   Rectangle rcr = table.getCellRect(row, draggedColumnIndex, true);
 2095                   rcr.x += distance;
 2096                   int x1 = rcr.x;
 2097                   int y1 = rcr.y;
 2098                   int x2 = x1 + rcr.width - 1;
 2099                   int y2 = y1 + rcr.height - 1;
 2100                   g.drawLine(x1, y2, x2, y2);
 2101               }
 2102           }
 2103       }
 2104   
 2105       private void paintCell(Graphics g, Rectangle cellRect, int row, int column) {
 2106           if (table.isEditing() && table.getEditingRow()==row &&
 2107                                    table.getEditingColumn()==column) {
 2108               Component component = table.getEditorComponent();
 2109               component.setBounds(cellRect);
 2110               component.validate();
 2111           }
 2112           else {
 2113               TableCellRenderer renderer = table.getCellRenderer(row, column);
 2114               Component component = table.prepareRenderer(renderer, row, column);
 2115               rendererPane.paintComponent(g, component, table, cellRect.x, cellRect.y,
 2116                                           cellRect.width, cellRect.height, true);
 2117           }
 2118       }
 2119   
 2120       private static int getAdjustedLead(JTable table,
 2121                                          boolean row,
 2122                                          ListSelectionModel model) {
 2123   
 2124           int index = model.getLeadSelectionIndex();
 2125           int compare = row ? table.getRowCount() : table.getColumnCount();
 2126           return index < compare ? index : -1;
 2127       }
 2128   
 2129       private static int getAdjustedLead(JTable table, boolean row) {
 2130           return row ? getAdjustedLead(table, row, table.getSelectionModel())
 2131                      : getAdjustedLead(table, row, table.getColumnModel().getSelectionModel());
 2132       }
 2133   
 2134   
 2135       private static final TransferHandler defaultTransferHandler = new TableTransferHandler();
 2136   
 2137       static class TableTransferHandler extends TransferHandler implements UIResource {
 2138   
 2139           /**
 2140            * Create a Transferable to use as the source for a data transfer.
 2141            *
 2142            * @param c  The component holding the data to be transfered.  This
 2143            *  argument is provided to enable sharing of TransferHandlers by
 2144            *  multiple components.
 2145            * @return  The representation of the data to be transfered.
 2146            *
 2147            */
 2148           protected Transferable createTransferable(JComponent c) {
 2149               if (c instanceof JTable) {
 2150                   JTable table = (JTable) c;
 2151                   int[] rows;
 2152                   int[] cols;
 2153   
 2154                   if (!table.getRowSelectionAllowed() && !table.getColumnSelectionAllowed()) {
 2155                       return null;
 2156                   }
 2157   
 2158                   if (!table.getRowSelectionAllowed()) {
 2159                       int rowCount = table.getRowCount();
 2160   
 2161                       rows = new int[rowCount];
 2162                       for (int counter = 0; counter < rowCount; counter++) {
 2163                           rows[counter] = counter;
 2164                       }
 2165                   } else {
 2166                       rows = table.getSelectedRows();
 2167                   }
 2168   
 2169                   if (!table.getColumnSelectionAllowed()) {
 2170                       int colCount = table.getColumnCount();
 2171   
 2172                       cols = new int[colCount];
 2173                       for (int counter = 0; counter < colCount; counter++) {
 2174                           cols[counter] = counter;
 2175                       }
 2176                   } else {
 2177                       cols = table.getSelectedColumns();
 2178                   }
 2179   
 2180                   if (rows == null || cols == null || rows.length == 0 || cols.length == 0) {
 2181                       return null;
 2182                   }
 2183   
 2184                   StringBuffer plainBuf = new StringBuffer();
 2185                   StringBuffer htmlBuf = new StringBuffer();
 2186   
 2187                   htmlBuf.append("<html>\n<body>\n<table>\n");
 2188   
 2189                   for (int row = 0; row < rows.length; row++) {
 2190                       htmlBuf.append("<tr>\n");
 2191                       for (int col = 0; col < cols.length; col++) {
 2192                           Object obj = table.getValueAt(rows[row], cols[col]);
 2193                           String val = ((obj == null) ? "" : obj.toString());
 2194                           plainBuf.append(val + "\t");
 2195                           htmlBuf.append("  <td>" + val + "</td>\n");
 2196                       }
 2197                       // we want a newline at the end of each line and not a tab
 2198                       plainBuf.deleteCharAt(plainBuf.length() - 1).append("\n");
 2199                       htmlBuf.append("</tr>\n");
 2200                   }
 2201   
 2202                   // remove the last newline
 2203                   plainBuf.deleteCharAt(plainBuf.length() - 1);
 2204                   htmlBuf.append("</table>\n</body>\n</html>");
 2205   
 2206                   return new BasicTransferable(plainBuf.toString(), htmlBuf.toString());
 2207               }
 2208   
 2209               return null;
 2210           }
 2211   
 2212           public int getSourceActions(JComponent c) {
 2213               return COPY;
 2214           }
 2215   
 2216       }
 2217   }  // End of Class BasicTableUI

Home » openjdk-7 » javax » swing » plaf » basic » [javadoc | source]