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