0N/A/*
6128N/A * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage javax.swing.plaf.basic;
0N/A
0N/Aimport java.awt.*;
0N/Aimport java.awt.datatransfer.*;
0N/Aimport java.awt.dnd.*;
0N/Aimport java.awt.event.*;
0N/Aimport java.util.Enumeration;
0N/Aimport java.util.EventObject;
0N/Aimport java.util.Hashtable;
0N/Aimport java.util.TooManyListenersException;
0N/Aimport javax.swing.*;
0N/Aimport javax.swing.event.*;
0N/Aimport javax.swing.plaf.*;
0N/Aimport javax.swing.text.*;
0N/Aimport javax.swing.table.*;
0N/Aimport javax.swing.plaf.basic.DragRecognitionSupport.BeforeDrag;
0N/Aimport sun.swing.SwingUtilities2;
0N/A
0N/A
0N/Aimport java.beans.PropertyChangeEvent;
0N/Aimport java.beans.PropertyChangeListener;
0N/A
0N/Aimport sun.swing.DefaultLookup;
0N/Aimport sun.swing.UIAction;
0N/A
0N/A/**
0N/A * BasicTableUI implementation
0N/A *
0N/A * @author Philip Milne
0N/A * @author Shannon Hickey (drag and drop)
0N/A */
0N/Apublic class BasicTableUI extends TableUI
0N/A{
0N/A private static final StringBuilder BASELINE_COMPONENT_KEY =
0N/A new StringBuilder("Table.baselineComponent");
0N/A
0N/A//
0N/A// Instance Variables
0N/A//
0N/A
0N/A // The JTable that is delegating the painting to this UI.
0N/A protected JTable table;
0N/A protected CellRendererPane rendererPane;
0N/A
0N/A // Listeners that are attached to the JTable
0N/A protected KeyListener keyListener;
0N/A protected FocusListener focusListener;
0N/A protected MouseInputListener mouseInputListener;
0N/A
0N/A private Handler handler;
0N/A
0N/A /**
0N/A * Local cache of Table's client property "Table.isFileList"
0N/A */
0N/A private boolean isFileList = false;
0N/A
0N/A//
0N/A// Helper class for keyboard actions
0N/A//
0N/A
0N/A private static class Actions extends UIAction {
0N/A private static final String CANCEL_EDITING = "cancel";
0N/A private static final String SELECT_ALL = "selectAll";
0N/A private static final String CLEAR_SELECTION = "clearSelection";
0N/A private static final String START_EDITING = "startEditing";
0N/A
0N/A private static final String NEXT_ROW = "selectNextRow";
0N/A private static final String NEXT_ROW_CELL = "selectNextRowCell";
0N/A private static final String NEXT_ROW_EXTEND_SELECTION =
0N/A "selectNextRowExtendSelection";
0N/A private static final String NEXT_ROW_CHANGE_LEAD =
0N/A "selectNextRowChangeLead";
0N/A private static final String PREVIOUS_ROW = "selectPreviousRow";
0N/A private static final String PREVIOUS_ROW_CELL = "selectPreviousRowCell";
0N/A private static final String PREVIOUS_ROW_EXTEND_SELECTION =
0N/A "selectPreviousRowExtendSelection";
0N/A private static final String PREVIOUS_ROW_CHANGE_LEAD =
0N/A "selectPreviousRowChangeLead";
0N/A
0N/A private static final String NEXT_COLUMN = "selectNextColumn";
0N/A private static final String NEXT_COLUMN_CELL = "selectNextColumnCell";
0N/A private static final String NEXT_COLUMN_EXTEND_SELECTION =
0N/A "selectNextColumnExtendSelection";
0N/A private static final String NEXT_COLUMN_CHANGE_LEAD =
0N/A "selectNextColumnChangeLead";
0N/A private static final String PREVIOUS_COLUMN = "selectPreviousColumn";
0N/A private static final String PREVIOUS_COLUMN_CELL =
0N/A "selectPreviousColumnCell";
0N/A private static final String PREVIOUS_COLUMN_EXTEND_SELECTION =
0N/A "selectPreviousColumnExtendSelection";
0N/A private static final String PREVIOUS_COLUMN_CHANGE_LEAD =
0N/A "selectPreviousColumnChangeLead";
0N/A
0N/A private static final String SCROLL_LEFT_CHANGE_SELECTION =
0N/A "scrollLeftChangeSelection";
0N/A private static final String SCROLL_LEFT_EXTEND_SELECTION =
0N/A "scrollLeftExtendSelection";
0N/A private static final String SCROLL_RIGHT_CHANGE_SELECTION =
0N/A "scrollRightChangeSelection";
0N/A private static final String SCROLL_RIGHT_EXTEND_SELECTION =
0N/A "scrollRightExtendSelection";
0N/A
0N/A private static final String SCROLL_UP_CHANGE_SELECTION =
0N/A "scrollUpChangeSelection";
0N/A private static final String SCROLL_UP_EXTEND_SELECTION =
0N/A "scrollUpExtendSelection";
0N/A private static final String SCROLL_DOWN_CHANGE_SELECTION =
0N/A "scrollDownChangeSelection";
0N/A private static final String SCROLL_DOWN_EXTEND_SELECTION =
0N/A "scrollDownExtendSelection";
0N/A
0N/A private static final String FIRST_COLUMN =
0N/A "selectFirstColumn";
0N/A private static final String FIRST_COLUMN_EXTEND_SELECTION =
0N/A "selectFirstColumnExtendSelection";
0N/A private static final String LAST_COLUMN =
0N/A "selectLastColumn";
0N/A private static final String LAST_COLUMN_EXTEND_SELECTION =
0N/A "selectLastColumnExtendSelection";
0N/A
0N/A private static final String FIRST_ROW =
0N/A "selectFirstRow";
0N/A private static final String FIRST_ROW_EXTEND_SELECTION =
0N/A "selectFirstRowExtendSelection";
0N/A private static final String LAST_ROW =
0N/A "selectLastRow";
0N/A private static final String LAST_ROW_EXTEND_SELECTION =
0N/A "selectLastRowExtendSelection";
0N/A
0N/A // add the lead item to the selection without changing lead or anchor
0N/A private static final String ADD_TO_SELECTION = "addToSelection";
0N/A
0N/A // toggle the selected state of the lead item and move the anchor to it
0N/A private static final String TOGGLE_AND_ANCHOR = "toggleAndAnchor";
0N/A
0N/A // extend the selection to the lead item
0N/A private static final String EXTEND_TO = "extendTo";
0N/A
0N/A // move the anchor to the lead and ensure only that item is selected
0N/A private static final String MOVE_SELECTION_TO = "moveSelectionTo";
0N/A
0N/A // give focus to the JTableHeader, if one exists
0N/A private static final String FOCUS_HEADER = "focusHeader";
0N/A
0N/A protected int dx;
0N/A protected int dy;
0N/A protected boolean extend;
0N/A protected boolean inSelection;
0N/A
0N/A // horizontally, forwards always means right,
0N/A // regardless of component orientation
0N/A protected boolean forwards;
0N/A protected boolean vertically;
0N/A protected boolean toLimit;
0N/A
0N/A protected int leadRow;
0N/A protected int leadColumn;
0N/A
0N/A Actions(String name) {
0N/A super(name);
0N/A }
0N/A
0N/A Actions(String name, int dx, int dy, boolean extend,
0N/A boolean inSelection) {
0N/A super(name);
0N/A
0N/A // Actions spcifying true for "inSelection" are
0N/A // fairly sensitive to bad parameter values. They require
0N/A // that one of dx and dy be 0 and the other be -1 or 1.
0N/A // Bogus parameter values could cause an infinite loop.
0N/A // To prevent any problems we massage the params here
0N/A // and complain if we get something we can't deal with.
0N/A if (inSelection) {
0N/A this.inSelection = true;
0N/A
0N/A // look at the sign of dx and dy only
0N/A dx = sign(dx);
0N/A dy = sign(dy);
0N/A
0N/A // make sure one is zero, but not both
0N/A assert (dx == 0 || dy == 0) && !(dx == 0 && dy == 0);
0N/A }
0N/A
0N/A this.dx = dx;
0N/A this.dy = dy;
0N/A this.extend = extend;
0N/A }
0N/A
0N/A Actions(String name, boolean extend, boolean forwards,
0N/A boolean vertically, boolean toLimit) {
0N/A this(name, 0, 0, extend, false);
0N/A this.forwards = forwards;
0N/A this.vertically = vertically;
0N/A this.toLimit = toLimit;
0N/A }
0N/A
0N/A private static int clipToRange(int i, int a, int b) {
0N/A return Math.min(Math.max(i, a), b-1);
0N/A }
0N/A
0N/A private void moveWithinTableRange(JTable table, int dx, int dy) {
0N/A leadRow = clipToRange(leadRow+dy, 0, table.getRowCount());
0N/A leadColumn = clipToRange(leadColumn+dx, 0, table.getColumnCount());
0N/A }
0N/A
0N/A private static int sign(int num) {
0N/A return (num < 0) ? -1 : ((num == 0) ? 0 : 1);
0N/A }
0N/A
0N/A /**
0N/A * Called to move within the selected range of the given JTable.
0N/A * This method uses the table's notion of selection, which is
0N/A * important to allow the user to navigate between items visually
0N/A * selected on screen. This notion may or may not be the same as
0N/A * what could be determined by directly querying the selection models.
0N/A * It depends on certain table properties (such as whether or not
0N/A * row or column selection is allowed). When performing modifications,
0N/A * it is recommended that caution be taken in order to preserve
0N/A * the intent of this method, especially when deciding whether to
0N/A * query the selection models or interact with JTable directly.
0N/A */
0N/A private boolean moveWithinSelectedRange(JTable table, int dx, int dy,
0N/A ListSelectionModel rsm, ListSelectionModel csm) {
0N/A
0N/A // Note: The Actions constructor ensures that only one of
0N/A // dx and dy is 0, and the other is either -1 or 1
0N/A
0N/A // find out how many items the table is showing as selected
0N/A // and the range of items to navigate through
0N/A int totalCount;
0N/A int minX, maxX, minY, maxY;
0N/A
0N/A boolean rs = table.getRowSelectionAllowed();
0N/A boolean cs = table.getColumnSelectionAllowed();
0N/A
0N/A // both column and row selection
0N/A if (rs && cs) {
0N/A totalCount = table.getSelectedRowCount() * table.getSelectedColumnCount();
0N/A minX = csm.getMinSelectionIndex();
0N/A maxX = csm.getMaxSelectionIndex();
0N/A minY = rsm.getMinSelectionIndex();
0N/A maxY = rsm.getMaxSelectionIndex();
0N/A // row selection only
0N/A } else if (rs) {
0N/A totalCount = table.getSelectedRowCount();
0N/A minX = 0;
0N/A maxX = table.getColumnCount() - 1;
0N/A minY = rsm.getMinSelectionIndex();
0N/A maxY = rsm.getMaxSelectionIndex();
0N/A // column selection only
0N/A } else if (cs) {
0N/A totalCount = table.getSelectedColumnCount();
0N/A minX = csm.getMinSelectionIndex();
0N/A maxX = csm.getMaxSelectionIndex();
0N/A minY = 0;
0N/A maxY = table.getRowCount() - 1;
0N/A // no selection allowed
0N/A } else {
0N/A totalCount = 0;
0N/A // A bogus assignment to stop javac from complaining
0N/A // about unitialized values. In this case, these
0N/A // won't even be used.
0N/A minX = maxX = minY = maxY = 0;
0N/A }
0N/A
0N/A // For some cases, there is no point in trying to stay within the
0N/A // selected area. Instead, move outside the selection, wrapping at
0N/A // the table boundaries. The cases are:
0N/A boolean stayInSelection;
0N/A
0N/A // - nothing selected
0N/A if (totalCount == 0 ||
0N/A // - one item selected, and the lead is already selected
0N/A (totalCount == 1 && table.isCellSelected(leadRow, leadColumn))) {
0N/A
0N/A stayInSelection = false;
0N/A
0N/A maxX = table.getColumnCount() - 1;
0N/A maxY = table.getRowCount() - 1;
0N/A
0N/A // the mins are calculated like this in case the max is -1
0N/A minX = Math.min(0, maxX);
0N/A minY = Math.min(0, maxY);
0N/A } else {
0N/A stayInSelection = true;
0N/A }
0N/A
0N/A // the algorithm below isn't prepared to deal with -1 lead/anchor
0N/A // so massage appropriately here first
0N/A if (dy == 1 && leadColumn == -1) {
0N/A leadColumn = minX;
0N/A leadRow = -1;
0N/A } else if (dx == 1 && leadRow == -1) {
0N/A leadRow = minY;
0N/A leadColumn = -1;
0N/A } else if (dy == -1 && leadColumn == -1) {
0N/A leadColumn = maxX;
0N/A leadRow = maxY + 1;
0N/A } else if (dx == -1 && leadRow == -1) {
0N/A leadRow = maxY;
0N/A leadColumn = maxX + 1;
0N/A }
0N/A
0N/A // In cases where the lead is not within the search range,
0N/A // we need to bring it within one cell for the the search
0N/A // to work properly. Check these here.
0N/A leadRow = Math.min(Math.max(leadRow, minY - 1), maxY + 1);
0N/A leadColumn = Math.min(Math.max(leadColumn, minX - 1), maxX + 1);
0N/A
0N/A // find the next position, possibly looping until it is selected
0N/A do {
0N/A calcNextPos(dx, minX, maxX, dy, minY, maxY);
0N/A } while (stayInSelection && !table.isCellSelected(leadRow, leadColumn));
0N/A
0N/A return stayInSelection;
0N/A }
0N/A
0N/A /**
0N/A * Find the next lead row and column based on the given
0N/A * dx/dy and max/min values.
0N/A */
0N/A private void calcNextPos(int dx, int minX, int maxX,
0N/A int dy, int minY, int maxY) {
0N/A
0N/A if (dx != 0) {
0N/A leadColumn += dx;
0N/A if (leadColumn > maxX) {
0N/A leadColumn = minX;
0N/A leadRow++;
0N/A if (leadRow > maxY) {
0N/A leadRow = minY;
0N/A }
0N/A } else if (leadColumn < minX) {
0N/A leadColumn = maxX;
0N/A leadRow--;
0N/A if (leadRow < minY) {
0N/A leadRow = maxY;
0N/A }
0N/A }
0N/A } else {
0N/A leadRow += dy;
0N/A if (leadRow > maxY) {
0N/A leadRow = minY;
0N/A leadColumn++;
0N/A if (leadColumn > maxX) {
0N/A leadColumn = minX;
0N/A }
0N/A } else if (leadRow < minY) {
0N/A leadRow = maxY;
0N/A leadColumn--;
0N/A if (leadColumn < minX) {
0N/A leadColumn = maxX;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A public void actionPerformed(ActionEvent e) {
0N/A String key = getName();
0N/A JTable table = (JTable)e.getSource();
0N/A
0N/A ListSelectionModel rsm = table.getSelectionModel();
0N/A leadRow = getAdjustedLead(table, true, rsm);
0N/A
0N/A ListSelectionModel csm = table.getColumnModel().getSelectionModel();
0N/A leadColumn = getAdjustedLead(table, false, csm);
0N/A
0N/A if (key == SCROLL_LEFT_CHANGE_SELECTION || // Paging Actions
0N/A key == SCROLL_LEFT_EXTEND_SELECTION ||
0N/A key == SCROLL_RIGHT_CHANGE_SELECTION ||
0N/A key == SCROLL_RIGHT_EXTEND_SELECTION ||
0N/A key == SCROLL_UP_CHANGE_SELECTION ||
0N/A key == SCROLL_UP_EXTEND_SELECTION ||
0N/A key == SCROLL_DOWN_CHANGE_SELECTION ||
0N/A key == SCROLL_DOWN_EXTEND_SELECTION ||
0N/A key == FIRST_COLUMN ||
0N/A key == FIRST_COLUMN_EXTEND_SELECTION ||
0N/A key == FIRST_ROW ||
0N/A key == FIRST_ROW_EXTEND_SELECTION ||
0N/A key == LAST_COLUMN ||
0N/A key == LAST_COLUMN_EXTEND_SELECTION ||
0N/A key == LAST_ROW ||
0N/A key == LAST_ROW_EXTEND_SELECTION) {
0N/A if (toLimit) {
0N/A if (vertically) {
0N/A int rowCount = table.getRowCount();
0N/A this.dx = 0;
0N/A this.dy = forwards ? rowCount : -rowCount;
0N/A }
0N/A else {
0N/A int colCount = table.getColumnCount();
0N/A this.dx = forwards ? colCount : -colCount;
0N/A this.dy = 0;
0N/A }
0N/A }
0N/A else {
6128N/A if (!(SwingUtilities.getUnwrappedParent(table).getParent() instanceof
0N/A JScrollPane)) {
0N/A return;
0N/A }
0N/A
0N/A Dimension delta = table.getParent().getSize();
0N/A
0N/A if (vertically) {
0N/A Rectangle r = table.getCellRect(leadRow, 0, true);
0N/A if (forwards) {
0N/A // scroll by at least one cell
0N/A r.y += Math.max(delta.height, r.height);
0N/A } else {
0N/A r.y -= delta.height;
0N/A }
0N/A
0N/A this.dx = 0;
0N/A int newRow = table.rowAtPoint(r.getLocation());
0N/A if (newRow == -1 && forwards) {
0N/A newRow = table.getRowCount();
0N/A }
0N/A this.dy = newRow - leadRow;
0N/A }
0N/A else {
0N/A Rectangle r = table.getCellRect(0, leadColumn, true);
0N/A
0N/A if (forwards) {
0N/A // scroll by at least one cell
0N/A r.x += Math.max(delta.width, r.width);
0N/A } else {
0N/A r.x -= delta.width;
0N/A }
0N/A
0N/A int newColumn = table.columnAtPoint(r.getLocation());
0N/A if (newColumn == -1) {
0N/A boolean ltr = table.getComponentOrientation().isLeftToRight();
0N/A
0N/A newColumn = forwards ? (ltr ? table.getColumnCount() : 0)
0N/A : (ltr ? 0 : table.getColumnCount());
0N/A
0N/A }
0N/A this.dx = newColumn - leadColumn;
0N/A this.dy = 0;
0N/A }
0N/A }
0N/A }
0N/A if (key == NEXT_ROW || // Navigate Actions
0N/A key == NEXT_ROW_CELL ||
0N/A key == NEXT_ROW_EXTEND_SELECTION ||
0N/A key == NEXT_ROW_CHANGE_LEAD ||
0N/A key == NEXT_COLUMN ||
0N/A key == NEXT_COLUMN_CELL ||
0N/A key == NEXT_COLUMN_EXTEND_SELECTION ||
0N/A key == NEXT_COLUMN_CHANGE_LEAD ||
0N/A key == PREVIOUS_ROW ||
0N/A key == PREVIOUS_ROW_CELL ||
0N/A key == PREVIOUS_ROW_EXTEND_SELECTION ||
0N/A key == PREVIOUS_ROW_CHANGE_LEAD ||
0N/A key == PREVIOUS_COLUMN ||
0N/A key == PREVIOUS_COLUMN_CELL ||
0N/A key == PREVIOUS_COLUMN_EXTEND_SELECTION ||
0N/A key == PREVIOUS_COLUMN_CHANGE_LEAD ||
0N/A // Paging Actions.
0N/A key == SCROLL_LEFT_CHANGE_SELECTION ||
0N/A key == SCROLL_LEFT_EXTEND_SELECTION ||
0N/A key == SCROLL_RIGHT_CHANGE_SELECTION ||
0N/A key == SCROLL_RIGHT_EXTEND_SELECTION ||
0N/A key == SCROLL_UP_CHANGE_SELECTION ||
0N/A key == SCROLL_UP_EXTEND_SELECTION ||
0N/A key == SCROLL_DOWN_CHANGE_SELECTION ||
0N/A key == SCROLL_DOWN_EXTEND_SELECTION ||
0N/A key == FIRST_COLUMN ||
0N/A key == FIRST_COLUMN_EXTEND_SELECTION ||
0N/A key == FIRST_ROW ||
0N/A key == FIRST_ROW_EXTEND_SELECTION ||
0N/A key == LAST_COLUMN ||
0N/A key == LAST_COLUMN_EXTEND_SELECTION ||
0N/A key == LAST_ROW ||
0N/A key == LAST_ROW_EXTEND_SELECTION) {
0N/A
0N/A if (table.isEditing() &&
0N/A !table.getCellEditor().stopCellEditing()) {
0N/A return;
0N/A }
0N/A
0N/A // Unfortunately, this strategy introduces bugs because
0N/A // of the asynchronous nature of requestFocus() call below.
0N/A // Introducing a delay with invokeLater() makes this work
0N/A // in the typical case though race conditions then allow
0N/A // focus to disappear altogether. The right solution appears
0N/A // to be to fix requestFocus() so that it queues a request
0N/A // for the focus regardless of who owns the focus at the
0N/A // time the call to requestFocus() is made. The optimisation
0N/A // to ignore the call to requestFocus() when the component
0N/A // already has focus may ligitimately be made as the
0N/A // request focus event is dequeued, not before.
0N/A
0N/A // boolean wasEditingWithFocus = table.isEditing() &&
0N/A // table.getEditorComponent().isFocusOwner();
0N/A
0N/A boolean changeLead = false;
0N/A if (key == NEXT_ROW_CHANGE_LEAD || key == PREVIOUS_ROW_CHANGE_LEAD) {
0N/A changeLead = (rsm.getSelectionMode()
0N/A == ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
0N/A } else if (key == NEXT_COLUMN_CHANGE_LEAD || key == PREVIOUS_COLUMN_CHANGE_LEAD) {
0N/A changeLead = (csm.getSelectionMode()
0N/A == ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
0N/A }
0N/A
0N/A if (changeLead) {
0N/A moveWithinTableRange(table, dx, dy);
0N/A if (dy != 0) {
0N/A // casting should be safe since the action is only enabled
0N/A // for DefaultListSelectionModel
0N/A ((DefaultListSelectionModel)rsm).moveLeadSelectionIndex(leadRow);
0N/A if (getAdjustedLead(table, false, csm) == -1
0N/A && table.getColumnCount() > 0) {
0N/A
0N/A ((DefaultListSelectionModel)csm).moveLeadSelectionIndex(0);
0N/A }
0N/A } else {
0N/A // casting should be safe since the action is only enabled
0N/A // for DefaultListSelectionModel
0N/A ((DefaultListSelectionModel)csm).moveLeadSelectionIndex(leadColumn);
0N/A if (getAdjustedLead(table, true, rsm) == -1
0N/A && table.getRowCount() > 0) {
0N/A
0N/A ((DefaultListSelectionModel)rsm).moveLeadSelectionIndex(0);
0N/A }
0N/A }
0N/A
0N/A Rectangle cellRect = table.getCellRect(leadRow, leadColumn, false);
0N/A if (cellRect != null) {
0N/A table.scrollRectToVisible(cellRect);
0N/A }
0N/A } else if (!inSelection) {
0N/A moveWithinTableRange(table, dx, dy);
0N/A table.changeSelection(leadRow, leadColumn, false, extend);
0N/A }
0N/A else {
0N/A if (table.getRowCount() <= 0 || table.getColumnCount() <= 0) {
0N/A // bail - don't try to move selection on an empty table
0N/A return;
0N/A }
0N/A
0N/A if (moveWithinSelectedRange(table, dx, dy, rsm, csm)) {
0N/A // this is the only way we have to set both the lead
0N/A // and the anchor without changing the selection
0N/A if (rsm.isSelectedIndex(leadRow)) {
0N/A rsm.addSelectionInterval(leadRow, leadRow);
0N/A } else {
0N/A rsm.removeSelectionInterval(leadRow, leadRow);
0N/A }
0N/A
0N/A if (csm.isSelectedIndex(leadColumn)) {
0N/A csm.addSelectionInterval(leadColumn, leadColumn);
0N/A } else {
0N/A csm.removeSelectionInterval(leadColumn, leadColumn);
0N/A }
0N/A
0N/A Rectangle cellRect = table.getCellRect(leadRow, leadColumn, false);
0N/A if (cellRect != null) {
0N/A table.scrollRectToVisible(cellRect);
0N/A }
0N/A }
0N/A else {
0N/A table.changeSelection(leadRow, leadColumn,
0N/A false, false);
0N/A }
0N/A }
0N/A
0N/A /*
0N/A if (wasEditingWithFocus) {
0N/A table.editCellAt(leadRow, leadColumn);
0N/A final Component editorComp = table.getEditorComponent();
0N/A if (editorComp != null) {
0N/A SwingUtilities.invokeLater(new Runnable() {
0N/A public void run() {
0N/A editorComp.requestFocus();
0N/A }
0N/A });
0N/A }
0N/A }
0N/A */
0N/A } else if (key == CANCEL_EDITING) {
0N/A table.removeEditor();
0N/A } else if (key == SELECT_ALL) {
0N/A table.selectAll();
0N/A } else if (key == CLEAR_SELECTION) {
0N/A table.clearSelection();
0N/A } else if (key == START_EDITING) {
0N/A if (!table.hasFocus()) {
0N/A CellEditor cellEditor = table.getCellEditor();
0N/A if (cellEditor != null && !cellEditor.stopCellEditing()) {
0N/A return;
0N/A }
0N/A table.requestFocus();
0N/A return;
0N/A }
0N/A table.editCellAt(leadRow, leadColumn, e);
0N/A Component editorComp = table.getEditorComponent();
0N/A if (editorComp != null) {
0N/A editorComp.requestFocus();
0N/A }
0N/A } else if (key == ADD_TO_SELECTION) {
0N/A if (!table.isCellSelected(leadRow, leadColumn)) {
0N/A int oldAnchorRow = rsm.getAnchorSelectionIndex();
0N/A int oldAnchorColumn = csm.getAnchorSelectionIndex();
0N/A rsm.setValueIsAdjusting(true);
0N/A csm.setValueIsAdjusting(true);
0N/A table.changeSelection(leadRow, leadColumn, true, false);
0N/A rsm.setAnchorSelectionIndex(oldAnchorRow);
0N/A csm.setAnchorSelectionIndex(oldAnchorColumn);
0N/A rsm.setValueIsAdjusting(false);
0N/A csm.setValueIsAdjusting(false);
0N/A }
0N/A } else if (key == TOGGLE_AND_ANCHOR) {
0N/A table.changeSelection(leadRow, leadColumn, true, false);
0N/A } else if (key == EXTEND_TO) {
0N/A table.changeSelection(leadRow, leadColumn, false, true);
0N/A } else if (key == MOVE_SELECTION_TO) {
0N/A table.changeSelection(leadRow, leadColumn, false, false);
0N/A } else if (key == FOCUS_HEADER) {
0N/A JTableHeader th = table.getTableHeader();
0N/A if (th != null) {
0N/A //Set the header's selected column to match the table.
0N/A int col = table.getSelectedColumn();
0N/A if (col >= 0) {
0N/A TableHeaderUI thUI = th.getUI();
0N/A if (thUI instanceof BasicTableHeaderUI) {
0N/A ((BasicTableHeaderUI)thUI).selectColumn(col);
0N/A }
0N/A }
0N/A
0N/A //Then give the header the focus.
0N/A th.requestFocusInWindow();
0N/A }
0N/A }
0N/A }
0N/A
0N/A public boolean isEnabled(Object sender) {
0N/A String key = getName();
0N/A
0N/A if (sender instanceof JTable &&
0N/A Boolean.TRUE.equals(((JTable)sender).getClientProperty("Table.isFileList"))) {
0N/A if (key == NEXT_COLUMN ||
0N/A key == NEXT_COLUMN_CELL ||
0N/A key == NEXT_COLUMN_EXTEND_SELECTION ||
0N/A key == NEXT_COLUMN_CHANGE_LEAD ||
0N/A key == PREVIOUS_COLUMN ||
0N/A key == PREVIOUS_COLUMN_CELL ||
0N/A key == PREVIOUS_COLUMN_EXTEND_SELECTION ||
0N/A key == PREVIOUS_COLUMN_CHANGE_LEAD ||
0N/A key == SCROLL_LEFT_CHANGE_SELECTION ||
0N/A key == SCROLL_LEFT_EXTEND_SELECTION ||
0N/A key == SCROLL_RIGHT_CHANGE_SELECTION ||
0N/A key == SCROLL_RIGHT_EXTEND_SELECTION ||
0N/A key == FIRST_COLUMN ||
0N/A key == FIRST_COLUMN_EXTEND_SELECTION ||
0N/A key == LAST_COLUMN ||
0N/A key == LAST_COLUMN_EXTEND_SELECTION ||
0N/A key == NEXT_ROW_CELL ||
0N/A key == PREVIOUS_ROW_CELL) {
0N/A
0N/A return false;
0N/A }
0N/A }
0N/A
0N/A if (key == CANCEL_EDITING && sender instanceof JTable) {
0N/A return ((JTable)sender).isEditing();
0N/A } else if (key == NEXT_ROW_CHANGE_LEAD ||
0N/A key == PREVIOUS_ROW_CHANGE_LEAD) {
0N/A // discontinuous selection actions are only enabled for
0N/A // DefaultListSelectionModel
0N/A return sender != null &&
0N/A ((JTable)sender).getSelectionModel()
0N/A instanceof DefaultListSelectionModel;
0N/A } else if (key == NEXT_COLUMN_CHANGE_LEAD ||
0N/A key == PREVIOUS_COLUMN_CHANGE_LEAD) {
0N/A // discontinuous selection actions are only enabled for
0N/A // DefaultListSelectionModel
0N/A return sender != null &&
0N/A ((JTable)sender).getColumnModel().getSelectionModel()
0N/A instanceof DefaultListSelectionModel;
0N/A } else if (key == ADD_TO_SELECTION && sender instanceof JTable) {
0N/A // This action is typically bound to SPACE.
0N/A // If the table is already in an editing mode, SPACE should
0N/A // simply enter a space character into the table, and not
0N/A // select a cell. Likewise, if the lead cell is already selected
0N/A // then hitting SPACE should just enter a space character
0N/A // into the cell and begin editing. In both of these cases
0N/A // this action will be disabled.
0N/A JTable table = (JTable)sender;
0N/A int leadRow = getAdjustedLead(table, true);
0N/A int leadCol = getAdjustedLead(table, false);
0N/A return !(table.isEditing() || table.isCellSelected(leadRow, leadCol));
0N/A } else if (key == FOCUS_HEADER && sender instanceof JTable) {
0N/A JTable table = (JTable)sender;
0N/A return table.getTableHeader() != null;
0N/A }
0N/A
0N/A return true;
0N/A }
0N/A }
0N/A
0N/A
0N/A//
0N/A// The Table's Key listener
0N/A//
0N/A
0N/A /**
0N/A * This class should be treated as a &quot;protected&quot; inner class.
3972N/A * Instantiate it only within subclasses of {@code BasicTableUI}.
0N/A * <p>As of Java 2 platform v1.3 this class is no longer used.
0N/A * Instead <code>JTable</code>
0N/A * overrides <code>processKeyBinding</code> to dispatch the event to
0N/A * the current <code>TableCellEditor</code>.
0N/A */
0N/A public class KeyHandler implements KeyListener {
0N/A // NOTE: This class exists only for backward compatability. All
0N/A // its functionality has been moved into Handler. If you need to add
0N/A // new functionality add it to the Handler, but make sure this
0N/A // class calls into the Handler.
0N/A public void keyPressed(KeyEvent e) {
0N/A getHandler().keyPressed(e);
0N/A }
0N/A
0N/A public void keyReleased(KeyEvent e) {
0N/A getHandler().keyReleased(e);
0N/A }
0N/A
0N/A public void keyTyped(KeyEvent e) {
0N/A getHandler().keyTyped(e);
0N/A }
0N/A }
0N/A
0N/A//
0N/A// The Table's focus listener
0N/A//
0N/A
0N/A /**
0N/A * This class should be treated as a &quot;protected&quot; inner class.
3972N/A * Instantiate it only within subclasses of {@code BasicTableUI}.
0N/A */
0N/A public class FocusHandler implements FocusListener {
0N/A // NOTE: This class exists only for backward compatability. All
0N/A // its functionality has been moved into Handler. If you need to add
0N/A // new functionality add it to the Handler, but make sure this
0N/A // class calls into the Handler.
0N/A public void focusGained(FocusEvent e) {
0N/A getHandler().focusGained(e);
0N/A }
0N/A
0N/A public void focusLost(FocusEvent e) {
0N/A getHandler().focusLost(e);
0N/A }
0N/A }
0N/A
0N/A//
0N/A// The Table's mouse and mouse motion listeners
0N/A//
0N/A
0N/A /**
0N/A * This class should be treated as a &quot;protected&quot; inner class.
0N/A * Instantiate it only within subclasses of BasicTableUI.
0N/A */
0N/A public class MouseInputHandler implements MouseInputListener {
0N/A // NOTE: This class exists only for backward compatability. All
0N/A // its functionality has been moved into Handler. If you need to add
0N/A // new functionality add it to the Handler, but make sure this
0N/A // class calls into the Handler.
0N/A public void mouseClicked(MouseEvent e) {
0N/A getHandler().mouseClicked(e);
0N/A }
0N/A
0N/A public void mousePressed(MouseEvent e) {
0N/A getHandler().mousePressed(e);
0N/A }
0N/A
0N/A public void mouseReleased(MouseEvent e) {
0N/A getHandler().mouseReleased(e);
0N/A }
0N/A
0N/A public void mouseEntered(MouseEvent e) {
0N/A getHandler().mouseEntered(e);
0N/A }
0N/A
0N/A public void mouseExited(MouseEvent e) {
0N/A getHandler().mouseExited(e);
0N/A }
0N/A
0N/A public void mouseMoved(MouseEvent e) {
0N/A getHandler().mouseMoved(e);
0N/A }
0N/A
0N/A public void mouseDragged(MouseEvent e) {
0N/A getHandler().mouseDragged(e);
0N/A }
0N/A }
0N/A
0N/A private class Handler implements FocusListener, MouseInputListener,
0N/A PropertyChangeListener, ListSelectionListener, ActionListener,
0N/A BeforeDrag {
0N/A
0N/A // FocusListener
0N/A private void repaintLeadCell( ) {
0N/A int lr = getAdjustedLead(table, true);
0N/A int lc = getAdjustedLead(table, false);
0N/A
0N/A if (lr < 0 || lc < 0) {
0N/A return;
0N/A }
0N/A
0N/A Rectangle dirtyRect = table.getCellRect(lr, lc, false);
0N/A table.repaint(dirtyRect);
0N/A }
0N/A
0N/A public void focusGained(FocusEvent e) {
0N/A repaintLeadCell();
0N/A }
0N/A
0N/A public void focusLost(FocusEvent e) {
0N/A repaintLeadCell();
0N/A }
0N/A
0N/A
0N/A // KeyListener
0N/A public void keyPressed(KeyEvent e) { }
0N/A
0N/A public void keyReleased(KeyEvent e) { }
0N/A
0N/A public void keyTyped(KeyEvent e) {
0N/A KeyStroke keyStroke = KeyStroke.getKeyStroke(e.getKeyChar(),
0N/A e.getModifiers());
0N/A
0N/A // We register all actions using ANCESTOR_OF_FOCUSED_COMPONENT
0N/A // which means that we might perform the appropriate action
0N/A // in the table and then forward it to the editor if the editor
0N/A // had focus. Make sure this doesn't happen by checking our
0N/A // InputMaps.
0N/A InputMap map = table.getInputMap(JComponent.WHEN_FOCUSED);
0N/A if (map != null && map.get(keyStroke) != null) {
0N/A return;
0N/A }
0N/A map = table.getInputMap(JComponent.
0N/A WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
0N/A if (map != null && map.get(keyStroke) != null) {
0N/A return;
0N/A }
0N/A
0N/A keyStroke = KeyStroke.getKeyStrokeForEvent(e);
0N/A
0N/A // The AWT seems to generate an unconsumed \r event when
0N/A // ENTER (\n) is pressed.
0N/A if (e.getKeyChar() == '\r') {
0N/A return;
0N/A }
0N/A
0N/A int leadRow = getAdjustedLead(table, true);
0N/A int leadColumn = getAdjustedLead(table, false);
0N/A if (leadRow != -1 && leadColumn != -1 && !table.isEditing()) {
0N/A if (!table.editCellAt(leadRow, leadColumn)) {
0N/A return;
0N/A }
0N/A }
0N/A
0N/A // Forwarding events this way seems to put the component
0N/A // in a state where it believes it has focus. In reality
0N/A // the table retains focus - though it is difficult for
0N/A // a user to tell, since the caret is visible and flashing.
0N/A
0N/A // Calling table.requestFocus() here, to get the focus back to
0N/A // the table, seems to have no effect.
0N/A
0N/A Component editorComp = table.getEditorComponent();
0N/A if (table.isEditing() && editorComp != null) {
0N/A if (editorComp instanceof JComponent) {
0N/A JComponent component = (JComponent)editorComp;
0N/A map = component.getInputMap(JComponent.WHEN_FOCUSED);
0N/A Object binding = (map != null) ? map.get(keyStroke) : null;
0N/A if (binding == null) {
0N/A map = component.getInputMap(JComponent.
0N/A WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
0N/A binding = (map != null) ? map.get(keyStroke) : null;
0N/A }
0N/A if (binding != null) {
0N/A ActionMap am = component.getActionMap();
0N/A Action action = (am != null) ? am.get(binding) : null;
0N/A if (action != null && SwingUtilities.
0N/A notifyAction(action, keyStroke, e, component,
0N/A e.getModifiers())) {
0N/A e.consume();
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A
0N/A // MouseInputListener
0N/A
0N/A // Component receiving mouse events during editing.
0N/A // May not be editorComponent.
0N/A private Component dispatchComponent;
0N/A
0N/A public void mouseClicked(MouseEvent e) {}
0N/A
0N/A private void setDispatchComponent(MouseEvent e) {
0N/A Component editorComponent = table.getEditorComponent();
0N/A Point p = e.getPoint();
0N/A Point p2 = SwingUtilities.convertPoint(table, p, editorComponent);
0N/A dispatchComponent =
0N/A SwingUtilities.getDeepestComponentAt(editorComponent,
0N/A p2.x, p2.y);
0N/A SwingUtilities2.setSkipClickCount(dispatchComponent,
0N/A e.getClickCount() - 1);
0N/A }
0N/A
0N/A private boolean repostEvent(MouseEvent e) {
0N/A // Check for isEditing() in case another event has
0N/A // caused the editor to be removed. See bug #4306499.
0N/A if (dispatchComponent == null || !table.isEditing()) {
0N/A return false;
0N/A }
0N/A MouseEvent e2 = SwingUtilities.convertMouseEvent(table, e,
0N/A dispatchComponent);
0N/A dispatchComponent.dispatchEvent(e2);
0N/A return true;
0N/A }
0N/A
0N/A private void setValueIsAdjusting(boolean flag) {
0N/A table.getSelectionModel().setValueIsAdjusting(flag);
0N/A table.getColumnModel().getSelectionModel().
0N/A setValueIsAdjusting(flag);
0N/A }
0N/A
0N/A // The row and column where the press occurred and the
0N/A // press event itself
0N/A private int pressedRow;
0N/A private int pressedCol;
0N/A private MouseEvent pressedEvent;
0N/A
0N/A // Whether or not the mouse press (which is being considered as part
0N/A // of a drag sequence) also caused the selection change to be fully
0N/A // processed.
0N/A private boolean dragPressDidSelection;
0N/A
0N/A // Set to true when a drag gesture has been fully recognized and DnD
0N/A // begins. Use this to ignore further mouse events which could be
0N/A // delivered if DnD is cancelled (via ESCAPE for example)
0N/A private boolean dragStarted;
0N/A
0N/A // Whether or not we should start the editing timer on release
0N/A private boolean shouldStartTimer;
0N/A
0N/A // To cache the return value of pointOutsidePrefSize since we use
0N/A // it multiple times.
0N/A private boolean outsidePrefSize;
0N/A
0N/A // Used to delay the start of editing.
0N/A private Timer timer = null;
0N/A
0N/A private boolean canStartDrag() {
0N/A if (pressedRow == -1 || pressedCol == -1) {
0N/A return false;
0N/A }
0N/A
0N/A if (isFileList) {
0N/A return !outsidePrefSize;
0N/A }
0N/A
0N/A // if this is a single selection table
0N/A if ((table.getSelectionModel().getSelectionMode() ==
0N/A ListSelectionModel.SINGLE_SELECTION) &&
0N/A (table.getColumnModel().getSelectionModel().getSelectionMode() ==
0N/A ListSelectionModel.SINGLE_SELECTION)) {
0N/A
0N/A return true;
0N/A }
0N/A
0N/A return table.isCellSelected(pressedRow, pressedCol);
0N/A }
0N/A
0N/A public void mousePressed(MouseEvent e) {
0N/A if (SwingUtilities2.shouldIgnore(e, table)) {
0N/A return;
0N/A }
0N/A
0N/A if (table.isEditing() && !table.getCellEditor().stopCellEditing()) {
0N/A Component editorComponent = table.getEditorComponent();
0N/A if (editorComponent != null && !editorComponent.hasFocus()) {
0N/A SwingUtilities2.compositeRequestFocus(editorComponent);
0N/A }
0N/A return;
0N/A }
0N/A
0N/A Point p = e.getPoint();
0N/A pressedRow = table.rowAtPoint(p);
0N/A pressedCol = table.columnAtPoint(p);
0N/A outsidePrefSize = pointOutsidePrefSize(pressedRow, pressedCol, p);
0N/A
0N/A if (isFileList) {
0N/A shouldStartTimer =
0N/A table.isCellSelected(pressedRow, pressedCol) &&
0N/A !e.isShiftDown() &&
1735N/A !BasicGraphicsUtils.isMenuShortcutKeyDown(e) &&
0N/A !outsidePrefSize;
0N/A }
0N/A
0N/A if (table.getDragEnabled()) {
0N/A mousePressedDND(e);
0N/A } else {
0N/A SwingUtilities2.adjustFocus(table);
0N/A if (!isFileList) {
0N/A setValueIsAdjusting(true);
0N/A }
0N/A adjustSelection(e);
0N/A }
0N/A }
0N/A
0N/A private void mousePressedDND(MouseEvent e) {
0N/A pressedEvent = e;
0N/A boolean grabFocus = true;
0N/A dragStarted = false;
0N/A
0N/A if (canStartDrag() && DragRecognitionSupport.mousePressed(e)) {
0N/A
0N/A dragPressDidSelection = false;
0N/A
1735N/A if (BasicGraphicsUtils.isMenuShortcutKeyDown(e) && isFileList) {
0N/A // do nothing for control - will be handled on release
0N/A // or when drag starts
0N/A return;
0N/A } else if (!e.isShiftDown() && table.isCellSelected(pressedRow, pressedCol)) {
0N/A // clicking on something that's already selected
0N/A // and need to make it the lead now
0N/A table.getSelectionModel().addSelectionInterval(pressedRow,
0N/A pressedRow);
0N/A table.getColumnModel().getSelectionModel().
0N/A addSelectionInterval(pressedCol, pressedCol);
0N/A
0N/A return;
0N/A }
0N/A
0N/A dragPressDidSelection = true;
0N/A
0N/A // could be a drag initiating event - don't grab focus
0N/A grabFocus = false;
0N/A } else if (!isFileList) {
0N/A // When drag can't happen, mouse drags might change the selection in the table
0N/A // so we want the isAdjusting flag to be set
0N/A setValueIsAdjusting(true);
0N/A }
0N/A
0N/A if (grabFocus) {
0N/A SwingUtilities2.adjustFocus(table);
0N/A }
0N/A
0N/A adjustSelection(e);
0N/A }
0N/A
0N/A private void adjustSelection(MouseEvent e) {
0N/A // Fix for 4835633
0N/A if (outsidePrefSize) {
0N/A // If shift is down in multi-select, we should just return.
0N/A // For single select or non-shift-click, clear the selection
0N/A if (e.getID() == MouseEvent.MOUSE_PRESSED &&
0N/A (!e.isShiftDown() ||
0N/A table.getSelectionModel().getSelectionMode() ==
0N/A ListSelectionModel.SINGLE_SELECTION)) {
0N/A table.clearSelection();
0N/A TableCellEditor tce = table.getCellEditor();
0N/A if (tce != null) {
0N/A tce.stopCellEditing();
0N/A }
0N/A }
0N/A return;
0N/A }
0N/A // The autoscroller can generate drag events outside the
0N/A // table's range.
0N/A if ((pressedCol == -1) || (pressedRow == -1)) {
0N/A return;
0N/A }
0N/A
0N/A boolean dragEnabled = table.getDragEnabled();
0N/A
0N/A if (!dragEnabled && !isFileList && table.editCellAt(pressedRow, pressedCol, e)) {
0N/A setDispatchComponent(e);
0N/A repostEvent(e);
0N/A }
0N/A
0N/A CellEditor editor = table.getCellEditor();
0N/A if (dragEnabled || editor == null || editor.shouldSelectCell(e)) {
1735N/A table.changeSelection(pressedRow, pressedCol,
1735N/A BasicGraphicsUtils.isMenuShortcutKeyDown(e),
1735N/A e.isShiftDown());
0N/A }
0N/A }
0N/A
0N/A public void valueChanged(ListSelectionEvent e) {
0N/A if (timer != null) {
0N/A timer.stop();
0N/A timer = null;
0N/A }
0N/A }
0N/A
0N/A public void actionPerformed(ActionEvent ae) {
0N/A table.editCellAt(pressedRow, pressedCol, null);
0N/A Component editorComponent = table.getEditorComponent();
0N/A if (editorComponent != null && !editorComponent.hasFocus()) {
0N/A SwingUtilities2.compositeRequestFocus(editorComponent);
0N/A }
0N/A return;
0N/A }
0N/A
0N/A private void maybeStartTimer() {
0N/A if (!shouldStartTimer) {
0N/A return;
0N/A }
0N/A
0N/A if (timer == null) {
0N/A timer = new Timer(1200, this);
0N/A timer.setRepeats(false);
0N/A }
0N/A
0N/A timer.start();
0N/A }
0N/A
0N/A public void mouseReleased(MouseEvent e) {
0N/A if (SwingUtilities2.shouldIgnore(e, table)) {
0N/A return;
0N/A }
0N/A
0N/A if (table.getDragEnabled()) {
0N/A mouseReleasedDND(e);
0N/A } else {
0N/A if (isFileList) {
0N/A maybeStartTimer();
0N/A }
0N/A }
0N/A
0N/A pressedEvent = null;
0N/A repostEvent(e);
0N/A dispatchComponent = null;
0N/A setValueIsAdjusting(false);
0N/A }
0N/A
0N/A private void mouseReleasedDND(MouseEvent e) {
0N/A MouseEvent me = DragRecognitionSupport.mouseReleased(e);
0N/A if (me != null) {
0N/A SwingUtilities2.adjustFocus(table);
0N/A if (!dragPressDidSelection) {
0N/A adjustSelection(me);
0N/A }
0N/A }
0N/A
0N/A if (!dragStarted) {
0N/A if (isFileList) {
0N/A maybeStartTimer();
0N/A return;
0N/A }
0N/A
0N/A Point p = e.getPoint();
0N/A
0N/A if (pressedEvent != null &&
0N/A table.rowAtPoint(p) == pressedRow &&
0N/A table.columnAtPoint(p) == pressedCol &&
0N/A table.editCellAt(pressedRow, pressedCol, pressedEvent)) {
0N/A
0N/A setDispatchComponent(pressedEvent);
0N/A repostEvent(pressedEvent);
0N/A
0N/A // This may appear completely odd, but must be done for backward
0N/A // compatibility reasons. Developers have been known to rely on
0N/A // a call to shouldSelectCell after editing has begun.
0N/A CellEditor ce = table.getCellEditor();
0N/A if (ce != null) {
0N/A ce.shouldSelectCell(pressedEvent);
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A public void mouseEntered(MouseEvent e) {}
0N/A
0N/A public void mouseExited(MouseEvent e) {}
0N/A
0N/A public void mouseMoved(MouseEvent e) {}
0N/A
0N/A public void dragStarting(MouseEvent me) {
0N/A dragStarted = true;
0N/A
1735N/A if (BasicGraphicsUtils.isMenuShortcutKeyDown(me) && isFileList) {
0N/A table.getSelectionModel().addSelectionInterval(pressedRow,
0N/A pressedRow);
0N/A table.getColumnModel().getSelectionModel().
0N/A addSelectionInterval(pressedCol, pressedCol);
0N/A }
0N/A
0N/A pressedEvent = null;
0N/A }
0N/A
0N/A public void mouseDragged(MouseEvent e) {
0N/A if (SwingUtilities2.shouldIgnore(e, table)) {
0N/A return;
0N/A }
0N/A
0N/A if (table.getDragEnabled() &&
0N/A (DragRecognitionSupport.mouseDragged(e, this) || dragStarted)) {
0N/A
0N/A return;
0N/A }
0N/A
0N/A repostEvent(e);
0N/A
0N/A // Check isFileList:
0N/A // Until we support drag-selection, dragging should not change
0N/A // the selection (act like single-select).
0N/A if (isFileList || table.isEditing()) {
0N/A return;
0N/A }
0N/A
0N/A Point p = e.getPoint();
0N/A int row = table.rowAtPoint(p);
0N/A int column = table.columnAtPoint(p);
0N/A // The autoscroller can generate drag events outside the
0N/A // table's range.
0N/A if ((column == -1) || (row == -1)) {
0N/A return;
0N/A }
0N/A
1735N/A table.changeSelection(row, column,
1735N/A BasicGraphicsUtils.isMenuShortcutKeyDown(e), true);
0N/A }
0N/A
0N/A
0N/A // PropertyChangeListener
0N/A public void propertyChange(PropertyChangeEvent event) {
0N/A String changeName = event.getPropertyName();
0N/A
0N/A if ("componentOrientation" == changeName) {
0N/A InputMap inputMap = getInputMap(
0N/A JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
0N/A
0N/A SwingUtilities.replaceUIInputMap(table,
0N/A JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
0N/A inputMap);
0N/A
0N/A JTableHeader header = table.getTableHeader();
0N/A if (header != null) {
0N/A header.setComponentOrientation(
0N/A (ComponentOrientation)event.getNewValue());
0N/A }
0N/A } else if ("dropLocation" == changeName) {
0N/A JTable.DropLocation oldValue = (JTable.DropLocation)event.getOldValue();
0N/A repaintDropLocation(oldValue);
0N/A repaintDropLocation(table.getDropLocation());
0N/A } else if ("Table.isFileList" == changeName) {
0N/A isFileList = Boolean.TRUE.equals(table.getClientProperty("Table.isFileList"));
0N/A table.revalidate();
0N/A table.repaint();
0N/A if (isFileList) {
0N/A table.getSelectionModel().addListSelectionListener(getHandler());
0N/A } else {
0N/A table.getSelectionModel().removeListSelectionListener(getHandler());
0N/A timer = null;
0N/A }
0N/A } else if ("selectionModel" == changeName) {
0N/A if (isFileList) {
0N/A ListSelectionModel old = (ListSelectionModel)event.getOldValue();
0N/A old.removeListSelectionListener(getHandler());
0N/A table.getSelectionModel().addListSelectionListener(getHandler());
0N/A }
0N/A }
0N/A }
0N/A
0N/A private void repaintDropLocation(JTable.DropLocation loc) {
0N/A if (loc == null) {
0N/A return;
0N/A }
0N/A
0N/A if (!loc.isInsertRow() && !loc.isInsertColumn()) {
0N/A Rectangle rect = table.getCellRect(loc.getRow(), loc.getColumn(), false);
0N/A if (rect != null) {
0N/A table.repaint(rect);
0N/A }
0N/A return;
0N/A }
0N/A
0N/A if (loc.isInsertRow()) {
0N/A Rectangle rect = extendRect(getHDropLineRect(loc), true);
0N/A if (rect != null) {
0N/A table.repaint(rect);
0N/A }
0N/A }
0N/A
0N/A if (loc.isInsertColumn()) {
0N/A Rectangle rect = extendRect(getVDropLineRect(loc), false);
0N/A if (rect != null) {
0N/A table.repaint(rect);
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A
0N/A /*
0N/A * Returns true if the given point is outside the preferredSize of the
0N/A * item at the given row of the table. (Column must be 0).
0N/A * Returns false if the "Table.isFileList" client property is not set.
0N/A */
0N/A private boolean pointOutsidePrefSize(int row, int column, Point p) {
0N/A if (!isFileList) {
0N/A return false;
0N/A }
0N/A
0N/A return SwingUtilities2.pointOutsidePrefSize(table, row, column, p);
0N/A }
0N/A
0N/A//
0N/A// Factory methods for the Listeners
0N/A//
0N/A
0N/A private Handler getHandler() {
0N/A if (handler == null) {
0N/A handler = new Handler();
0N/A }
0N/A return handler;
0N/A }
0N/A
0N/A /**
0N/A * Creates the key listener for handling keyboard navigation in the JTable.
0N/A */
0N/A protected KeyListener createKeyListener() {
0N/A return null;
0N/A }
0N/A
0N/A /**
0N/A * Creates the focus listener for handling keyboard navigation in the JTable.
0N/A */
0N/A protected FocusListener createFocusListener() {
0N/A return getHandler();
0N/A }
0N/A
0N/A /**
0N/A * Creates the mouse listener for the JTable.
0N/A */
0N/A protected MouseInputListener createMouseInputListener() {
0N/A return getHandler();
0N/A }
0N/A
0N/A//
0N/A// The installation/uninstall procedures and support
0N/A//
0N/A
0N/A public static ComponentUI createUI(JComponent c) {
0N/A return new BasicTableUI();
0N/A }
0N/A
0N/A// Installation
0N/A
0N/A public void installUI(JComponent c) {
0N/A table = (JTable)c;
0N/A
0N/A rendererPane = new CellRendererPane();
0N/A table.add(rendererPane);
0N/A installDefaults();
0N/A installDefaults2();
0N/A installListeners();
0N/A installKeyboardActions();
0N/A }
0N/A
0N/A /**
0N/A * Initialize JTable properties, e.g. font, foreground, and background.
0N/A * The font, foreground, and background properties are only set if their
0N/A * current value is either null or a UIResource, other properties are set
0N/A * if the current value is null.
0N/A *
0N/A * @see #installUI
0N/A */
0N/A protected void installDefaults() {
0N/A LookAndFeel.installColorsAndFont(table, "Table.background",
0N/A "Table.foreground", "Table.font");
0N/A // JTable's original row height is 16. To correctly display the
0N/A // contents on Linux we should have set it to 18, Windows 19 and
0N/A // Solaris 20. As these values vary so much it's too hard to
0N/A // be backward compatable and try to update the row height, we're
0N/A // therefor NOT going to adjust the row height based on font. If the
0N/A // developer changes the font, it's there responsability to update
0N/A // the row height.
0N/A
0N/A LookAndFeel.installProperty(table, "opaque", Boolean.TRUE);
0N/A
0N/A Color sbg = table.getSelectionBackground();
0N/A if (sbg == null || sbg instanceof UIResource) {
1173N/A sbg = UIManager.getColor("Table.selectionBackground");
1173N/A table.setSelectionBackground(sbg != null ? sbg : UIManager.getColor("textHighlight"));
0N/A }
0N/A
0N/A Color sfg = table.getSelectionForeground();
0N/A if (sfg == null || sfg instanceof UIResource) {
1173N/A sfg = UIManager.getColor("Table.selectionForeground");
1173N/A table.setSelectionForeground(sfg != null ? sfg : UIManager.getColor("textHighlightText"));
0N/A }
0N/A
0N/A Color gridColor = table.getGridColor();
0N/A if (gridColor == null || gridColor instanceof UIResource) {
1173N/A gridColor = UIManager.getColor("Table.gridColor");
1173N/A table.setGridColor(gridColor != null ? gridColor : Color.GRAY);
0N/A }
0N/A
0N/A // install the scrollpane border
6128N/A Container parent = SwingUtilities.getUnwrappedParent(table); // should be viewport
0N/A if (parent != null) {
0N/A parent = parent.getParent(); // should be the scrollpane
0N/A if (parent != null && parent instanceof JScrollPane) {
0N/A LookAndFeel.installBorder((JScrollPane)parent, "Table.scrollPaneBorder");
0N/A }
0N/A }
0N/A
0N/A isFileList = Boolean.TRUE.equals(table.getClientProperty("Table.isFileList"));
0N/A }
0N/A
0N/A private void installDefaults2() {
0N/A TransferHandler th = table.getTransferHandler();
0N/A if (th == null || th instanceof UIResource) {
0N/A table.setTransferHandler(defaultTransferHandler);
0N/A // default TransferHandler doesn't support drop
0N/A // so we don't want drop handling
0N/A if (table.getDropTarget() instanceof UIResource) {
0N/A table.setDropTarget(null);
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Attaches listeners to the JTable.
0N/A */
0N/A protected void installListeners() {
0N/A focusListener = createFocusListener();
0N/A keyListener = createKeyListener();
0N/A mouseInputListener = createMouseInputListener();
0N/A
0N/A table.addFocusListener(focusListener);
0N/A table.addKeyListener(keyListener);
0N/A table.addMouseListener(mouseInputListener);
0N/A table.addMouseMotionListener(mouseInputListener);
0N/A table.addPropertyChangeListener(getHandler());
0N/A if (isFileList) {
0N/A table.getSelectionModel().addListSelectionListener(getHandler());
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Register all keyboard actions on the JTable.
0N/A */
0N/A protected void installKeyboardActions() {
0N/A LazyActionMap.installLazyActionMap(table, BasicTableUI.class,
0N/A "Table.actionMap");
0N/A
0N/A InputMap inputMap = getInputMap(JComponent.
0N/A WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
0N/A SwingUtilities.replaceUIInputMap(table,
0N/A JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT,
0N/A inputMap);
0N/A }
0N/A
0N/A InputMap getInputMap(int condition) {
0N/A if (condition == JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) {
0N/A InputMap keyMap =
0N/A (InputMap)DefaultLookup.get(table, this,
0N/A "Table.ancestorInputMap");
0N/A InputMap rtlKeyMap;
0N/A
0N/A if (table.getComponentOrientation().isLeftToRight() ||
0N/A ((rtlKeyMap = (InputMap)DefaultLookup.get(table, this,
0N/A "Table.ancestorInputMap.RightToLeft")) == null)) {
0N/A return keyMap;
0N/A } else {
0N/A rtlKeyMap.setParent(keyMap);
0N/A return rtlKeyMap;
0N/A }
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A static void loadActionMap(LazyActionMap map) {
0N/A // IMPORTANT: There is a very close coupling between the parameters
0N/A // passed to the Actions constructor. Only certain parameter
0N/A // combinations are supported. For example, the following Action would
0N/A // not work as expected:
0N/A // new Actions(Actions.NEXT_ROW_CELL, 1, 4, false, true)
0N/A // Actions which move within the selection only (having a true
0N/A // inSelection parameter) require that one of dx or dy be
0N/A // zero and the other be -1 or 1. The point of this warning is
0N/A // that you should be very careful about making sure a particular
0N/A // combination of parameters is supported before changing or
0N/A // adding anything here.
0N/A
0N/A map.put(new Actions(Actions.NEXT_COLUMN, 1, 0,
0N/A false, false));
0N/A map.put(new Actions(Actions.NEXT_COLUMN_CHANGE_LEAD, 1, 0,
0N/A false, false));
0N/A map.put(new Actions(Actions.PREVIOUS_COLUMN, -1, 0,
0N/A false, false));
0N/A map.put(new Actions(Actions.PREVIOUS_COLUMN_CHANGE_LEAD, -1, 0,
0N/A false, false));
0N/A map.put(new Actions(Actions.NEXT_ROW, 0, 1,
0N/A false, false));
0N/A map.put(new Actions(Actions.NEXT_ROW_CHANGE_LEAD, 0, 1,
0N/A false, false));
0N/A map.put(new Actions(Actions.PREVIOUS_ROW, 0, -1,
0N/A false, false));
0N/A map.put(new Actions(Actions.PREVIOUS_ROW_CHANGE_LEAD, 0, -1,
0N/A false, false));
0N/A map.put(new Actions(Actions.NEXT_COLUMN_EXTEND_SELECTION,
0N/A 1, 0, true, false));
0N/A map.put(new Actions(Actions.PREVIOUS_COLUMN_EXTEND_SELECTION,
0N/A -1, 0, true, false));
0N/A map.put(new Actions(Actions.NEXT_ROW_EXTEND_SELECTION,
0N/A 0, 1, true, false));
0N/A map.put(new Actions(Actions.PREVIOUS_ROW_EXTEND_SELECTION,
0N/A 0, -1, true, false));
0N/A map.put(new Actions(Actions.SCROLL_UP_CHANGE_SELECTION,
0N/A false, false, true, false));
0N/A map.put(new Actions(Actions.SCROLL_DOWN_CHANGE_SELECTION,
0N/A false, true, true, false));
0N/A map.put(new Actions(Actions.FIRST_COLUMN,
0N/A false, false, false, true));
0N/A map.put(new Actions(Actions.LAST_COLUMN,
0N/A false, true, false, true));
0N/A
0N/A map.put(new Actions(Actions.SCROLL_UP_EXTEND_SELECTION,
0N/A true, false, true, false));
0N/A map.put(new Actions(Actions.SCROLL_DOWN_EXTEND_SELECTION,
0N/A true, true, true, false));
0N/A map.put(new Actions(Actions.FIRST_COLUMN_EXTEND_SELECTION,
0N/A true, false, false, true));
0N/A map.put(new Actions(Actions.LAST_COLUMN_EXTEND_SELECTION,
0N/A true, true, false, true));
0N/A
0N/A map.put(new Actions(Actions.FIRST_ROW, false, false, true, true));
0N/A map.put(new Actions(Actions.LAST_ROW, false, true, true, true));
0N/A
0N/A map.put(new Actions(Actions.FIRST_ROW_EXTEND_SELECTION,
0N/A true, false, true, true));
0N/A map.put(new Actions(Actions.LAST_ROW_EXTEND_SELECTION,
0N/A true, true, true, true));
0N/A
0N/A map.put(new Actions(Actions.NEXT_COLUMN_CELL,
0N/A 1, 0, false, true));
0N/A map.put(new Actions(Actions.PREVIOUS_COLUMN_CELL,
0N/A -1, 0, false, true));
0N/A map.put(new Actions(Actions.NEXT_ROW_CELL, 0, 1, false, true));
0N/A map.put(new Actions(Actions.PREVIOUS_ROW_CELL,
0N/A 0, -1, false, true));
0N/A
0N/A map.put(new Actions(Actions.SELECT_ALL));
0N/A map.put(new Actions(Actions.CLEAR_SELECTION));
0N/A map.put(new Actions(Actions.CANCEL_EDITING));
0N/A map.put(new Actions(Actions.START_EDITING));
0N/A
0N/A map.put(TransferHandler.getCutAction().getValue(Action.NAME),
0N/A TransferHandler.getCutAction());
0N/A map.put(TransferHandler.getCopyAction().getValue(Action.NAME),
0N/A TransferHandler.getCopyAction());
0N/A map.put(TransferHandler.getPasteAction().getValue(Action.NAME),
0N/A TransferHandler.getPasteAction());
0N/A
0N/A map.put(new Actions(Actions.SCROLL_LEFT_CHANGE_SELECTION,
0N/A false, false, false, false));
0N/A map.put(new Actions(Actions.SCROLL_RIGHT_CHANGE_SELECTION,
0N/A false, true, false, false));
0N/A map.put(new Actions(Actions.SCROLL_LEFT_EXTEND_SELECTION,
0N/A true, false, false, false));
0N/A map.put(new Actions(Actions.SCROLL_RIGHT_EXTEND_SELECTION,
0N/A true, true, false, false));
0N/A
0N/A map.put(new Actions(Actions.ADD_TO_SELECTION));
0N/A map.put(new Actions(Actions.TOGGLE_AND_ANCHOR));
0N/A map.put(new Actions(Actions.EXTEND_TO));
0N/A map.put(new Actions(Actions.MOVE_SELECTION_TO));
0N/A map.put(new Actions(Actions.FOCUS_HEADER));
0N/A }
0N/A
0N/A// Uninstallation
0N/A
0N/A public void uninstallUI(JComponent c) {
0N/A uninstallDefaults();
0N/A uninstallListeners();
0N/A uninstallKeyboardActions();
0N/A
0N/A table.remove(rendererPane);
0N/A rendererPane = null;
0N/A table = null;
0N/A }
0N/A
0N/A protected void uninstallDefaults() {
0N/A if (table.getTransferHandler() instanceof UIResource) {
0N/A table.setTransferHandler(null);
0N/A }
0N/A }
0N/A
0N/A protected void uninstallListeners() {
0N/A table.removeFocusListener(focusListener);
0N/A table.removeKeyListener(keyListener);
0N/A table.removeMouseListener(mouseInputListener);
0N/A table.removeMouseMotionListener(mouseInputListener);
0N/A table.removePropertyChangeListener(getHandler());
0N/A if (isFileList) {
0N/A table.getSelectionModel().removeListSelectionListener(getHandler());
0N/A }
0N/A
0N/A focusListener = null;
0N/A keyListener = null;
0N/A mouseInputListener = null;
0N/A handler = null;
0N/A }
0N/A
0N/A protected void uninstallKeyboardActions() {
0N/A SwingUtilities.replaceUIInputMap(table, JComponent.
0N/A WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, null);
0N/A SwingUtilities.replaceUIActionMap(table, null);
0N/A }
0N/A
0N/A /**
0N/A * Returns the baseline.
0N/A *
0N/A * @throws NullPointerException {@inheritDoc}
0N/A * @throws IllegalArgumentException {@inheritDoc}
0N/A * @see javax.swing.JComponent#getBaseline(int, int)
0N/A * @since 1.6
0N/A */
0N/A public int getBaseline(JComponent c, int width, int height) {
0N/A super.getBaseline(c, width, height);
0N/A UIDefaults lafDefaults = UIManager.getLookAndFeelDefaults();
0N/A Component renderer = (Component)lafDefaults.get(
0N/A BASELINE_COMPONENT_KEY);
0N/A if (renderer == null) {
0N/A DefaultTableCellRenderer tcr = new DefaultTableCellRenderer();
0N/A renderer = tcr.getTableCellRendererComponent(
0N/A table, "a", false, false, -1, -1);
0N/A lafDefaults.put(BASELINE_COMPONENT_KEY, renderer);
0N/A }
0N/A renderer.setFont(table.getFont());
0N/A int rowMargin = table.getRowMargin();
0N/A return renderer.getBaseline(Integer.MAX_VALUE, table.getRowHeight() -
0N/A rowMargin) + rowMargin / 2;
0N/A }
0N/A
0N/A /**
0N/A * Returns an enum indicating how the baseline of the component
0N/A * changes as the size changes.
0N/A *
0N/A * @throws NullPointerException {@inheritDoc}
0N/A * @see javax.swing.JComponent#getBaseline(int, int)
0N/A * @since 1.6
0N/A */
0N/A public Component.BaselineResizeBehavior getBaselineResizeBehavior(
0N/A JComponent c) {
0N/A super.getBaselineResizeBehavior(c);
0N/A return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
0N/A }
0N/A
0N/A//
0N/A// Size Methods
0N/A//
0N/A
0N/A private Dimension createTableSize(long width) {
0N/A int height = 0;
0N/A int rowCount = table.getRowCount();
0N/A if (rowCount > 0 && table.getColumnCount() > 0) {
0N/A Rectangle r = table.getCellRect(rowCount-1, 0, true);
0N/A height = r.y + r.height;
0N/A }
0N/A // Width is always positive. The call to abs() is a workaround for
0N/A // a bug in the 1.1.6 JIT on Windows.
0N/A long tmp = Math.abs(width);
0N/A if (tmp > Integer.MAX_VALUE) {
0N/A tmp = Integer.MAX_VALUE;
0N/A }
0N/A return new Dimension((int)tmp, height);
0N/A }
0N/A
0N/A /**
0N/A * Return the minimum size of the table. The minimum height is the
0N/A * row height times the number of rows.
0N/A * The minimum width is the sum of the minimum widths of each column.
0N/A */
0N/A public Dimension getMinimumSize(JComponent c) {
0N/A long width = 0;
0N/A Enumeration enumeration = table.getColumnModel().getColumns();
0N/A while (enumeration.hasMoreElements()) {
0N/A TableColumn aColumn = (TableColumn)enumeration.nextElement();
0N/A width = width + aColumn.getMinWidth();
0N/A }
0N/A return createTableSize(width);
0N/A }
0N/A
0N/A /**
0N/A * Return the preferred size of the table. The preferred height is the
0N/A * row height times the number of rows.
0N/A * The preferred width is the sum of the preferred widths of each column.
0N/A */
0N/A public Dimension getPreferredSize(JComponent c) {
0N/A long width = 0;
0N/A Enumeration enumeration = table.getColumnModel().getColumns();
0N/A while (enumeration.hasMoreElements()) {
0N/A TableColumn aColumn = (TableColumn)enumeration.nextElement();
0N/A width = width + aColumn.getPreferredWidth();
0N/A }
0N/A return createTableSize(width);
0N/A }
0N/A
0N/A /**
0N/A * Return the maximum size of the table. The maximum height is the
0N/A * row heighttimes the number of rows.
0N/A * The maximum width is the sum of the maximum widths of each column.
0N/A */
0N/A public Dimension getMaximumSize(JComponent c) {
0N/A long width = 0;
0N/A Enumeration enumeration = table.getColumnModel().getColumns();
0N/A while (enumeration.hasMoreElements()) {
0N/A TableColumn aColumn = (TableColumn)enumeration.nextElement();
0N/A width = width + aColumn.getMaxWidth();
0N/A }
0N/A return createTableSize(width);
0N/A }
0N/A
0N/A//
0N/A// Paint methods and support
0N/A//
0N/A
0N/A /** Paint a representation of the <code>table</code> instance
0N/A * that was set in installUI().
0N/A */
0N/A public void paint(Graphics g, JComponent c) {
0N/A Rectangle clip = g.getClipBounds();
0N/A
0N/A Rectangle bounds = table.getBounds();
0N/A // account for the fact that the graphics has already been translated
0N/A // into the table's bounds
0N/A bounds.x = bounds.y = 0;
0N/A
0N/A if (table.getRowCount() <= 0 || table.getColumnCount() <= 0 ||
0N/A // this check prevents us from painting the entire table
0N/A // when the clip doesn't intersect our bounds at all
0N/A !bounds.intersects(clip)) {
0N/A
0N/A paintDropLines(g);
0N/A return;
0N/A }
0N/A
0N/A boolean ltr = table.getComponentOrientation().isLeftToRight();
0N/A
0N/A Point upperLeft = clip.getLocation();
0N/A Point lowerRight = new Point(clip.x + clip.width - 1,
0N/A clip.y + clip.height - 1);
0N/A
0N/A int rMin = table.rowAtPoint(upperLeft);
0N/A int rMax = table.rowAtPoint(lowerRight);
0N/A // This should never happen (as long as our bounds intersect the clip,
0N/A // which is why we bail above if that is the case).
0N/A if (rMin == -1) {
0N/A rMin = 0;
0N/A }
0N/A // If the table does not have enough rows to fill the view we'll get -1.
0N/A // (We could also get -1 if our bounds don't intersect the clip,
0N/A // which is why we bail above if that is the case).
0N/A // Replace this with the index of the last row.
0N/A if (rMax == -1) {
0N/A rMax = table.getRowCount()-1;
0N/A }
0N/A
0N/A int cMin = table.columnAtPoint(ltr ? upperLeft : lowerRight);
0N/A int cMax = table.columnAtPoint(ltr ? lowerRight : upperLeft);
0N/A // This should never happen.
0N/A if (cMin == -1) {
0N/A cMin = 0;
0N/A }
0N/A // If the table does not have enough columns to fill the view we'll get -1.
0N/A // Replace this with the index of the last column.
0N/A if (cMax == -1) {
0N/A cMax = table.getColumnCount()-1;
0N/A }
0N/A
0N/A // Paint the grid.
0N/A paintGrid(g, rMin, rMax, cMin, cMax);
0N/A
0N/A // Paint the cells.
0N/A paintCells(g, rMin, rMax, cMin, cMax);
0N/A
0N/A paintDropLines(g);
0N/A }
0N/A
0N/A private void paintDropLines(Graphics g) {
0N/A JTable.DropLocation loc = table.getDropLocation();
0N/A if (loc == null) {
0N/A return;
0N/A }
0N/A
0N/A Color color = UIManager.getColor("Table.dropLineColor");
0N/A Color shortColor = UIManager.getColor("Table.dropLineShortColor");
0N/A if (color == null && shortColor == null) {
0N/A return;
0N/A }
0N/A
0N/A Rectangle rect;
0N/A
0N/A rect = getHDropLineRect(loc);
0N/A if (rect != null) {
0N/A int x = rect.x;
0N/A int w = rect.width;
0N/A if (color != null) {
0N/A extendRect(rect, true);
0N/A g.setColor(color);
0N/A g.fillRect(rect.x, rect.y, rect.width, rect.height);
0N/A }
0N/A if (!loc.isInsertColumn() && shortColor != null) {
0N/A g.setColor(shortColor);
0N/A g.fillRect(x, rect.y, w, rect.height);
0N/A }
0N/A }
0N/A
0N/A rect = getVDropLineRect(loc);
0N/A if (rect != null) {
0N/A int y = rect.y;
0N/A int h = rect.height;
0N/A if (color != null) {
0N/A extendRect(rect, false);
0N/A g.setColor(color);
0N/A g.fillRect(rect.x, rect.y, rect.width, rect.height);
0N/A }
0N/A if (!loc.isInsertRow() && shortColor != null) {
0N/A g.setColor(shortColor);
0N/A g.fillRect(rect.x, y, rect.width, h);
0N/A }
0N/A }
0N/A }
0N/A
0N/A private Rectangle getHDropLineRect(JTable.DropLocation loc) {
0N/A if (!loc.isInsertRow()) {
0N/A return null;
0N/A }
0N/A
0N/A int row = loc.getRow();
0N/A int col = loc.getColumn();
0N/A if (col >= table.getColumnCount()) {
0N/A col--;
0N/A }
0N/A
0N/A Rectangle rect = table.getCellRect(row, col, true);
0N/A
0N/A if (row >= table.getRowCount()) {
0N/A row--;
0N/A Rectangle prevRect = table.getCellRect(row, col, true);
0N/A rect.y = prevRect.y + prevRect.height;
0N/A }
0N/A
0N/A if (rect.y == 0) {
0N/A rect.y = -1;
0N/A } else {
0N/A rect.y -= 2;
0N/A }
0N/A
0N/A rect.height = 3;
0N/A
0N/A return rect;
0N/A }
0N/A
0N/A private Rectangle getVDropLineRect(JTable.DropLocation loc) {
0N/A if (!loc.isInsertColumn()) {
0N/A return null;
0N/A }
0N/A
0N/A boolean ltr = table.getComponentOrientation().isLeftToRight();
0N/A int col = loc.getColumn();
0N/A Rectangle rect = table.getCellRect(loc.getRow(), col, true);
0N/A
0N/A if (col >= table.getColumnCount()) {
0N/A col--;
0N/A rect = table.getCellRect(loc.getRow(), col, true);
0N/A if (ltr) {
0N/A rect.x = rect.x + rect.width;
0N/A }
0N/A } else if (!ltr) {
0N/A rect.x = rect.x + rect.width;
0N/A }
0N/A
0N/A if (rect.x == 0) {
0N/A rect.x = -1;
0N/A } else {
0N/A rect.x -= 2;
0N/A }
0N/A
0N/A rect.width = 3;
0N/A
0N/A return rect;
0N/A }
0N/A
0N/A private Rectangle extendRect(Rectangle rect, boolean horizontal) {
0N/A if (rect == null) {
0N/A return rect;
0N/A }
0N/A
0N/A if (horizontal) {
0N/A rect.x = 0;
0N/A rect.width = table.getWidth();
0N/A } else {
0N/A rect.y = 0;
0N/A
0N/A if (table.getRowCount() != 0) {
0N/A Rectangle lastRect = table.getCellRect(table.getRowCount() - 1, 0, true);
0N/A rect.height = lastRect.y + lastRect.height;
0N/A } else {
0N/A rect.height = table.getHeight();
0N/A }
0N/A }
0N/A
0N/A return rect;
0N/A }
0N/A
0N/A /*
0N/A * Paints the grid lines within <I>aRect</I>, using the grid
0N/A * color set with <I>setGridColor</I>. Paints vertical lines
0N/A * if <code>getShowVerticalLines()</code> returns true and paints
0N/A * horizontal lines if <code>getShowHorizontalLines()</code>
0N/A * returns true.
0N/A */
0N/A private void paintGrid(Graphics g, int rMin, int rMax, int cMin, int cMax) {
0N/A g.setColor(table.getGridColor());
0N/A
0N/A Rectangle minCell = table.getCellRect(rMin, cMin, true);
0N/A Rectangle maxCell = table.getCellRect(rMax, cMax, true);
0N/A Rectangle damagedArea = minCell.union( maxCell );
0N/A
0N/A if (table.getShowHorizontalLines()) {
0N/A int tableWidth = damagedArea.x + damagedArea.width;
0N/A int y = damagedArea.y;
0N/A for (int row = rMin; row <= rMax; row++) {
0N/A y += table.getRowHeight(row);
0N/A g.drawLine(damagedArea.x, y - 1, tableWidth - 1, y - 1);
0N/A }
0N/A }
0N/A if (table.getShowVerticalLines()) {
0N/A TableColumnModel cm = table.getColumnModel();
0N/A int tableHeight = damagedArea.y + damagedArea.height;
0N/A int x;
0N/A if (table.getComponentOrientation().isLeftToRight()) {
0N/A x = damagedArea.x;
0N/A for (int column = cMin; column <= cMax; column++) {
0N/A int w = cm.getColumn(column).getWidth();
0N/A x += w;
0N/A g.drawLine(x - 1, 0, x - 1, tableHeight - 1);
0N/A }
0N/A } else {
0N/A x = damagedArea.x;
0N/A for (int column = cMax; column >= cMin; column--) {
0N/A int w = cm.getColumn(column).getWidth();
0N/A x += w;
0N/A g.drawLine(x - 1, 0, x - 1, tableHeight - 1);
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A private int viewIndexForColumn(TableColumn aColumn) {
0N/A TableColumnModel cm = table.getColumnModel();
0N/A for (int column = 0; column < cm.getColumnCount(); column++) {
0N/A if (cm.getColumn(column) == aColumn) {
0N/A return column;
0N/A }
0N/A }
0N/A return -1;
0N/A }
0N/A
0N/A private void paintCells(Graphics g, int rMin, int rMax, int cMin, int cMax) {
0N/A JTableHeader header = table.getTableHeader();
0N/A TableColumn draggedColumn = (header == null) ? null : header.getDraggedColumn();
0N/A
0N/A TableColumnModel cm = table.getColumnModel();
0N/A int columnMargin = cm.getColumnMargin();
0N/A
0N/A Rectangle cellRect;
0N/A TableColumn aColumn;
0N/A int columnWidth;
0N/A if (table.getComponentOrientation().isLeftToRight()) {
0N/A for(int row = rMin; row <= rMax; row++) {
0N/A cellRect = table.getCellRect(row, cMin, false);
0N/A for(int column = cMin; column <= cMax; column++) {
0N/A aColumn = cm.getColumn(column);
0N/A columnWidth = aColumn.getWidth();
0N/A cellRect.width = columnWidth - columnMargin;
0N/A if (aColumn != draggedColumn) {
0N/A paintCell(g, cellRect, row, column);
0N/A }
0N/A cellRect.x += columnWidth;
0N/A }
0N/A }
0N/A } else {
0N/A for(int row = rMin; row <= rMax; row++) {
0N/A cellRect = table.getCellRect(row, cMin, false);
0N/A aColumn = cm.getColumn(cMin);
0N/A if (aColumn != draggedColumn) {
0N/A columnWidth = aColumn.getWidth();
0N/A cellRect.width = columnWidth - columnMargin;
0N/A paintCell(g, cellRect, row, cMin);
0N/A }
0N/A for(int column = cMin+1; column <= cMax; column++) {
0N/A aColumn = cm.getColumn(column);
0N/A columnWidth = aColumn.getWidth();
0N/A cellRect.width = columnWidth - columnMargin;
0N/A cellRect.x -= columnWidth;
0N/A if (aColumn != draggedColumn) {
0N/A paintCell(g, cellRect, row, column);
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A // Paint the dragged column if we are dragging.
0N/A if (draggedColumn != null) {
0N/A paintDraggedArea(g, rMin, rMax, draggedColumn, header.getDraggedDistance());
0N/A }
0N/A
0N/A // Remove any renderers that may be left in the rendererPane.
0N/A rendererPane.removeAll();
0N/A }
0N/A
0N/A private void paintDraggedArea(Graphics g, int rMin, int rMax, TableColumn draggedColumn, int distance) {
0N/A int draggedColumnIndex = viewIndexForColumn(draggedColumn);
0N/A
0N/A Rectangle minCell = table.getCellRect(rMin, draggedColumnIndex, true);
0N/A Rectangle maxCell = table.getCellRect(rMax, draggedColumnIndex, true);
0N/A
0N/A Rectangle vacatedColumnRect = minCell.union(maxCell);
0N/A
0N/A // Paint a gray well in place of the moving column.
0N/A g.setColor(table.getParent().getBackground());
0N/A g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,
0N/A vacatedColumnRect.width, vacatedColumnRect.height);
0N/A
0N/A // Move to the where the cell has been dragged.
0N/A vacatedColumnRect.x += distance;
0N/A
0N/A // Fill the background.
0N/A g.setColor(table.getBackground());
0N/A g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,
0N/A vacatedColumnRect.width, vacatedColumnRect.height);
0N/A
0N/A // Paint the vertical grid lines if necessary.
0N/A if (table.getShowVerticalLines()) {
0N/A g.setColor(table.getGridColor());
0N/A int x1 = vacatedColumnRect.x;
0N/A int y1 = vacatedColumnRect.y;
0N/A int x2 = x1 + vacatedColumnRect.width - 1;
0N/A int y2 = y1 + vacatedColumnRect.height - 1;
0N/A // Left
0N/A g.drawLine(x1-1, y1, x1-1, y2);
0N/A // Right
0N/A g.drawLine(x2, y1, x2, y2);
0N/A }
0N/A
0N/A for(int row = rMin; row <= rMax; row++) {
0N/A // Render the cell value
0N/A Rectangle r = table.getCellRect(row, draggedColumnIndex, false);
0N/A r.x += distance;
0N/A paintCell(g, r, row, draggedColumnIndex);
0N/A
0N/A // Paint the (lower) horizontal grid line if necessary.
0N/A if (table.getShowHorizontalLines()) {
0N/A g.setColor(table.getGridColor());
0N/A Rectangle rcr = table.getCellRect(row, draggedColumnIndex, true);
0N/A rcr.x += distance;
0N/A int x1 = rcr.x;
0N/A int y1 = rcr.y;
0N/A int x2 = x1 + rcr.width - 1;
0N/A int y2 = y1 + rcr.height - 1;
0N/A g.drawLine(x1, y2, x2, y2);
0N/A }
0N/A }
0N/A }
0N/A
0N/A private void paintCell(Graphics g, Rectangle cellRect, int row, int column) {
0N/A if (table.isEditing() && table.getEditingRow()==row &&
0N/A table.getEditingColumn()==column) {
0N/A Component component = table.getEditorComponent();
0N/A component.setBounds(cellRect);
0N/A component.validate();
0N/A }
0N/A else {
0N/A TableCellRenderer renderer = table.getCellRenderer(row, column);
0N/A Component component = table.prepareRenderer(renderer, row, column);
0N/A rendererPane.paintComponent(g, component, table, cellRect.x, cellRect.y,
0N/A cellRect.width, cellRect.height, true);
0N/A }
0N/A }
0N/A
0N/A private static int getAdjustedLead(JTable table,
0N/A boolean row,
0N/A ListSelectionModel model) {
0N/A
0N/A int index = model.getLeadSelectionIndex();
0N/A int compare = row ? table.getRowCount() : table.getColumnCount();
0N/A return index < compare ? index : -1;
0N/A }
0N/A
0N/A private static int getAdjustedLead(JTable table, boolean row) {
0N/A return row ? getAdjustedLead(table, row, table.getSelectionModel())
0N/A : getAdjustedLead(table, row, table.getColumnModel().getSelectionModel());
0N/A }
0N/A
0N/A
0N/A private static final TransferHandler defaultTransferHandler = new TableTransferHandler();
0N/A
0N/A static class TableTransferHandler extends TransferHandler implements UIResource {
0N/A
0N/A /**
0N/A * Create a Transferable to use as the source for a data transfer.
0N/A *
0N/A * @param c The component holding the data to be transfered. This
0N/A * argument is provided to enable sharing of TransferHandlers by
0N/A * multiple components.
0N/A * @return The representation of the data to be transfered.
0N/A *
0N/A */
0N/A protected Transferable createTransferable(JComponent c) {
0N/A if (c instanceof JTable) {
0N/A JTable table = (JTable) c;
0N/A int[] rows;
0N/A int[] cols;
0N/A
0N/A if (!table.getRowSelectionAllowed() && !table.getColumnSelectionAllowed()) {
0N/A return null;
0N/A }
0N/A
0N/A if (!table.getRowSelectionAllowed()) {
0N/A int rowCount = table.getRowCount();
0N/A
0N/A rows = new int[rowCount];
0N/A for (int counter = 0; counter < rowCount; counter++) {
0N/A rows[counter] = counter;
0N/A }
0N/A } else {
0N/A rows = table.getSelectedRows();
0N/A }
0N/A
0N/A if (!table.getColumnSelectionAllowed()) {
0N/A int colCount = table.getColumnCount();
0N/A
0N/A cols = new int[colCount];
0N/A for (int counter = 0; counter < colCount; counter++) {
0N/A cols[counter] = counter;
0N/A }
0N/A } else {
0N/A cols = table.getSelectedColumns();
0N/A }
0N/A
0N/A if (rows == null || cols == null || rows.length == 0 || cols.length == 0) {
0N/A return null;
0N/A }
0N/A
0N/A StringBuffer plainBuf = new StringBuffer();
0N/A StringBuffer htmlBuf = new StringBuffer();
0N/A
0N/A htmlBuf.append("<html>\n<body>\n<table>\n");
0N/A
0N/A for (int row = 0; row < rows.length; row++) {
0N/A htmlBuf.append("<tr>\n");
0N/A for (int col = 0; col < cols.length; col++) {
0N/A Object obj = table.getValueAt(rows[row], cols[col]);
0N/A String val = ((obj == null) ? "" : obj.toString());
0N/A plainBuf.append(val + "\t");
0N/A htmlBuf.append(" <td>" + val + "</td>\n");
0N/A }
0N/A // we want a newline at the end of each line and not a tab
0N/A plainBuf.deleteCharAt(plainBuf.length() - 1).append("\n");
0N/A htmlBuf.append("</tr>\n");
0N/A }
0N/A
0N/A // remove the last newline
0N/A plainBuf.deleteCharAt(plainBuf.length() - 1);
0N/A htmlBuf.append("</table>\n</body>\n</html>");
0N/A
0N/A return new BasicTransferable(plainBuf.toString(), htmlBuf.toString());
0N/A }
0N/A
0N/A return null;
0N/A }
0N/A
0N/A public int getSourceActions(JComponent c) {
0N/A return COPY;
0N/A }
0N/A
0N/A }
0N/A} // End of Class BasicTableUI