Save This Page
Home » openjdk-7 » javax » swing » plaf » basic » [javadoc | source]
    1   /*
    2    * Copyright 1997-2007 Sun Microsystems, Inc.  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.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any 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 inner class is marked &quot;public&quot; due to a compiler bug.
  734        * This class should be treated as a &quot;protected&quot; inner class.
  735        * Instantiate it only within subclasses of BasicTableUI.
  736        * <p>As of Java 2 platform v1.3 this class is no longer used.
  737        * Instead <code>JTable</code>
  738        * overrides <code>processKeyBinding</code> to dispatch the event to
  739        * the current <code>TableCellEditor</code>.
  740        */
  741        public class KeyHandler implements KeyListener {
  742           // NOTE: This class exists only for backward compatability. All
  743           // its functionality has been moved into Handler. If you need to add
  744           // new functionality add it to the Handler, but make sure this
  745           // class calls into the Handler.
  746           public void keyPressed(KeyEvent e) {
  747               getHandler().keyPressed(e);
  748           }
  749   
  750           public void keyReleased(KeyEvent e) {
  751               getHandler().keyReleased(e);
  752           }
  753   
  754           public void keyTyped(KeyEvent e) {
  755               getHandler().keyTyped(e);
  756           }
  757       }
  758   
  759   //
  760   //  The Table's focus listener
  761   //
  762   
  763       /**
  764        * This inner class is marked &quot;public&quot; due to a compiler bug.
  765        * This class should be treated as a &quot;protected&quot; inner class.
  766        * Instantiate it only within subclasses of BasicTableUI.
  767        */
  768       public class FocusHandler implements FocusListener {
  769           // NOTE: This class exists only for backward compatability. All
  770           // its functionality has been moved into Handler. If you need to add
  771           // new functionality add it to the Handler, but make sure this
  772           // class calls into the Handler.
  773           public void focusGained(FocusEvent e) {
  774               getHandler().focusGained(e);
  775           }
  776   
  777           public void focusLost(FocusEvent e) {
  778               getHandler().focusLost(e);
  779           }
  780       }
  781   
  782   //
  783   //  The Table's mouse and mouse motion listeners
  784   //
  785   
  786       /**
  787        * This inner class is marked &quot;public&quot; due to a compiler bug.
  788        * This class should be treated as a &quot;protected&quot; inner class.
  789        * Instantiate it only within subclasses of BasicTableUI.
  790        */
  791       public class MouseInputHandler implements MouseInputListener {
  792           // NOTE: This class exists only for backward compatability. All
  793           // its functionality has been moved into Handler. If you need to add
  794           // new functionality add it to the Handler, but make sure this
  795           // class calls into the Handler.
  796           public void mouseClicked(MouseEvent e) {
  797               getHandler().mouseClicked(e);
  798           }
  799   
  800           public void mousePressed(MouseEvent e) {
  801               getHandler().mousePressed(e);
  802           }
  803   
  804           public void mouseReleased(MouseEvent e) {
  805               getHandler().mouseReleased(e);
  806           }
  807   
  808           public void mouseEntered(MouseEvent e) {
  809               getHandler().mouseEntered(e);
  810           }
  811   
  812           public void mouseExited(MouseEvent e) {
  813               getHandler().mouseExited(e);
  814           }
  815   
  816           public void mouseMoved(MouseEvent e) {
  817               getHandler().mouseMoved(e);
  818           }
  819   
  820           public void mouseDragged(MouseEvent e) {
  821               getHandler().mouseDragged(e);
  822           }
  823       }
  824   
  825       private class Handler implements FocusListener, MouseInputListener,
  826               PropertyChangeListener, ListSelectionListener, ActionListener,
  827               BeforeDrag {
  828   
  829           // FocusListener
  830           private void repaintLeadCell( ) {
  831               int lr = getAdjustedLead(table, true);
  832               int lc = getAdjustedLead(table, false);
  833   
  834               if (lr < 0 || lc < 0) {
  835                   return;
  836               }
  837   
  838               Rectangle dirtyRect = table.getCellRect(lr, lc, false);
  839               table.repaint(dirtyRect);
  840           }
  841   
  842           public void focusGained(FocusEvent e) {
  843               repaintLeadCell();
  844           }
  845   
  846           public void focusLost(FocusEvent e) {
  847               repaintLeadCell();
  848           }
  849   
  850   
  851           // KeyListener
  852           public void keyPressed(KeyEvent e) { }
  853   
  854           public void keyReleased(KeyEvent e) { }
  855   
  856           public void keyTyped(KeyEvent e) {
  857               KeyStroke keyStroke = KeyStroke.getKeyStroke(e.getKeyChar(),
  858                       e.getModifiers());
  859   
  860               // We register all actions using ANCESTOR_OF_FOCUSED_COMPONENT
  861               // which means that we might perform the appropriate action
  862               // in the table and then forward it to the editor if the editor
  863               // had focus. Make sure this doesn't happen by checking our
  864               // InputMaps.
  865               InputMap map = table.getInputMap(JComponent.WHEN_FOCUSED);
  866               if (map != null && map.get(keyStroke) != null) {
  867                   return;
  868               }
  869               map = table.getInputMap(JComponent.
  870                                     WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  871               if (map != null && map.get(keyStroke) != null) {
  872                   return;
  873               }
  874   
  875               keyStroke = KeyStroke.getKeyStrokeForEvent(e);
  876   
  877               // The AWT seems to generate an unconsumed \r event when
  878               // ENTER (\n) is pressed.
  879               if (e.getKeyChar() == '\r') {
  880                   return;
  881               }
  882   
  883               int leadRow = getAdjustedLead(table, true);
  884               int leadColumn = getAdjustedLead(table, false);
  885               if (leadRow != -1 && leadColumn != -1 && !table.isEditing()) {
  886                   if (!table.editCellAt(leadRow, leadColumn)) {
  887                       return;
  888                   }
  889               }
  890   
  891               // Forwarding events this way seems to put the component
  892               // in a state where it believes it has focus. In reality
  893               // the table retains focus - though it is difficult for
  894               // a user to tell, since the caret is visible and flashing.
  895   
  896               // Calling table.requestFocus() here, to get the focus back to
  897               // the table, seems to have no effect.
  898   
  899               Component editorComp = table.getEditorComponent();
  900               if (table.isEditing() && editorComp != null) {
  901                   if (editorComp instanceof JComponent) {
  902                       JComponent component = (JComponent)editorComp;
  903                       map = component.getInputMap(JComponent.WHEN_FOCUSED);
  904                       Object binding = (map != null) ? map.get(keyStroke) : null;
  905                       if (binding == null) {
  906                           map = component.getInputMap(JComponent.
  907                                            WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
  908                           binding = (map != null) ? map.get(keyStroke) : null;
  909                       }
  910                       if (binding != null) {
  911                           ActionMap am = component.getActionMap();
  912                           Action action = (am != null) ? am.get(binding) : null;
  913                           if (action != null && SwingUtilities.
  914                               notifyAction(action, keyStroke, e, component,
  915                                            e.getModifiers())) {
  916                               e.consume();
  917                           }
  918                       }
  919                   }
  920               }
  921           }
  922   
  923   
  924           // MouseInputListener
  925   
  926           // Component receiving mouse events during editing.
  927           // May not be editorComponent.
  928           private Component dispatchComponent;
  929   
  930           public void mouseClicked(MouseEvent e) {}
  931   
  932           private void setDispatchComponent(MouseEvent e) {
  933               Component editorComponent = table.getEditorComponent();
  934               Point p = e.getPoint();
  935               Point p2 = SwingUtilities.convertPoint(table, p, editorComponent);
  936               dispatchComponent =
  937                       SwingUtilities.getDeepestComponentAt(editorComponent,
  938                               p2.x, p2.y);
  939               SwingUtilities2.setSkipClickCount(dispatchComponent,
  940                                                 e.getClickCount() - 1);
  941           }
  942   
  943           private boolean repostEvent(MouseEvent e) {
  944               // Check for isEditing() in case another event has
  945               // caused the editor to be removed. See bug #4306499.
  946               if (dispatchComponent == null || !table.isEditing()) {
  947                   return false;
  948               }
  949               MouseEvent e2 = SwingUtilities.convertMouseEvent(table, e,
  950                       dispatchComponent);
  951               dispatchComponent.dispatchEvent(e2);
  952               return true;
  953           }
  954   
  955           private void setValueIsAdjusting(boolean flag) {
  956               table.getSelectionModel().setValueIsAdjusting(flag);
  957               table.getColumnModel().getSelectionModel().
  958                       setValueIsAdjusting(flag);
  959           }
  960   
  961           // The row and column where the press occurred and the
  962           // press event itself
  963           private int pressedRow;
  964           private int pressedCol;
  965           private MouseEvent pressedEvent;
  966   
  967           // Whether or not the mouse press (which is being considered as part
  968           // of a drag sequence) also caused the selection change to be fully
  969           // processed.
  970           private boolean dragPressDidSelection;
  971   
  972           // Set to true when a drag gesture has been fully recognized and DnD
  973           // begins. Use this to ignore further mouse events which could be
  974           // delivered if DnD is cancelled (via ESCAPE for example)
  975           private boolean dragStarted;
  976   
  977           // Whether or not we should start the editing timer on release
  978           private boolean shouldStartTimer;
  979   
  980           // To cache the return value of pointOutsidePrefSize since we use
  981           // it multiple times.
  982           private boolean outsidePrefSize;
  983   
  984           // Used to delay the start of editing.
  985           private Timer timer = null;
  986   
  987           private boolean canStartDrag() {
  988               if (pressedRow == -1 || pressedCol == -1) {
  989                   return false;
  990               }
  991   
  992               if (isFileList) {
  993                   return !outsidePrefSize;
  994               }
  995   
  996               // if this is a single selection table
  997               if ((table.getSelectionModel().getSelectionMode() ==
  998                        ListSelectionModel.SINGLE_SELECTION) &&
  999                   (table.getColumnModel().getSelectionModel().getSelectionMode() ==
 1000                        ListSelectionModel.SINGLE_SELECTION)) {
 1001   
 1002                   return true;
 1003               }
 1004   
 1005               return table.isCellSelected(pressedRow, pressedCol);
 1006           }
 1007   
 1008           public void mousePressed(MouseEvent e) {
 1009               if (SwingUtilities2.shouldIgnore(e, table)) {
 1010                   return;
 1011               }
 1012   
 1013               if (table.isEditing() && !table.getCellEditor().stopCellEditing()) {
 1014                   Component editorComponent = table.getEditorComponent();
 1015                   if (editorComponent != null && !editorComponent.hasFocus()) {
 1016                       SwingUtilities2.compositeRequestFocus(editorComponent);
 1017                   }
 1018                   return;
 1019               }
 1020   
 1021               Point p = e.getPoint();
 1022               pressedRow = table.rowAtPoint(p);
 1023               pressedCol = table.columnAtPoint(p);
 1024               outsidePrefSize = pointOutsidePrefSize(pressedRow, pressedCol, p);
 1025   
 1026               if (isFileList) {
 1027                   shouldStartTimer =
 1028                       table.isCellSelected(pressedRow, pressedCol) &&
 1029                       !e.isShiftDown() &&
 1030                       !e.isControlDown() &&
 1031                       !outsidePrefSize;
 1032               }
 1033   
 1034               if (table.getDragEnabled()) {
 1035                   mousePressedDND(e);
 1036               } else {
 1037                   SwingUtilities2.adjustFocus(table);
 1038                   if (!isFileList) {
 1039                       setValueIsAdjusting(true);
 1040                   }
 1041                   adjustSelection(e);
 1042               }
 1043           }
 1044   
 1045           private void mousePressedDND(MouseEvent e) {
 1046               pressedEvent = e;
 1047               boolean grabFocus = true;
 1048               dragStarted = false;
 1049   
 1050               if (canStartDrag() && DragRecognitionSupport.mousePressed(e)) {
 1051   
 1052                   dragPressDidSelection = false;
 1053   
 1054                   if (e.isControlDown() && isFileList) {
 1055                       // do nothing for control - will be handled on release
 1056                       // or when drag starts
 1057                       return;
 1058                   } else if (!e.isShiftDown() && table.isCellSelected(pressedRow, pressedCol)) {
 1059                       // clicking on something that's already selected
 1060                       // and need to make it the lead now
 1061                       table.getSelectionModel().addSelectionInterval(pressedRow,
 1062                                                                      pressedRow);
 1063                       table.getColumnModel().getSelectionModel().
 1064                           addSelectionInterval(pressedCol, pressedCol);
 1065   
 1066                       return;
 1067                   }
 1068   
 1069                   dragPressDidSelection = true;
 1070   
 1071                   // could be a drag initiating event - don't grab focus
 1072                   grabFocus = false;
 1073               } else if (!isFileList) {
 1074                   // When drag can't happen, mouse drags might change the selection in the table
 1075                   // so we want the isAdjusting flag to be set
 1076                   setValueIsAdjusting(true);
 1077               }
 1078   
 1079               if (grabFocus) {
 1080                   SwingUtilities2.adjustFocus(table);
 1081               }
 1082   
 1083               adjustSelection(e);
 1084           }
 1085   
 1086           private void adjustSelection(MouseEvent e) {
 1087               // Fix for 4835633
 1088               if (outsidePrefSize) {
 1089                   // If shift is down in multi-select, we should just return.
 1090                   // For single select or non-shift-click, clear the selection
 1091                   if (e.getID() ==  MouseEvent.MOUSE_PRESSED &&
 1092                       (!e.isShiftDown() ||
 1093                        table.getSelectionModel().getSelectionMode() ==
 1094                        ListSelectionModel.SINGLE_SELECTION)) {
 1095                       table.clearSelection();
 1096                       TableCellEditor tce = table.getCellEditor();
 1097                       if (tce != null) {
 1098                           tce.stopCellEditing();
 1099                       }
 1100                   }
 1101                   return;
 1102               }
 1103               // The autoscroller can generate drag events outside the
 1104               // table's range.
 1105               if ((pressedCol == -1) || (pressedRow == -1)) {
 1106                   return;
 1107               }
 1108   
 1109               boolean dragEnabled = table.getDragEnabled();
 1110   
 1111               if (!dragEnabled && !isFileList && table.editCellAt(pressedRow, pressedCol, e)) {
 1112                   setDispatchComponent(e);
 1113                   repostEvent(e);
 1114               }
 1115   
 1116               CellEditor editor = table.getCellEditor();
 1117               if (dragEnabled || editor == null || editor.shouldSelectCell(e)) {
 1118                   table.changeSelection(pressedRow, pressedCol, e.isControlDown(), e.isShiftDown());
 1119               }
 1120           }
 1121   
 1122           public void valueChanged(ListSelectionEvent e) {
 1123               if (timer != null) {
 1124                   timer.stop();
 1125                   timer = null;
 1126               }
 1127           }
 1128   
 1129           public void actionPerformed(ActionEvent ae) {
 1130               table.editCellAt(pressedRow, pressedCol, null);
 1131               Component editorComponent = table.getEditorComponent();
 1132               if (editorComponent != null && !editorComponent.hasFocus()) {
 1133                   SwingUtilities2.compositeRequestFocus(editorComponent);
 1134               }
 1135               return;
 1136           }
 1137   
 1138           private void maybeStartTimer() {
 1139               if (!shouldStartTimer) {
 1140                   return;
 1141               }
 1142   
 1143               if (timer == null) {
 1144                   timer = new Timer(1200, this);
 1145                   timer.setRepeats(false);
 1146               }
 1147   
 1148               timer.start();
 1149           }
 1150   
 1151           public void mouseReleased(MouseEvent e) {
 1152               if (SwingUtilities2.shouldIgnore(e, table)) {
 1153                   return;
 1154               }
 1155   
 1156               if (table.getDragEnabled()) {
 1157                   mouseReleasedDND(e);
 1158               } else {
 1159                   if (isFileList) {
 1160                       maybeStartTimer();
 1161                   }
 1162               }
 1163   
 1164               pressedEvent = null;
 1165               repostEvent(e);
 1166               dispatchComponent = null;
 1167               setValueIsAdjusting(false);
 1168           }
 1169   
 1170           private void mouseReleasedDND(MouseEvent e) {
 1171               MouseEvent me = DragRecognitionSupport.mouseReleased(e);
 1172               if (me != null) {
 1173                   SwingUtilities2.adjustFocus(table);
 1174                   if (!dragPressDidSelection) {
 1175                       adjustSelection(me);
 1176                   }
 1177               }
 1178   
 1179               if (!dragStarted) {
 1180                   if (isFileList) {
 1181                       maybeStartTimer();
 1182                       return;
 1183                   }
 1184   
 1185                   Point p = e.getPoint();
 1186   
 1187                   if (pressedEvent != null &&
 1188                           table.rowAtPoint(p) == pressedRow &&
 1189                           table.columnAtPoint(p) == pressedCol &&
 1190                           table.editCellAt(pressedRow, pressedCol, pressedEvent)) {
 1191   
 1192                       setDispatchComponent(pressedEvent);
 1193                       repostEvent(pressedEvent);
 1194   
 1195                       // This may appear completely odd, but must be done for backward
 1196                       // compatibility reasons. Developers have been known to rely on
 1197                       // a call to shouldSelectCell after editing has begun.
 1198                       CellEditor ce = table.getCellEditor();
 1199                       if (ce != null) {
 1200                           ce.shouldSelectCell(pressedEvent);
 1201                       }
 1202                   }
 1203               }
 1204           }
 1205   
 1206           public void mouseEntered(MouseEvent e) {}
 1207   
 1208           public void mouseExited(MouseEvent e) {}
 1209   
 1210           public void mouseMoved(MouseEvent e) {}
 1211   
 1212           public void dragStarting(MouseEvent me) {
 1213               dragStarted = true;
 1214   
 1215               if (me.isControlDown() && isFileList) {
 1216                   table.getSelectionModel().addSelectionInterval(pressedRow,
 1217                                                                  pressedRow);
 1218                   table.getColumnModel().getSelectionModel().
 1219                       addSelectionInterval(pressedCol, pressedCol);
 1220               }
 1221   
 1222               pressedEvent = null;
 1223           }
 1224   
 1225           public void mouseDragged(MouseEvent e) {
 1226               if (SwingUtilities2.shouldIgnore(e, table)) {
 1227                   return;
 1228               }
 1229   
 1230               if (table.getDragEnabled() &&
 1231                       (DragRecognitionSupport.mouseDragged(e, this) || dragStarted)) {
 1232   
 1233                   return;
 1234               }
 1235   
 1236               repostEvent(e);
 1237   
 1238               // Check isFileList:
 1239               // Until we support drag-selection, dragging should not change
 1240               // the selection (act like single-select).
 1241               if (isFileList || table.isEditing()) {
 1242                   return;
 1243               }
 1244   
 1245               Point p = e.getPoint();
 1246               int row = table.rowAtPoint(p);
 1247               int column = table.columnAtPoint(p);
 1248               // The autoscroller can generate drag events outside the
 1249               // table's range.
 1250               if ((column == -1) || (row == -1)) {
 1251                   return;
 1252               }
 1253   
 1254               table.changeSelection(row, column, e.isControlDown(), 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               table.setSelectionBackground(UIManager.getColor("Table.selectionBackground"));
 1418           }
 1419   
 1420           Color sfg = table.getSelectionForeground();
 1421           if (sfg == null || sfg instanceof UIResource) {
 1422               table.setSelectionForeground(UIManager.getColor("Table.selectionForeground"));
 1423           }
 1424   
 1425           Color gridColor = table.getGridColor();
 1426           if (gridColor == null || gridColor instanceof UIResource) {
 1427               table.setGridColor(UIManager.getColor("Table.gridColor"));
 1428           }
 1429   
 1430           // install the scrollpane border
 1431           Container parent = table.getParent();  // should be viewport
 1432           if (parent != null) {
 1433               parent = parent.getParent();  // should be the scrollpane
 1434               if (parent != null && parent instanceof JScrollPane) {
 1435                   LookAndFeel.installBorder((JScrollPane)parent, "Table.scrollPaneBorder");
 1436               }
 1437           }
 1438   
 1439           isFileList = Boolean.TRUE.equals(table.getClientProperty("Table.isFileList"));
 1440       }
 1441   
 1442       private void installDefaults2() {
 1443           TransferHandler th = table.getTransferHandler();
 1444           if (th == null || th instanceof UIResource) {
 1445               table.setTransferHandler(defaultTransferHandler);
 1446               // default TransferHandler doesn't support drop
 1447               // so we don't want drop handling
 1448               if (table.getDropTarget() instanceof UIResource) {
 1449                   table.setDropTarget(null);
 1450               }
 1451           }
 1452       }
 1453   
 1454       /**
 1455        * Attaches listeners to the JTable.
 1456        */
 1457       protected void installListeners() {
 1458           focusListener = createFocusListener();
 1459           keyListener = createKeyListener();
 1460           mouseInputListener = createMouseInputListener();
 1461   
 1462           table.addFocusListener(focusListener);
 1463           table.addKeyListener(keyListener);
 1464           table.addMouseListener(mouseInputListener);
 1465           table.addMouseMotionListener(mouseInputListener);
 1466           table.addPropertyChangeListener(getHandler());
 1467           if (isFileList) {
 1468               table.getSelectionModel().addListSelectionListener(getHandler());
 1469           }
 1470       }
 1471   
 1472       /**
 1473        * Register all keyboard actions on the JTable.
 1474        */
 1475       protected void installKeyboardActions() {
 1476           LazyActionMap.installLazyActionMap(table, BasicTableUI.class,
 1477                   "Table.actionMap");
 1478   
 1479           InputMap inputMap = getInputMap(JComponent.
 1480                                           WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
 1481           SwingUtilities.replaceUIInputMap(table,
 1482                                   JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
 1483                                   inputMap);
 1484       }
 1485   
 1486       InputMap getInputMap(int condition) {
 1487           if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
 1488               InputMap keyMap =
 1489                   (InputMap)DefaultLookup.get(table, this,
 1490                                               "Table.ancestorInputMap");
 1491               InputMap rtlKeyMap;
 1492   
 1493               if (table.getComponentOrientation().isLeftToRight() ||
 1494                   ((rtlKeyMap = (InputMap)DefaultLookup.get(table, this,
 1495                                               "Table.ancestorInputMap.RightToLeft")) == null)) {
 1496                   return keyMap;
 1497               } else {
 1498                   rtlKeyMap.setParent(keyMap);
 1499                   return rtlKeyMap;
 1500               }
 1501           }
 1502           return null;
 1503       }
 1504   
 1505       static void loadActionMap(LazyActionMap map) {
 1506           // IMPORTANT: There is a very close coupling between the parameters
 1507           // passed to the Actions constructor. Only certain parameter
 1508           // combinations are supported. For example, the following Action would
 1509           // not work as expected:
 1510           //     new Actions(Actions.NEXT_ROW_CELL, 1, 4, false, true)
 1511           // Actions which move within the selection only (having a true
 1512           // inSelection parameter) require that one of dx or dy be
 1513           // zero and the other be -1 or 1. The point of this warning is
 1514           // that you should be very careful about making sure a particular
 1515           // combination of parameters is supported before changing or
 1516           // adding anything here.
 1517   
 1518           map.put(new Actions(Actions.NEXT_COLUMN, 1, 0,
 1519                   false, false));
 1520           map.put(new Actions(Actions.NEXT_COLUMN_CHANGE_LEAD, 1, 0,
 1521                   false, false));
 1522           map.put(new Actions(Actions.PREVIOUS_COLUMN, -1, 0,
 1523                   false, false));
 1524           map.put(new Actions(Actions.PREVIOUS_COLUMN_CHANGE_LEAD, -1, 0,
 1525                   false, false));
 1526           map.put(new Actions(Actions.NEXT_ROW, 0, 1,
 1527                   false, false));
 1528           map.put(new Actions(Actions.NEXT_ROW_CHANGE_LEAD, 0, 1,
 1529                   false, false));
 1530           map.put(new Actions(Actions.PREVIOUS_ROW, 0, -1,
 1531                   false, false));
 1532           map.put(new Actions(Actions.PREVIOUS_ROW_CHANGE_LEAD, 0, -1,
 1533                   false, false));
 1534           map.put(new Actions(Actions.NEXT_COLUMN_EXTEND_SELECTION,
 1535                   1, 0, true, false));
 1536           map.put(new Actions(Actions.PREVIOUS_COLUMN_EXTEND_SELECTION,
 1537                   -1, 0, true, false));
 1538           map.put(new Actions(Actions.NEXT_ROW_EXTEND_SELECTION,
 1539                   0, 1, true, false));
 1540           map.put(new Actions(Actions.PREVIOUS_ROW_EXTEND_SELECTION,
 1541                   0, -1, true, false));
 1542           map.put(new Actions(Actions.SCROLL_UP_CHANGE_SELECTION,
 1543                   false, false, true, false));
 1544           map.put(new Actions(Actions.SCROLL_DOWN_CHANGE_SELECTION,
 1545                   false, true, true, false));
 1546           map.put(new Actions(Actions.FIRST_COLUMN,
 1547                   false, false, false, true));
 1548           map.put(new Actions(Actions.LAST_COLUMN,
 1549                   false, true, false, true));
 1550   
 1551           map.put(new Actions(Actions.SCROLL_UP_EXTEND_SELECTION,
 1552                   true, false, true, false));
 1553           map.put(new Actions(Actions.SCROLL_DOWN_EXTEND_SELECTION,
 1554                   true, true, true, false));
 1555           map.put(new Actions(Actions.FIRST_COLUMN_EXTEND_SELECTION,
 1556                   true, false, false, true));
 1557           map.put(new Actions(Actions.LAST_COLUMN_EXTEND_SELECTION,
 1558                   true, true, false, true));
 1559   
 1560           map.put(new Actions(Actions.FIRST_ROW, false, false, true, true));
 1561           map.put(new Actions(Actions.LAST_ROW, false, true, true, true));
 1562   
 1563           map.put(new Actions(Actions.FIRST_ROW_EXTEND_SELECTION,
 1564                   true, false, true, true));
 1565           map.put(new Actions(Actions.LAST_ROW_EXTEND_SELECTION,
 1566                   true, true, true, true));
 1567   
 1568           map.put(new Actions(Actions.NEXT_COLUMN_CELL,
 1569                   1, 0, false, true));
 1570           map.put(new Actions(Actions.PREVIOUS_COLUMN_CELL,
 1571                   -1, 0, false, true));
 1572           map.put(new Actions(Actions.NEXT_ROW_CELL, 0, 1, false, true));
 1573           map.put(new Actions(Actions.PREVIOUS_ROW_CELL,
 1574                   0, -1, false, true));
 1575   
 1576           map.put(new Actions(Actions.SELECT_ALL));
 1577           map.put(new Actions(Actions.CLEAR_SELECTION));
 1578           map.put(new Actions(Actions.CANCEL_EDITING));
 1579           map.put(new Actions(Actions.START_EDITING));
 1580   
 1581           map.put(TransferHandler.getCutAction().getValue(Action.NAME),
 1582                   TransferHandler.getCutAction());
 1583           map.put(TransferHandler.getCopyAction().getValue(Action.NAME),
 1584                   TransferHandler.getCopyAction());
 1585           map.put(TransferHandler.getPasteAction().getValue(Action.NAME),
 1586                   TransferHandler.getPasteAction());
 1587   
 1588           map.put(new Actions(Actions.SCROLL_LEFT_CHANGE_SELECTION,
 1589                   false, false, false, false));
 1590           map.put(new Actions(Actions.SCROLL_RIGHT_CHANGE_SELECTION,
 1591                   false, true, false, false));
 1592           map.put(new Actions(Actions.SCROLL_LEFT_EXTEND_SELECTION,
 1593                   true, false, false, false));
 1594           map.put(new Actions(Actions.SCROLL_RIGHT_EXTEND_SELECTION,
 1595                   true, true, false, false));
 1596   
 1597           map.put(new Actions(Actions.ADD_TO_SELECTION));
 1598           map.put(new Actions(Actions.TOGGLE_AND_ANCHOR));
 1599           map.put(new Actions(Actions.EXTEND_TO));
 1600           map.put(new Actions(Actions.MOVE_SELECTION_TO));
 1601           map.put(new Actions(Actions.FOCUS_HEADER));
 1602       }
 1603   
 1604   //  Uninstallation
 1605   
 1606       public void uninstallUI(JComponent c) {
 1607           uninstallDefaults();
 1608           uninstallListeners();
 1609           uninstallKeyboardActions();
 1610   
 1611           table.remove(rendererPane);
 1612           rendererPane = null;
 1613           table = null;
 1614       }
 1615   
 1616       protected void uninstallDefaults() {
 1617           if (table.getTransferHandler() instanceof UIResource) {
 1618               table.setTransferHandler(null);
 1619           }
 1620       }
 1621   
 1622       protected void uninstallListeners() {
 1623           table.removeFocusListener(focusListener);
 1624           table.removeKeyListener(keyListener);
 1625           table.removeMouseListener(mouseInputListener);
 1626           table.removeMouseMotionListener(mouseInputListener);
 1627           table.removePropertyChangeListener(getHandler());
 1628           if (isFileList) {
 1629               table.getSelectionModel().removeListSelectionListener(getHandler());
 1630           }
 1631   
 1632           focusListener = null;
 1633           keyListener = null;
 1634           mouseInputListener = null;
 1635           handler = null;
 1636       }
 1637   
 1638       protected void uninstallKeyboardActions() {
 1639           SwingUtilities.replaceUIInputMap(table, JComponent.
 1640                                      WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
 1641           SwingUtilities.replaceUIActionMap(table, null);
 1642       }
 1643   
 1644       /**
 1645        * Returns the baseline.
 1646        *
 1647        * @throws NullPointerException {@inheritDoc}
 1648        * @throws IllegalArgumentException {@inheritDoc}
 1649        * @see javax.swing.JComponent#getBaseline(int, int)
 1650        * @since 1.6
 1651        */
 1652       public int getBaseline(JComponent c, int width, int height) {
 1653           super.getBaseline(c, width, height);
 1654           UIDefaults lafDefaults = UIManager.getLookAndFeelDefaults();
 1655           Component renderer = (Component)lafDefaults.get(
 1656                   BASELINE_COMPONENT_KEY);
 1657           if (renderer == null) {
 1658               DefaultTableCellRenderer tcr = new DefaultTableCellRenderer();
 1659               renderer = tcr.getTableCellRendererComponent(
 1660                       table, "a", false, false, -1, -1);
 1661               lafDefaults.put(BASELINE_COMPONENT_KEY, renderer);
 1662           }
 1663           renderer.setFont(table.getFont());
 1664           int rowMargin = table.getRowMargin();
 1665           return renderer.getBaseline(Integer.MAX_VALUE, table.getRowHeight() -
 1666                                       rowMargin) + rowMargin / 2;
 1667       }
 1668   
 1669       /**
 1670        * Returns an enum indicating how the baseline of the component
 1671        * changes as the size changes.
 1672        *
 1673        * @throws NullPointerException {@inheritDoc}
 1674        * @see javax.swing.JComponent#getBaseline(int, int)
 1675        * @since 1.6
 1676        */
 1677       public Component.BaselineResizeBehavior getBaselineResizeBehavior(
 1678               JComponent c) {
 1679           super.getBaselineResizeBehavior(c);
 1680           return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
 1681       }
 1682   
 1683   //
 1684   // Size Methods
 1685   //
 1686   
 1687       private Dimension createTableSize(long width) {
 1688           int height = 0;
 1689           int rowCount = table.getRowCount();
 1690           if (rowCount > 0 && table.getColumnCount() > 0) {
 1691               Rectangle r = table.getCellRect(rowCount-1, 0, true);
 1692               height = r.y + r.height;
 1693           }
 1694           // Width is always positive. The call to abs() is a workaround for
 1695           // a bug in the 1.1.6 JIT on Windows.
 1696           long tmp = Math.abs(width);
 1697           if (tmp > Integer.MAX_VALUE) {
 1698               tmp = Integer.MAX_VALUE;
 1699           }
 1700           return new Dimension((int)tmp, height);
 1701       }
 1702   
 1703       /**
 1704        * Return the minimum size of the table. The minimum height is the
 1705        * row height times the number of rows.
 1706        * The minimum width is the sum of the minimum widths of each column.
 1707        */
 1708       public Dimension getMinimumSize(JComponent c) {
 1709           long width = 0;
 1710           Enumeration enumeration = table.getColumnModel().getColumns();
 1711           while (enumeration.hasMoreElements()) {
 1712               TableColumn aColumn = (TableColumn)enumeration.nextElement();
 1713               width = width + aColumn.getMinWidth();
 1714           }
 1715           return createTableSize(width);
 1716       }
 1717   
 1718       /**
 1719        * Return the preferred size of the table. The preferred height is the
 1720        * row height times the number of rows.
 1721        * The preferred width is the sum of the preferred widths of each column.
 1722        */
 1723       public Dimension getPreferredSize(JComponent c) {
 1724           long width = 0;
 1725           Enumeration enumeration = table.getColumnModel().getColumns();
 1726           while (enumeration.hasMoreElements()) {
 1727               TableColumn aColumn = (TableColumn)enumeration.nextElement();
 1728               width = width + aColumn.getPreferredWidth();
 1729           }
 1730           return createTableSize(width);
 1731       }
 1732   
 1733       /**
 1734        * Return the maximum size of the table. The maximum height is the
 1735        * row heighttimes the number of rows.
 1736        * The maximum width is the sum of the maximum widths of each column.
 1737        */
 1738       public Dimension getMaximumSize(JComponent c) {
 1739           long width = 0;
 1740           Enumeration enumeration = table.getColumnModel().getColumns();
 1741           while (enumeration.hasMoreElements()) {
 1742               TableColumn aColumn = (TableColumn)enumeration.nextElement();
 1743               width = width + aColumn.getMaxWidth();
 1744           }
 1745           return createTableSize(width);
 1746       }
 1747   
 1748   //
 1749   //  Paint methods and support
 1750   //
 1751   
 1752       /** Paint a representation of the <code>table</code> instance
 1753        * that was set in installUI().
 1754        */
 1755       public void paint(Graphics g, JComponent c) {
 1756           Rectangle clip = g.getClipBounds();
 1757   
 1758           Rectangle bounds = table.getBounds();
 1759           // account for the fact that the graphics has already been translated
 1760           // into the table's bounds
 1761           bounds.x = bounds.y = 0;
 1762   
 1763           if (table.getRowCount() <= 0 || table.getColumnCount() <= 0 ||
 1764                   // this check prevents us from painting the entire table
 1765                   // when the clip doesn't intersect our bounds at all
 1766                   !bounds.intersects(clip)) {
 1767   
 1768               paintDropLines(g);
 1769               return;
 1770           }
 1771   
 1772           boolean ltr = table.getComponentOrientation().isLeftToRight();
 1773   
 1774           Point upperLeft = clip.getLocation();
 1775           Point lowerRight = new Point(clip.x + clip.width - 1,
 1776                                        clip.y + clip.height - 1);
 1777   
 1778           int rMin = table.rowAtPoint(upperLeft);
 1779           int rMax = table.rowAtPoint(lowerRight);
 1780           // This should never happen (as long as our bounds intersect the clip,
 1781           // which is why we bail above if that is the case).
 1782           if (rMin == -1) {
 1783               rMin = 0;
 1784           }
 1785           // If the table does not have enough rows to fill the view we'll get -1.
 1786           // (We could also get -1 if our bounds don't intersect the clip,
 1787           // which is why we bail above if that is the case).
 1788           // Replace this with the index of the last row.
 1789           if (rMax == -1) {
 1790               rMax = table.getRowCount()-1;
 1791           }
 1792   
 1793           int cMin = table.columnAtPoint(ltr ? upperLeft : lowerRight);
 1794           int cMax = table.columnAtPoint(ltr ? lowerRight : upperLeft);
 1795           // This should never happen.
 1796           if (cMin == -1) {
 1797               cMin = 0;
 1798           }
 1799           // If the table does not have enough columns to fill the view we'll get -1.
 1800           // Replace this with the index of the last column.
 1801           if (cMax == -1) {
 1802               cMax = table.getColumnCount()-1;
 1803           }
 1804   
 1805           // Paint the grid.
 1806           paintGrid(g, rMin, rMax, cMin, cMax);
 1807   
 1808           // Paint the cells.
 1809           paintCells(g, rMin, rMax, cMin, cMax);
 1810   
 1811           paintDropLines(g);
 1812       }
 1813   
 1814       private void paintDropLines(Graphics g) {
 1815           JTable.DropLocation loc = table.getDropLocation();
 1816           if (loc == null) {
 1817               return;
 1818           }
 1819   
 1820           Color color = UIManager.getColor("Table.dropLineColor");
 1821           Color shortColor = UIManager.getColor("Table.dropLineShortColor");
 1822           if (color == null && shortColor == null) {
 1823               return;
 1824           }
 1825   
 1826           Rectangle rect;
 1827   
 1828           rect = getHDropLineRect(loc);
 1829           if (rect != null) {
 1830               int x = rect.x;
 1831               int w = rect.width;
 1832               if (color != null) {
 1833                   extendRect(rect, true);
 1834                   g.setColor(color);
 1835                   g.fillRect(rect.x, rect.y, rect.width, rect.height);
 1836               }
 1837               if (!loc.isInsertColumn() && shortColor != null) {
 1838                   g.setColor(shortColor);
 1839                   g.fillRect(x, rect.y, w, rect.height);
 1840               }
 1841           }
 1842   
 1843           rect = getVDropLineRect(loc);
 1844           if (rect != null) {
 1845               int y = rect.y;
 1846               int h = rect.height;
 1847               if (color != null) {
 1848                   extendRect(rect, false);
 1849                   g.setColor(color);
 1850                   g.fillRect(rect.x, rect.y, rect.width, rect.height);
 1851               }
 1852               if (!loc.isInsertRow() && shortColor != null) {
 1853                   g.setColor(shortColor);
 1854                   g.fillRect(rect.x, y, rect.width, h);
 1855               }
 1856           }
 1857       }
 1858   
 1859       private Rectangle getHDropLineRect(JTable.DropLocation loc) {
 1860           if (!loc.isInsertRow()) {
 1861               return null;
 1862           }
 1863   
 1864           int row = loc.getRow();
 1865           int col = loc.getColumn();
 1866           if (col >= table.getColumnCount()) {
 1867               col--;
 1868           }
 1869   
 1870           Rectangle rect = table.getCellRect(row, col, true);
 1871   
 1872           if (row >= table.getRowCount()) {
 1873               row--;
 1874               Rectangle prevRect = table.getCellRect(row, col, true);
 1875               rect.y = prevRect.y + prevRect.height;
 1876           }
 1877   
 1878           if (rect.y == 0) {
 1879               rect.y = -1;
 1880           } else {
 1881               rect.y -= 2;
 1882           }
 1883   
 1884           rect.height = 3;
 1885   
 1886           return rect;
 1887       }
 1888   
 1889       private Rectangle getVDropLineRect(JTable.DropLocation loc) {
 1890           if (!loc.isInsertColumn()) {
 1891               return null;
 1892           }
 1893   
 1894           boolean ltr = table.getComponentOrientation().isLeftToRight();
 1895           int col = loc.getColumn();
 1896           Rectangle rect = table.getCellRect(loc.getRow(), col, true);
 1897   
 1898           if (col >= table.getColumnCount()) {
 1899               col--;
 1900               rect = table.getCellRect(loc.getRow(), col, true);
 1901               if (ltr) {
 1902                   rect.x = rect.x + rect.width;
 1903               }
 1904           } else if (!ltr) {
 1905               rect.x = rect.x + rect.width;
 1906           }
 1907   
 1908           if (rect.x == 0) {
 1909               rect.x = -1;
 1910           } else {
 1911               rect.x -= 2;
 1912           }
 1913   
 1914           rect.width = 3;
 1915   
 1916           return rect;
 1917       }
 1918   
 1919       private Rectangle extendRect(Rectangle rect, boolean horizontal) {
 1920           if (rect == null) {
 1921               return rect;
 1922           }
 1923   
 1924           if (horizontal) {
 1925               rect.x = 0;
 1926               rect.width = table.getWidth();
 1927           } else {
 1928               rect.y = 0;
 1929   
 1930               if (table.getRowCount() != 0) {
 1931                   Rectangle lastRect = table.getCellRect(table.getRowCount() - 1, 0, true);
 1932                   rect.height = lastRect.y + lastRect.height;
 1933               } else {
 1934                   rect.height = table.getHeight();
 1935               }
 1936           }
 1937   
 1938           return rect;
 1939       }
 1940   
 1941       /*
 1942        * Paints the grid lines within <I>aRect</I>, using the grid
 1943        * color set with <I>setGridColor</I>. Paints vertical lines
 1944        * if <code>getShowVerticalLines()</code> returns true and paints
 1945        * horizontal lines if <code>getShowHorizontalLines()</code>
 1946        * returns true.
 1947        */
 1948       private void paintGrid(Graphics g, int rMin, int rMax, int cMin, int cMax) {
 1949           g.setColor(table.getGridColor());
 1950   
 1951           Rectangle minCell = table.getCellRect(rMin, cMin, true);
 1952           Rectangle maxCell = table.getCellRect(rMax, cMax, true);
 1953           Rectangle damagedArea = minCell.union( maxCell );
 1954   
 1955           if (table.getShowHorizontalLines()) {
 1956               int tableWidth = damagedArea.x + damagedArea.width;
 1957               int y = damagedArea.y;
 1958               for (int row = rMin; row <= rMax; row++) {
 1959                   y += table.getRowHeight(row);
 1960                   g.drawLine(damagedArea.x, y - 1, tableWidth - 1, y - 1);
 1961               }
 1962           }
 1963           if (table.getShowVerticalLines()) {
 1964               TableColumnModel cm = table.getColumnModel();
 1965               int tableHeight = damagedArea.y + damagedArea.height;
 1966               int x;
 1967               if (table.getComponentOrientation().isLeftToRight()) {
 1968                   x = damagedArea.x;
 1969                   for (int column = cMin; column <= cMax; column++) {
 1970                       int w = cm.getColumn(column).getWidth();
 1971                       x += w;
 1972                       g.drawLine(x - 1, 0, x - 1, tableHeight - 1);
 1973                   }
 1974               } else {
 1975                   x = damagedArea.x;
 1976                   for (int column = cMax; column >= cMin; column--) {
 1977                       int w = cm.getColumn(column).getWidth();
 1978                       x += w;
 1979                       g.drawLine(x - 1, 0, x - 1, tableHeight - 1);
 1980                   }
 1981               }
 1982           }
 1983       }
 1984   
 1985       private int viewIndexForColumn(TableColumn aColumn) {
 1986           TableColumnModel cm = table.getColumnModel();
 1987           for (int column = 0; column < cm.getColumnCount(); column++) {
 1988               if (cm.getColumn(column) == aColumn) {
 1989                   return column;
 1990               }
 1991           }
 1992           return -1;
 1993       }
 1994   
 1995       private void paintCells(Graphics g, int rMin, int rMax, int cMin, int cMax) {
 1996           JTableHeader header = table.getTableHeader();
 1997           TableColumn draggedColumn = (header == null) ? null : header.getDraggedColumn();
 1998   
 1999           TableColumnModel cm = table.getColumnModel();
 2000           int columnMargin = cm.getColumnMargin();
 2001   
 2002           Rectangle cellRect;
 2003           TableColumn aColumn;
 2004           int columnWidth;
 2005           if (table.getComponentOrientation().isLeftToRight()) {
 2006               for(int row = rMin; row <= rMax; row++) {
 2007                   cellRect = table.getCellRect(row, cMin, false);
 2008                   for(int column = cMin; column <= cMax; column++) {
 2009                       aColumn = cm.getColumn(column);
 2010                       columnWidth = aColumn.getWidth();
 2011                       cellRect.width = columnWidth - columnMargin;
 2012                       if (aColumn != draggedColumn) {
 2013                           paintCell(g, cellRect, row, column);
 2014                       }
 2015                       cellRect.x += columnWidth;
 2016                   }
 2017               }
 2018           } else {
 2019               for(int row = rMin; row <= rMax; row++) {
 2020                   cellRect = table.getCellRect(row, cMin, false);
 2021                   aColumn = cm.getColumn(cMin);
 2022                   if (aColumn != draggedColumn) {
 2023                       columnWidth = aColumn.getWidth();
 2024                       cellRect.width = columnWidth - columnMargin;
 2025                       paintCell(g, cellRect, row, cMin);
 2026                   }
 2027                   for(int column = cMin+1; column <= cMax; column++) {
 2028                       aColumn = cm.getColumn(column);
 2029                       columnWidth = aColumn.getWidth();
 2030                       cellRect.width = columnWidth - columnMargin;
 2031                       cellRect.x -= columnWidth;
 2032                       if (aColumn != draggedColumn) {
 2033                           paintCell(g, cellRect, row, column);
 2034                       }
 2035                   }
 2036               }
 2037           }
 2038   
 2039           // Paint the dragged column if we are dragging.
 2040           if (draggedColumn != null) {
 2041               paintDraggedArea(g, rMin, rMax, draggedColumn, header.getDraggedDistance());
 2042           }
 2043   
 2044           // Remove any renderers that may be left in the rendererPane.
 2045           rendererPane.removeAll();
 2046       }
 2047   
 2048       private void paintDraggedArea(Graphics g, int rMin, int rMax, TableColumn draggedColumn, int distance) {
 2049           int draggedColumnIndex = viewIndexForColumn(draggedColumn);
 2050   
 2051           Rectangle minCell = table.getCellRect(rMin, draggedColumnIndex, true);
 2052           Rectangle maxCell = table.getCellRect(rMax, draggedColumnIndex, true);
 2053   
 2054           Rectangle vacatedColumnRect = minCell.union(maxCell);
 2055   
 2056           // Paint a gray well in place of the moving column.
 2057           g.setColor(table.getParent().getBackground());
 2058           g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,
 2059                      vacatedColumnRect.width, vacatedColumnRect.height);
 2060   
 2061           // Move to the where the cell has been dragged.
 2062           vacatedColumnRect.x += distance;
 2063   
 2064           // Fill the background.
 2065           g.setColor(table.getBackground());
 2066           g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,
 2067                      vacatedColumnRect.width, vacatedColumnRect.height);
 2068   
 2069           // Paint the vertical grid lines if necessary.
 2070           if (table.getShowVerticalLines()) {
 2071               g.setColor(table.getGridColor());
 2072               int x1 = vacatedColumnRect.x;
 2073               int y1 = vacatedColumnRect.y;
 2074               int x2 = x1 + vacatedColumnRect.width - 1;
 2075               int y2 = y1 + vacatedColumnRect.height - 1;
 2076               // Left
 2077               g.drawLine(x1-1, y1, x1-1, y2);
 2078               // Right
 2079               g.drawLine(x2, y1, x2, y2);
 2080           }
 2081   
 2082           for(int row = rMin; row <= rMax; row++) {
 2083               // Render the cell value
 2084               Rectangle r = table.getCellRect(row, draggedColumnIndex, false);
 2085               r.x += distance;
 2086               paintCell(g, r, row, draggedColumnIndex);
 2087   
 2088               // Paint the (lower) horizontal grid line if necessary.
 2089               if (table.getShowHorizontalLines()) {
 2090                   g.setColor(table.getGridColor());
 2091                   Rectangle rcr = table.getCellRect(row, draggedColumnIndex, true);
 2092                   rcr.x += distance;
 2093                   int x1 = rcr.x;
 2094                   int y1 = rcr.y;
 2095                   int x2 = x1 + rcr.width - 1;
 2096                   int y2 = y1 + rcr.height - 1;
 2097                   g.drawLine(x1, y2, x2, y2);
 2098               }
 2099           }
 2100       }
 2101   
 2102       private void paintCell(Graphics g, Rectangle cellRect, int row, int column) {
 2103           if (table.isEditing() && table.getEditingRow()==row &&
 2104                                    table.getEditingColumn()==column) {
 2105               Component component = table.getEditorComponent();
 2106               component.setBounds(cellRect);
 2107               component.validate();
 2108           }
 2109           else {
 2110               TableCellRenderer renderer = table.getCellRenderer(row, column);
 2111               Component component = table.prepareRenderer(renderer, row, column);
 2112               rendererPane.paintComponent(g, component, table, cellRect.x, cellRect.y,
 2113                                           cellRect.width, cellRect.height, true);
 2114           }
 2115       }
 2116   
 2117       private static int getAdjustedLead(JTable table,
 2118                                          boolean row,
 2119                                          ListSelectionModel model) {
 2120   
 2121           int index = model.getLeadSelectionIndex();
 2122           int compare = row ? table.getRowCount() : table.getColumnCount();
 2123           return index < compare ? index : -1;
 2124       }
 2125   
 2126       private static int getAdjustedLead(JTable table, boolean row) {
 2127           return row ? getAdjustedLead(table, row, table.getSelectionModel())
 2128                      : getAdjustedLead(table, row, table.getColumnModel().getSelectionModel());
 2129       }
 2130   
 2131   
 2132       private static final TransferHandler defaultTransferHandler = new TableTransferHandler();
 2133   
 2134       static class TableTransferHandler extends TransferHandler implements UIResource {
 2135   
 2136           /**
 2137            * Create a Transferable to use as the source for a data transfer.
 2138            *
 2139            * @param c  The component holding the data to be transfered.  This
 2140            *  argument is provided to enable sharing of TransferHandlers by
 2141            *  multiple components.
 2142            * @return  The representation of the data to be transfered.
 2143            *
 2144            */
 2145           protected Transferable createTransferable(JComponent c) {
 2146               if (c instanceof JTable) {
 2147                   JTable table = (JTable) c;
 2148                   int[] rows;
 2149                   int[] cols;
 2150   
 2151                   if (!table.getRowSelectionAllowed() && !table.getColumnSelectionAllowed()) {
 2152                       return null;
 2153                   }
 2154   
 2155                   if (!table.getRowSelectionAllowed()) {
 2156                       int rowCount = table.getRowCount();
 2157   
 2158                       rows = new int[rowCount];
 2159                       for (int counter = 0; counter < rowCount; counter++) {
 2160                           rows[counter] = counter;
 2161                       }
 2162                   } else {
 2163                       rows = table.getSelectedRows();
 2164                   }
 2165   
 2166                   if (!table.getColumnSelectionAllowed()) {
 2167                       int colCount = table.getColumnCount();
 2168   
 2169                       cols = new int[colCount];
 2170                       for (int counter = 0; counter < colCount; counter++) {
 2171                           cols[counter] = counter;
 2172                       }
 2173                   } else {
 2174                       cols = table.getSelectedColumns();
 2175                   }
 2176   
 2177                   if (rows == null || cols == null || rows.length == 0 || cols.length == 0) {
 2178                       return null;
 2179                   }
 2180   
 2181                   StringBuffer plainBuf = new StringBuffer();
 2182                   StringBuffer htmlBuf = new StringBuffer();
 2183   
 2184                   htmlBuf.append("<html>\n<body>\n<table>\n");
 2185   
 2186                   for (int row = 0; row < rows.length; row++) {
 2187                       htmlBuf.append("<tr>\n");
 2188                       for (int col = 0; col < cols.length; col++) {
 2189                           Object obj = table.getValueAt(rows[row], cols[col]);
 2190                           String val = ((obj == null) ? "" : obj.toString());
 2191                           plainBuf.append(val + "\t");
 2192                           htmlBuf.append("  <td>" + val + "</td>\n");
 2193                       }
 2194                       // we want a newline at the end of each line and not a tab
 2195                       plainBuf.deleteCharAt(plainBuf.length() - 1).append("\n");
 2196                       htmlBuf.append("</tr>\n");
 2197                   }
 2198   
 2199                   // remove the last newline
 2200                   plainBuf.deleteCharAt(plainBuf.length() - 1);
 2201                   htmlBuf.append("</table>\n</body>\n</html>");
 2202   
 2203                   return new BasicTransferable(plainBuf.toString(), htmlBuf.toString());
 2204               }
 2205   
 2206               return null;
 2207           }
 2208   
 2209           public int getSourceActions(JComponent c) {
 2210               return COPY;
 2211           }
 2212   
 2213       }
 2214   }  // End of Class BasicTableUI

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