0N/A/*
3909N/A * Copyright (c) 1997, 2010, 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.event.*;
0N/Aimport java.util.*;
0N/Aimport javax.swing.*;
0N/Aimport javax.swing.event.*;
0N/Aimport javax.swing.plaf.*;
0N/Aimport javax.swing.table.*;
0N/A
0N/Aimport sun.swing.*;
0N/A
0N/A/**
0N/A * BasicTableHeaderUI implementation
0N/A *
0N/A * @author Alan Chung
0N/A * @author Philip Milne
0N/A */
0N/Apublic class BasicTableHeaderUI extends TableHeaderUI {
0N/A
0N/A private static Cursor resizeCursor = Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR);
0N/A
0N/A//
0N/A// Instance Variables
0N/A//
0N/A
0N/A /** The JTableHeader that is delegating the painting to this UI. */
0N/A protected JTableHeader header;
0N/A protected CellRendererPane rendererPane;
0N/A
0N/A // Listeners that are attached to the JTable
0N/A protected MouseInputListener mouseInputListener;
0N/A
0N/A // The column header over which the mouse currently is.
0N/A private int rolloverColumn = -1;
0N/A
0N/A // The column that should be highlighted when the table header has the focus.
0N/A private int selectedColumnIndex = 0; // Read ONLY via getSelectedColumnIndex!
0N/A
0N/A private static FocusListener focusListener = new FocusListener() {
0N/A public void focusGained(FocusEvent e) {
41N/A repaintHeader(e.getSource());
41N/A }
41N/A
41N/A public void focusLost(FocusEvent e) {
41N/A repaintHeader(e.getSource());
0N/A }
0N/A
0N/A private void repaintHeader(Object source) {
0N/A if (source instanceof JTableHeader) {
0N/A JTableHeader th = (JTableHeader)source;
0N/A BasicTableHeaderUI ui =
0N/A (BasicTableHeaderUI)BasicLookAndFeel.
0N/A getUIOfType(th.getUI(),
0N/A BasicTableHeaderUI.class);
0N/A if (ui == null) {
0N/A return;
0N/A }
0N/A
0N/A th.repaint(th.getHeaderRect(ui.getSelectedColumnIndex()));
0N/A }
0N/A }
0N/A };
0N/A
0N/A /**
0N/A * This class should be treated as a "protected" inner class.
0N/A * Instantiate it only within subclasses of {@code BasicTableHeaderUI}.
0N/A */
0N/A public class MouseInputHandler implements MouseInputListener {
0N/A
0N/A private int mouseXOffset;
0N/A private Cursor otherCursor = resizeCursor;
0N/A
0N/A public void mouseClicked(MouseEvent e) {
0N/A if (!header.isEnabled()) {
0N/A return;
0N/A }
0N/A if (e.getClickCount() % 2 == 1 &&
0N/A SwingUtilities.isLeftMouseButton(e)) {
0N/A JTable table = header.getTable();
0N/A RowSorter sorter;
0N/A if (table != null && (sorter = table.getRowSorter()) != null) {
0N/A int columnIndex = header.columnAtPoint(e.getPoint());
0N/A if (columnIndex != -1) {
0N/A columnIndex = table.convertColumnIndexToModel(
0N/A columnIndex);
0N/A sorter.toggleSortOrder(columnIndex);
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A private TableColumn getResizingColumn(Point p) {
0N/A return getResizingColumn(p, header.columnAtPoint(p));
0N/A }
0N/A
0N/A private TableColumn getResizingColumn(Point p, int column) {
0N/A if (column == -1) {
0N/A return null;
0N/A }
0N/A Rectangle r = header.getHeaderRect(column);
0N/A r.grow(-3, 0);
0N/A if (r.contains(p)) {
0N/A return null;
0N/A }
0N/A int midPoint = r.x + r.width/2;
0N/A int columnIndex;
0N/A if( header.getComponentOrientation().isLeftToRight() ) {
0N/A columnIndex = (p.x < midPoint) ? column - 1 : column;
0N/A } else {
0N/A columnIndex = (p.x < midPoint) ? column : column - 1;
0N/A }
0N/A if (columnIndex == -1) {
0N/A return null;
0N/A }
0N/A return header.getColumnModel().getColumn(columnIndex);
0N/A }
0N/A
0N/A public void mousePressed(MouseEvent e) {
0N/A if (!header.isEnabled()) {
0N/A return;
0N/A }
0N/A header.setDraggedColumn(null);
0N/A header.setResizingColumn(null);
0N/A header.setDraggedDistance(0);
0N/A
0N/A Point p = e.getPoint();
0N/A
0N/A // First find which header cell was hit
0N/A TableColumnModel columnModel = header.getColumnModel();
0N/A int index = header.columnAtPoint(p);
0N/A
0N/A if (index != -1) {
0N/A // The last 3 pixels + 3 pixels of next column are for resizing
0N/A TableColumn resizingColumn = getResizingColumn(p, index);
0N/A if (canResize(resizingColumn, header)) {
0N/A header.setResizingColumn(resizingColumn);
0N/A if( header.getComponentOrientation().isLeftToRight() ) {
0N/A mouseXOffset = p.x - resizingColumn.getWidth();
0N/A } else {
0N/A mouseXOffset = p.x + resizingColumn.getWidth();
0N/A }
0N/A }
0N/A else if (header.getReorderingAllowed()) {
0N/A TableColumn hitColumn = columnModel.getColumn(index);
0N/A header.setDraggedColumn(hitColumn);
0N/A mouseXOffset = p.x;
0N/A }
0N/A }
0N/A
0N/A if (header.getReorderingAllowed()) {
0N/A int oldRolloverColumn = rolloverColumn;
0N/A rolloverColumn = -1;
0N/A rolloverColumnUpdated(oldRolloverColumn, rolloverColumn);
0N/A }
0N/A }
0N/A
0N/A private void swapCursor() {
0N/A Cursor tmp = header.getCursor();
0N/A header.setCursor(otherCursor);
0N/A otherCursor = tmp;
0N/A }
0N/A
0N/A public void mouseMoved(MouseEvent e) {
0N/A if (!header.isEnabled()) {
0N/A return;
0N/A }
0N/A if (canResize(getResizingColumn(e.getPoint()), header) !=
0N/A (header.getCursor() == resizeCursor)) {
0N/A swapCursor();
0N/A }
0N/A updateRolloverColumn(e);
0N/A }
0N/A
0N/A public void mouseDragged(MouseEvent e) {
0N/A if (!header.isEnabled()) {
0N/A return;
0N/A }
0N/A int mouseX = e.getX();
0N/A
0N/A TableColumn resizingColumn = header.getResizingColumn();
0N/A TableColumn draggedColumn = header.getDraggedColumn();
0N/A
0N/A boolean headerLeftToRight = header.getComponentOrientation().isLeftToRight();
0N/A
0N/A if (resizingColumn != null) {
0N/A int oldWidth = resizingColumn.getWidth();
0N/A int newWidth;
0N/A if (headerLeftToRight) {
0N/A newWidth = mouseX - mouseXOffset;
0N/A } else {
0N/A newWidth = mouseXOffset - mouseX;
0N/A }
0N/A mouseXOffset += changeColumnWidth(resizingColumn, header,
0N/A oldWidth, newWidth);
0N/A }
0N/A else if (draggedColumn != null) {
0N/A TableColumnModel cm = header.getColumnModel();
0N/A int draggedDistance = mouseX - mouseXOffset;
2979N/A int direction = (draggedDistance < 0) ? -1 : 1;
2979N/A int columnIndex = viewIndexForColumn(draggedColumn);
2979N/A int newColumnIndex = columnIndex + (headerLeftToRight ? direction : -direction);
2979N/A if (0 <= newColumnIndex && newColumnIndex < cm.getColumnCount()) {
0N/A int width = cm.getColumn(newColumnIndex).getWidth();
0N/A if (Math.abs(draggedDistance) > (width / 2)) {
0N/A
0N/A mouseXOffset = mouseXOffset + direction * width;
0N/A header.setDraggedDistance(draggedDistance - direction * width);
0N/A
0N/A //Cache the selected column.
0N/A int selectedIndex =
0N/A SwingUtilities2.convertColumnIndexToModel(
0N/A header.getColumnModel(),
0N/A getSelectedColumnIndex());
2350N/A
2350N/A //Now do the move.
2350N/A cm.moveColumn(columnIndex, newColumnIndex);
2350N/A
2350N/A //Update the selected index.
2350N/A selectColumn(
2350N/A SwingUtilities2.convertColumnIndexToView(
2350N/A header.getColumnModel(), selectedIndex),
2350N/A false);
2350N/A
2350N/A return;
2350N/A }
2350N/A }
2350N/A setDraggedDistance(draggedDistance, columnIndex);
2350N/A }
0N/A
2350N/A updateRolloverColumn(e);
2350N/A }
2350N/A
2350N/A public void mouseReleased(MouseEvent e) {
2350N/A if (!header.isEnabled()) {
2350N/A return;
2350N/A }
2350N/A setDraggedDistance(0, viewIndexForColumn(header.getDraggedColumn()));
2350N/A
2350N/A header.setResizingColumn(null);
2350N/A header.setDraggedColumn(null);
2350N/A
2350N/A updateRolloverColumn(e);
2350N/A }
2350N/A
0N/A public void mouseEntered(MouseEvent e) {
0N/A if (!header.isEnabled()) {
0N/A return;
0N/A }
0N/A updateRolloverColumn(e);
0N/A }
0N/A
0N/A public void mouseExited(MouseEvent e) {
0N/A if (!header.isEnabled()) {
0N/A return;
0N/A }
0N/A int oldRolloverColumn = rolloverColumn;
0N/A rolloverColumn = -1;
0N/A rolloverColumnUpdated(oldRolloverColumn, rolloverColumn);
0N/A }
0N/A//
0N/A// Protected & Private Methods
0N/A//
0N/A
0N/A private void setDraggedDistance(int draggedDistance, int column) {
0N/A header.setDraggedDistance(draggedDistance);
0N/A if (column != -1) {
0N/A header.getColumnModel().moveColumn(column, column);
0N/A }
0N/A }
0N/A }
0N/A
0N/A//
0N/A// Factory methods for the Listeners
0N/A//
0N/A
0N/A /**
0N/A * Creates the mouse listener for the JTableHeader.
0N/A */
0N/A protected MouseInputListener createMouseInputListener() {
0N/A return new MouseInputHandler();
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 h) {
0N/A return new BasicTableHeaderUI();
0N/A }
0N/A
0N/A// Installation
0N/A
0N/A public void installUI(JComponent c) {
0N/A header = (JTableHeader)c;
0N/A
0N/A rendererPane = new CellRendererPane();
0N/A header.add(rendererPane);
0N/A
0N/A installDefaults();
0N/A installListeners();
0N/A installKeyboardActions();
0N/A }
0N/A
0N/A /**
0N/A * Initializes JTableHeader properties such as 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(header, "TableHeader.background",
0N/A "TableHeader.foreground", "TableHeader.font");
0N/A LookAndFeel.installProperty(header, "opaque", Boolean.TRUE);
0N/A }
0N/A
0N/A /**
0N/A * Attaches listeners to the JTableHeader.
0N/A */
0N/A protected void installListeners() {
0N/A mouseInputListener = createMouseInputListener();
0N/A
0N/A header.addMouseListener(mouseInputListener);
0N/A header.addMouseMotionListener(mouseInputListener);
0N/A header.addFocusListener(focusListener);
0N/A }
0N/A
0N/A /**
0N/A * Register all keyboard actions on the JTableHeader.
0N/A */
0N/A protected void installKeyboardActions() {
0N/A InputMap keyMap = (InputMap)DefaultLookup.get(header, this,
0N/A "TableHeader.ancestorInputMap");
0N/A SwingUtilities.replaceUIInputMap(header,
0N/A JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, keyMap);
0N/A LazyActionMap.installLazyActionMap(header, BasicTableHeaderUI.class,
0N/A "TableHeader.actionMap");
0N/A }
0N/A
0N/A// Uninstall methods
0N/A
0N/A public void uninstallUI(JComponent c) {
0N/A uninstallDefaults();
0N/A uninstallListeners();
0N/A uninstallKeyboardActions();
0N/A
0N/A header.remove(rendererPane);
0N/A rendererPane = null;
0N/A header = null;
0N/A }
0N/A
0N/A protected void uninstallDefaults() {}
0N/A
0N/A protected void uninstallListeners() {
0N/A header.removeMouseListener(mouseInputListener);
0N/A header.removeMouseMotionListener(mouseInputListener);
0N/A
0N/A mouseInputListener = null;
0N/A }
0N/A
0N/A /**
0N/A * Unregisters default key actions.
0N/A */
0N/A protected void uninstallKeyboardActions() {
0N/A SwingUtilities.replaceUIInputMap(header, JComponent.WHEN_FOCUSED, null);
0N/A SwingUtilities.replaceUIActionMap(header, null);
0N/A }
0N/A
0N/A /**
0N/A * Populates TableHeader's actions.
0N/A */
0N/A static void loadActionMap(LazyActionMap map) {
0N/A map.put(new Actions(Actions.TOGGLE_SORT_ORDER));
0N/A map.put(new Actions(Actions.SELECT_COLUMN_TO_LEFT));
0N/A map.put(new Actions(Actions.SELECT_COLUMN_TO_RIGHT));
0N/A map.put(new Actions(Actions.MOVE_COLUMN_LEFT));
0N/A map.put(new Actions(Actions.MOVE_COLUMN_RIGHT));
0N/A map.put(new Actions(Actions.RESIZE_LEFT));
0N/A map.put(new Actions(Actions.RESIZE_RIGHT));
0N/A map.put(new Actions(Actions.FOCUS_TABLE));
0N/A }
0N/A
0N/A//
0N/A// Support for mouse rollover
0N/A//
0N/A
0N/A /**
0N/A * Returns the index of the column header over which the mouse
0N/A * currently is. When the mouse is not over the table header,
0N/A * -1 is returned.
0N/A *
0N/A * @see #rolloverColumnUpdated(int, int)
0N/A * @return the index of the current rollover column
0N/A * @since 1.6
0N/A */
0N/A protected int getRolloverColumn() {
0N/A return rolloverColumn;
0N/A }
0N/A
0N/A /**
0N/A * This method gets called every time when a rollover column in the table
0N/A * header is updated. Every look and feel that supports a rollover effect
0N/A * in a table header should override this method and repaint the header.
0N/A *
0N/A * @param oldColumn the index of the previous rollover column or -1 if the
0N/A * mouse was not over a column
0N/A * @param newColumn the index of the new rollover column or -1 if the mouse
0N/A * is not over a column
0N/A * @see #getRolloverColumn()
0N/A * @see JTableHeader#getHeaderRect(int)
0N/A * @since 1.6
0N/A */
0N/A protected void rolloverColumnUpdated(int oldColumn, int newColumn) {
0N/A }
0N/A
0N/A private void updateRolloverColumn(MouseEvent e) {
0N/A if (header.getDraggedColumn() == null &&
0N/A header.contains(e.getPoint())) {
0N/A
0N/A int col = header.columnAtPoint(e.getPoint());
0N/A if (col != rolloverColumn) {
0N/A int oldRolloverColumn = rolloverColumn;
0N/A rolloverColumn = col;
0N/A rolloverColumnUpdated(oldRolloverColumn, rolloverColumn);
0N/A }
0N/A }
0N/A }
0N/A
0N/A//
0N/A// Support for keyboard and mouse access
0N/A//
0N/A private int selectNextColumn(boolean doIt) {
0N/A int newIndex = getSelectedColumnIndex();
0N/A if (newIndex < header.getColumnModel().getColumnCount() - 1) {
0N/A newIndex++;
0N/A if (doIt) {
0N/A selectColumn(newIndex);
0N/A }
0N/A }
0N/A return newIndex;
0N/A }
0N/A
0N/A private int selectPreviousColumn(boolean doIt) {
0N/A int newIndex = getSelectedColumnIndex();
0N/A if (newIndex > 0) {
0N/A newIndex--;
0N/A if (doIt) {
0N/A selectColumn(newIndex);
0N/A }
0N/A }
0N/A return newIndex;
0N/A }
0N/A
0N/A /**
0N/A * Selects the specified column in the table header. Repaints the
0N/A * affected header cells and makes sure the newly selected one is visible.
0N/A */
0N/A void selectColumn(int newColIndex) {
0N/A selectColumn(newColIndex, true);
0N/A }
0N/A
0N/A void selectColumn(int newColIndex, boolean doScroll) {
0N/A Rectangle repaintRect = header.getHeaderRect(selectedColumnIndex);
0N/A header.repaint(repaintRect);
0N/A selectedColumnIndex = newColIndex;
0N/A repaintRect = header.getHeaderRect(newColIndex);
0N/A header.repaint(repaintRect);
0N/A if (doScroll) {
0N/A scrollToColumn(newColIndex);
0N/A }
0N/A return;
0N/A }
0N/A /**
0N/A * Used by selectColumn to scroll horizontally, if necessary,
0N/A * to ensure that the newly selected column is visible.
0N/A */
0N/A private void scrollToColumn(int col) {
0N/A Container container;
0N/A JTable table;
0N/A
0N/A //Test whether the header is in a scroll pane and has a table.
0N/A if ((header.getParent() == null) ||
0N/A ((container = header.getParent().getParent()) == null) ||
0N/A !(container instanceof JScrollPane) ||
0N/A ((table = header.getTable()) == null)) {
0N/A return;
0N/A }
0N/A
0N/A //Now scroll, if necessary.
0N/A Rectangle vis = table.getVisibleRect();
0N/A Rectangle cellBounds = table.getCellRect(0, col, true);
0N/A vis.x = cellBounds.x;
0N/A vis.width = cellBounds.width;
0N/A table.scrollRectToVisible(vis);
0N/A }
0N/A
0N/A private int getSelectedColumnIndex() {
0N/A int numCols = header.getColumnModel().getColumnCount();
0N/A if (selectedColumnIndex >= numCols && numCols > 0) {
0N/A selectedColumnIndex = numCols - 1;
0N/A }
0N/A return selectedColumnIndex;
0N/A }
0N/A
0N/A private static boolean canResize(TableColumn column,
0N/A JTableHeader header) {
0N/A return (column != null) && header.getResizingAllowed()
0N/A && column.getResizable();
0N/A }
0N/A
0N/A private int changeColumnWidth(TableColumn resizingColumn,
0N/A JTableHeader th,
0N/A int oldWidth, int newWidth) {
0N/A resizingColumn.setWidth(newWidth);
0N/A
0N/A Container container;
0N/A JTable table;
0N/A
0N/A if ((th.getParent() == null) ||
0N/A ((container = th.getParent().getParent()) == null) ||
0N/A !(container instanceof JScrollPane) ||
0N/A ((table = th.getTable()) == null)) {
0N/A return 0;
0N/A }
0N/A
0N/A if (!container.getComponentOrientation().isLeftToRight() &&
0N/A !th.getComponentOrientation().isLeftToRight()) {
0N/A JViewport viewport = ((JScrollPane)container).getViewport();
0N/A int viewportWidth = viewport.getWidth();
0N/A int diff = newWidth - oldWidth;
0N/A int newHeaderWidth = table.getWidth() + diff;
0N/A
0N/A /* Resize a table */
0N/A Dimension tableSize = table.getSize();
0N/A tableSize.width += diff;
0N/A table.setSize(tableSize);
0N/A
0N/A /* If this table is in AUTO_RESIZE_OFF mode and
0N/A * has a horizontal scrollbar, we need to update
0N/A * a view's position.
0N/A */
0N/A if ((newHeaderWidth >= viewportWidth) &&
0N/A (table.getAutoResizeMode() == JTable.AUTO_RESIZE_OFF)) {
0N/A Point p = viewport.getViewPosition();
0N/A p.x = Math.max(0, Math.min(newHeaderWidth - viewportWidth,
0N/A p.x + diff));
0N/A viewport.setViewPosition(p);
0N/A return diff;
0N/A }
0N/A }
0N/A return 0;
0N/A }
0N/A
0N/A//
0N/A// Baseline
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 int baseline = -1;
0N/A TableColumnModel columnModel = header.getColumnModel();
0N/A for(int column = 0; column < columnModel.getColumnCount();
0N/A column++) {
0N/A TableColumn aColumn = columnModel.getColumn(column);
0N/A Component comp = getHeaderRenderer(column);
0N/A Dimension pref = comp.getPreferredSize();
0N/A int columnBaseline = comp.getBaseline(pref.width, height);
0N/A if (columnBaseline >= 0) {
0N/A if (baseline == -1) {
0N/A baseline = columnBaseline;
0N/A }
0N/A else if (baseline != columnBaseline) {
0N/A baseline = -1;
0N/A break;
0N/A }
0N/A }
0N/A }
0N/A return baseline;
0N/A }
0N/A
0N/A//
0N/A// Paint Methods and support
0N/A//
0N/A
0N/A public void paint(Graphics g, JComponent c) {
0N/A if (header.getColumnModel().getColumnCount() <= 0) {
0N/A return;
0N/A }
0N/A boolean ltr = header.getComponentOrientation().isLeftToRight();
0N/A
0N/A Rectangle clip = g.getClipBounds();
0N/A Point left = clip.getLocation();
0N/A Point right = new Point( clip.x + clip.width - 1, clip.y );
0N/A TableColumnModel cm = header.getColumnModel();
0N/A int cMin = header.columnAtPoint( ltr ? left : right );
0N/A int cMax = header.columnAtPoint( ltr ? right : left );
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 = cm.getColumnCount()-1;
0N/A }
0N/A
0N/A TableColumn draggedColumn = header.getDraggedColumn();
0N/A int columnWidth;
0N/A Rectangle cellRect = header.getHeaderRect(ltr ? cMin : cMax);
0N/A TableColumn aColumn;
0N/A if (ltr) {
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;
0N/A if (aColumn != draggedColumn) {
0N/A paintCell(g, cellRect, column);
0N/A }
0N/A cellRect.x += columnWidth;
0N/A }
0N/A } else {
0N/A for(int column = cMax; column >= cMin; column--) {
0N/A aColumn = cm.getColumn(column);
0N/A columnWidth = aColumn.getWidth();
0N/A cellRect.width = columnWidth;
0N/A if (aColumn != draggedColumn) {
0N/A paintCell(g, cellRect, column);
0N/A }
0N/A cellRect.x += columnWidth;
0N/A }
0N/A }
0N/A
0N/A // Paint the dragged column if we are dragging.
0N/A if (draggedColumn != null) {
0N/A int draggedColumnIndex = viewIndexForColumn(draggedColumn);
0N/A Rectangle draggedCellRect = header.getHeaderRect(draggedColumnIndex);
0N/A
0N/A // Draw a gray well in place of the moving column.
0N/A g.setColor(header.getParent().getBackground());
0N/A g.fillRect(draggedCellRect.x, draggedCellRect.y,
0N/A draggedCellRect.width, draggedCellRect.height);
0N/A
0N/A draggedCellRect.x += header.getDraggedDistance();
0N/A
0N/A // Fill the background.
0N/A g.setColor(header.getBackground());
0N/A g.fillRect(draggedCellRect.x, draggedCellRect.y,
0N/A draggedCellRect.width, draggedCellRect.height);
0N/A
0N/A paintCell(g, draggedCellRect, draggedColumnIndex);
0N/A }
0N/A
0N/A // Remove all components in the rendererPane.
0N/A rendererPane.removeAll();
0N/A }
0N/A
0N/A private Component getHeaderRenderer(int columnIndex) {
0N/A TableColumn aColumn = header.getColumnModel().getColumn(columnIndex);
0N/A TableCellRenderer renderer = aColumn.getHeaderRenderer();
0N/A if (renderer == null) {
0N/A renderer = header.getDefaultRenderer();
0N/A }
0N/A
0N/A boolean hasFocus = !header.isPaintingForPrint()
0N/A && (columnIndex == getSelectedColumnIndex())
0N/A && header.hasFocus();
0N/A return renderer.getTableCellRendererComponent(header.getTable(),
0N/A aColumn.getHeaderValue(),
0N/A false, hasFocus,
0N/A -1, columnIndex);
0N/A }
0N/A
0N/A private void paintCell(Graphics g, Rectangle cellRect, int columnIndex) {
0N/A Component component = getHeaderRenderer(columnIndex);
0N/A rendererPane.paintComponent(g, component, header, cellRect.x, cellRect.y,
0N/A cellRect.width, cellRect.height, true);
0N/A }
0N/A
0N/A private int viewIndexForColumn(TableColumn aColumn) {
0N/A TableColumnModel cm = header.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//
0N/A// Size Methods
0N/A//
0N/A
0N/A private int getHeaderHeight() {
0N/A int height = 0;
0N/A boolean accomodatedDefault = false;
0N/A TableColumnModel columnModel = header.getColumnModel();
0N/A for(int column = 0; column < columnModel.getColumnCount(); column++) {
0N/A TableColumn aColumn = columnModel.getColumn(column);
0N/A boolean isDefault = (aColumn.getHeaderRenderer() == null);
0N/A
0N/A if (!isDefault || !accomodatedDefault) {
0N/A Component comp = getHeaderRenderer(column);
0N/A int rendererHeight = comp.getPreferredSize().height;
0N/A height = Math.max(height, rendererHeight);
0N/A
0N/A // Configuring the header renderer to calculate its preferred size
0N/A // is expensive. Optimise this by assuming the default renderer
0N/A // always has the same height as the first non-zero height that
0N/A // it returns for a non-null/non-empty value.
0N/A if (isDefault && rendererHeight > 0) {
0N/A Object headerValue = aColumn.getHeaderValue();
0N/A if (headerValue != null) {
0N/A headerValue = headerValue.toString();
0N/A
0N/A if (headerValue != null && !headerValue.equals("")) {
0N/A accomodatedDefault = true;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A return height;
0N/A }
0N/A
0N/A private Dimension createHeaderSize(long width) {
0N/A // None of the callers include the intercell spacing, do it here.
0N/A if (width > Integer.MAX_VALUE) {
0N/A width = Integer.MAX_VALUE;
0N/A }
0N/A return new Dimension((int)width, getHeaderHeight());
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Return the minimum size of the header. The minimum width is the sum
0N/A * of the minimum widths of each column (plus inter-cell spacing).
0N/A */
0N/A public Dimension getMinimumSize(JComponent c) {
0N/A long width = 0;
0N/A Enumeration enumeration = header.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 createHeaderSize(width);
0N/A }
0N/A
0N/A /**
0N/A * Return the preferred size of the header. The preferred height is the
0N/A * maximum of the preferred heights of all of the components provided
0N/A * by the header renderers. The preferred width is the sum of the
0N/A * preferred widths of each column (plus inter-cell spacing).
0N/A */
0N/A public Dimension getPreferredSize(JComponent c) {
0N/A long width = 0;
0N/A Enumeration enumeration = header.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 createHeaderSize(width);
0N/A }
0N/A
0N/A /**
0N/A * Return the maximum size of the header. The maximum width is the sum
0N/A * of the maximum widths of each column (plus inter-cell spacing).
0N/A */
0N/A public Dimension getMaximumSize(JComponent c) {
0N/A long width = 0;
0N/A Enumeration enumeration = header.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 createHeaderSize(width);
0N/A }
0N/A
0N/A private static class Actions extends UIAction {
0N/A public static final String TOGGLE_SORT_ORDER =
0N/A "toggleSortOrder";
0N/A public static final String SELECT_COLUMN_TO_LEFT =
0N/A "selectColumnToLeft";
0N/A public static final String SELECT_COLUMN_TO_RIGHT =
0N/A "selectColumnToRight";
0N/A public static final String MOVE_COLUMN_LEFT =
0N/A "moveColumnLeft";
0N/A public static final String MOVE_COLUMN_RIGHT =
0N/A "moveColumnRight";
0N/A public static final String RESIZE_LEFT =
0N/A "resizeLeft";
0N/A public static final String RESIZE_RIGHT =
0N/A "resizeRight";
0N/A public static final String FOCUS_TABLE =
0N/A "focusTable";
0N/A
0N/A public Actions(String name) {
0N/A super(name);
0N/A }
0N/A
0N/A public boolean isEnabled(Object sender) {
0N/A if (sender instanceof JTableHeader) {
0N/A JTableHeader th = (JTableHeader)sender;
0N/A TableColumnModel cm = th.getColumnModel();
0N/A if (cm.getColumnCount() <= 0) {
0N/A return false;
0N/A }
0N/A
0N/A String key = getName();
0N/A BasicTableHeaderUI ui =
0N/A (BasicTableHeaderUI)BasicLookAndFeel.getUIOfType(th.getUI(),
0N/A BasicTableHeaderUI.class);
0N/A if (ui != null) {
0N/A if (key == MOVE_COLUMN_LEFT) {
0N/A return th.getReorderingAllowed()
0N/A && maybeMoveColumn(true, th, ui, false);
0N/A } else if (key == MOVE_COLUMN_RIGHT) {
0N/A return th.getReorderingAllowed()
0N/A && maybeMoveColumn(false, th, ui, false);
0N/A } else if (key == RESIZE_LEFT ||
0N/A key == RESIZE_RIGHT) {
0N/A return canResize(cm.getColumn(ui.getSelectedColumnIndex()), th);
0N/A } else if (key == FOCUS_TABLE) {
0N/A return (th.getTable() != null);
0N/A }
0N/A }
0N/A }
0N/A return true;
0N/A }
0N/A
0N/A public void actionPerformed(ActionEvent e) {
0N/A JTableHeader th = (JTableHeader)e.getSource();
0N/A BasicTableHeaderUI ui =
0N/A (BasicTableHeaderUI)BasicLookAndFeel.
0N/A getUIOfType(th.getUI(),
0N/A BasicTableHeaderUI.class);
0N/A if (ui == null) {
0N/A return;
0N/A }
0N/A
0N/A String name = getName();
0N/A if (TOGGLE_SORT_ORDER == name) {
0N/A JTable table = th.getTable();
0N/A RowSorter sorter = table == null ? null : table.getRowSorter();
0N/A if (sorter != null) {
0N/A int columnIndex = ui.getSelectedColumnIndex();
0N/A columnIndex = table.convertColumnIndexToModel(
0N/A columnIndex);
0N/A sorter.toggleSortOrder(columnIndex);
0N/A }
0N/A } else if (SELECT_COLUMN_TO_LEFT == name) {
0N/A if (th.getComponentOrientation().isLeftToRight()) {
0N/A ui.selectPreviousColumn(true);
0N/A } else {
0N/A ui.selectNextColumn(true);
0N/A }
0N/A } else if (SELECT_COLUMN_TO_RIGHT == name) {
0N/A if (th.getComponentOrientation().isLeftToRight()) {
0N/A ui.selectNextColumn(true);
0N/A } else {
0N/A ui.selectPreviousColumn(true);
4106N/A }
4106N/A } else if (MOVE_COLUMN_LEFT == name) {
0N/A moveColumn(true, th, ui);
0N/A } else if (MOVE_COLUMN_RIGHT == name) {
4106N/A moveColumn(false, th, ui);
4106N/A } else if (RESIZE_LEFT == name) {
4106N/A resize(true, th, ui);
0N/A } else if (RESIZE_RIGHT == name) {
0N/A resize(false, th, ui);
0N/A } else if (FOCUS_TABLE == name) {
0N/A JTable table = th.getTable();
0N/A if (table != null) {
0N/A table.requestFocusInWindow();
0N/A }
0N/A }
0N/A }
0N/A
0N/A private void moveColumn(boolean leftArrow, JTableHeader th,
0N/A BasicTableHeaderUI ui) {
0N/A maybeMoveColumn(leftArrow, th, ui, true);
0N/A }
0N/A
0N/A private boolean maybeMoveColumn(boolean leftArrow, JTableHeader th,
4106N/A BasicTableHeaderUI ui, boolean doIt) {
4106N/A int oldIndex = ui.getSelectedColumnIndex();
0N/A int newIndex;
0N/A
4106N/A if (th.getComponentOrientation().isLeftToRight()) {
4106N/A newIndex = leftArrow ? ui.selectPreviousColumn(doIt)
4106N/A : ui.selectNextColumn(doIt);
0N/A } else {
0N/A newIndex = leftArrow ? ui.selectNextColumn(doIt)
3203N/A : ui.selectPreviousColumn(doIt);
0N/A }
0N/A
0N/A if (newIndex != oldIndex) {
0N/A if (doIt) {
0N/A th.getColumnModel().moveColumn(oldIndex, newIndex);
0N/A } else {
0N/A return true; // we'd do the move if asked
0N/A }
0N/A }
0N/A
0N/A return false;
0N/A }
0N/A
0N/A private void resize(boolean leftArrow, JTableHeader th,
0N/A BasicTableHeaderUI ui) {
0N/A int columnIndex = ui.getSelectedColumnIndex();
0N/A TableColumn resizingColumn =
0N/A th.getColumnModel().getColumn(columnIndex);
0N/A
0N/A th.setResizingColumn(resizingColumn);
0N/A int oldWidth = resizingColumn.getWidth();
0N/A int newWidth = oldWidth;
0N/A
0N/A if (th.getComponentOrientation().isLeftToRight()) {
0N/A newWidth = newWidth + (leftArrow ? -1 : 1);
0N/A } else {
0N/A newWidth = newWidth + (leftArrow ? 1 : -1);
0N/A }
0N/A
0N/A ui.changeColumnWidth(resizingColumn, th, oldWidth, newWidth);
0N/A }
0N/A }
0N/A} // End of Class BasicTableHeaderUI
0N/A