/* * Copyright (c) 2002 and later by MH Software-Entwicklung. All Rights Reserved. * * JTattoo is multiple licensed. If your are an open source developer you can use * it under the terms and conditions of the GNU General Public License version 2.0 * or later as published by the Free Software Foundation. * * see: gpl-2.0.txt * * If you pay for a license you will become a registered user who could use the * software under the terms and conditions of the GNU Lesser General Public License * version 2.0 or later with classpath exception as published by the Free Software * Foundation. * * see: lgpl-2.0.txt * see: classpath-exception.txt * * Registered users could also use JTattoo under the terms and conditions of the * Apache License, Version 2.0 as published by the Apache Software Foundation. * * see: APACHE-LICENSE-2.0.txt */ package com.jtattoo.plaf; import java.awt.*; import java.awt.event.*; import java.util.Enumeration; import java.util.List; import javax.swing.*; import javax.swing.plaf.ColorUIResource; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicTableHeaderUI; import javax.swing.table.*; /** * * @author Michael Hagen */ public class BaseTableHeaderUI extends BasicTableHeaderUI { private TableCellRenderer originalHeaderRenderer; protected MouseAdapter myMouseAdapter = null; protected MouseMotionAdapter myMouseMotionAdapter = null; protected int rolloverCol = -1; public static ComponentUI createUI(JComponent h) { return new BaseTableHeaderUI(); } public void installUI(JComponent c) { super.installUI(c); if (header != null) { originalHeaderRenderer = header.getDefaultRenderer(); if ((originalHeaderRenderer != null) && "sun.swing.table.DefaultTableCellHeaderRenderer".equals(originalHeaderRenderer.getClass().getName())) { header.setDefaultRenderer(new BaseDefaultHeaderRenderer()); } } } public void uninstallUI(JComponent c) { if (header != null) { if (header.getDefaultRenderer() instanceof BaseDefaultHeaderRenderer) { header.setDefaultRenderer(originalHeaderRenderer); } } super.uninstallUI(c); } public void installListeners() { super.installListeners(); myMouseAdapter = new MouseAdapter() { public void mouseReleased(MouseEvent e) { if ((header == null) || (header.getTable() == null)) { return; } boolean rolloverEnabled = Boolean.TRUE.equals(header.getClientProperty("rolloverEnabled")); boolean sortingAllowed = false; if (JTattooUtilities.getJavaVersion() >= 1.6) { sortingAllowed = header.getTable().getRowSorter() != null; } if (rolloverEnabled || sortingAllowed || header.getReorderingAllowed()) { final Point pt = e.getPoint(); SwingUtilities.invokeLater(new Runnable() { public void run() { if (header.getBounds().contains(pt)) { int oldRolloverCol = rolloverCol; rolloverCol = header.getTable().columnAtPoint(pt); updateRolloverColumn(oldRolloverCol, rolloverCol); } else { int oldRolloverCol = rolloverCol; rolloverCol = -1; updateRolloverColumn(oldRolloverCol, rolloverCol); } } }); } } public void mouseEntered(MouseEvent e) { if ((header == null) || (header.getTable() == null)) { return; } boolean rolloverEnabled = Boolean.TRUE.equals(header.getClientProperty("rolloverEnabled")); boolean sortingAllowed = false; if (JTattooUtilities.getJavaVersion() >= 1.6) { sortingAllowed = header.getTable().getRowSorter() != null; } if (rolloverEnabled || sortingAllowed || header.getReorderingAllowed()) { int oldRolloverCol = rolloverCol; rolloverCol = header.getTable().columnAtPoint(e.getPoint()); updateRolloverColumn(oldRolloverCol, rolloverCol); } } public void mouseExited(MouseEvent e) { if ((header == null) || (header.getTable() == null)) { return; } boolean rolloverEnabled = Boolean.TRUE.equals(header.getClientProperty("rolloverEnabled")); boolean sortingAllowed = false; if (JTattooUtilities.getJavaVersion() >= 1.6) { sortingAllowed = header.getTable().getRowSorter() != null; } if (rolloverEnabled || sortingAllowed || header.getReorderingAllowed()) { int oldRolloverCol = rolloverCol; rolloverCol = -1; updateRolloverColumn(oldRolloverCol, rolloverCol); } } }; myMouseMotionAdapter = new MouseMotionAdapter() { public void mouseMoved(MouseEvent e) { if ((header == null) || (header.getTable() == null)) { return; } boolean rolloverEnabled = Boolean.TRUE.equals(header.getClientProperty("rolloverEnabled")); boolean sortingAllowed = false; if (JTattooUtilities.getJavaVersion() >= 1.6) { sortingAllowed = header.getTable().getRowSorter() != null; } if (rolloverEnabled || sortingAllowed || header.getReorderingAllowed()) { if (header.getDraggedColumn() == null) { int oldRolloverCol = rolloverCol; rolloverCol = header.getTable().columnAtPoint(e.getPoint()); updateRolloverColumn(oldRolloverCol, rolloverCol); } } } public void mouseDragged(MouseEvent e) { if ((header == null) || (header.getTable() == null)) { return; } boolean rolloverEnabled = Boolean.TRUE.equals(header.getClientProperty("rolloverEnabled")); boolean sortingAllowed = false; if (JTattooUtilities.getJavaVersion() >= 1.6) { sortingAllowed = header.getTable().getRowSorter() != null; } if (rolloverEnabled || sortingAllowed || header.getReorderingAllowed()) { if (header.getDraggedColumn() != null && header.getDraggedColumn().getIdentifier() != null) { rolloverCol = header.getColumnModel().getColumnIndex(header.getDraggedColumn().getIdentifier()); } else if (header.getResizingColumn() != null) { rolloverCol = -1; } } } }; header.addMouseListener(myMouseAdapter); header.addMouseMotionListener(myMouseMotionAdapter); } public void uninstallListeners() { header.removeMouseListener(myMouseAdapter); header.removeMouseMotionListener(myMouseMotionAdapter); super.uninstallListeners(); } protected boolean drawAlwaysActive() { return false; } protected boolean drawRolloverBar() { return false; } protected Component getHeaderRenderer(int col) { if (header == null) { return null; } TableColumn tabCol = header.getColumnModel().getColumn(col); TableCellRenderer renderer = tabCol.getHeaderRenderer(); if (renderer == null) { renderer = header.getDefaultRenderer(); } return renderer.getTableCellRendererComponent(header.getTable(), tabCol.getHeaderValue(), false, false, -1, col); } private int getHeaderHeight() { if (header == null) { return 0; } int height = 0; boolean accomodatedDefault = false; TableColumnModel columnModel = header.getColumnModel(); for (int column = 0; column < columnModel.getColumnCount(); column++) { TableColumn aColumn = columnModel.getColumn(column); boolean isDefault = (aColumn.getHeaderRenderer() == null); if (!isDefault || !accomodatedDefault) { Component comp = getHeaderRenderer(column); int rendererHeight = comp.getPreferredSize().height; height = Math.max(height, rendererHeight); // Configuring the header renderer to calculate its preferred size // is expensive. Optimise this by assuming the default renderer // always has the same height as the first non-zero height that // it returns for a non-null/non-empty value. if (isDefault && rendererHeight > 0) { Object headerValue = aColumn.getHeaderValue(); if (headerValue != null) { headerValue = headerValue.toString(); if (headerValue != null && !headerValue.equals("")) { accomodatedDefault = true; } } } } } return height + 2; } /** * Return the preferred size of the header. The preferred height is the maximum of the preferred heights of all of * the components provided by the header renderers. The preferred width is the sum of the preferred widths of each * column (plus inter-cell spacing). * * @return the preferredSize */ public Dimension getPreferredSize(JComponent c) { if (header == null) { return new Dimension(0, 0); } long width = 0; Enumeration enumeration = header.getColumnModel().getColumns(); while (enumeration.hasMoreElements()) { TableColumn aColumn = (TableColumn) enumeration.nextElement(); width = width + aColumn.getPreferredWidth(); } if (width > Integer.MAX_VALUE) { width = Integer.MAX_VALUE; } return new Dimension((int) width, getHeaderHeight()); } protected void updateRolloverColumn(int oldColumn, int newColumn) { if (header == null) { return; } header.repaint(header.getHeaderRect(oldColumn)); header.repaint(header.getHeaderRect(newColumn)); } protected void rolloverColumnUpdated(int oldColumn, int newColumn) { // Empty to avoid multiple paints } public void paint(Graphics g, JComponent c) { if ((header == null) || header.getColumnModel().getColumnCount() <= 0) { return; } boolean ltr = header.getComponentOrientation().isLeftToRight(); Rectangle clip = g.getClipBounds(); Point left = clip.getLocation(); Point right = new Point(clip.x + clip.width - 1, clip.y); TableColumnModel cm = header.getColumnModel(); int cMin = header.columnAtPoint(ltr ? left : right); int cMax = header.columnAtPoint(ltr ? right : left); // This should never happen. if (cMin == -1) { cMin = 0; } // If the table does not have enough columns to fill the view we'll get -1. // Replace this with the index of the last column. if (cMax == -1) { cMax = cm.getColumnCount() - 1; } TableColumn draggedColumn = header.getDraggedColumn(); Rectangle cellRect = header.getHeaderRect(ltr ? cMin : cMax); int columnWidth; TableColumn aColumn; if (ltr) { for (int column = cMin; column <= cMax; column++) { aColumn = cm.getColumn(column); columnWidth = aColumn.getWidth(); cellRect.width = columnWidth; if (aColumn != draggedColumn) { paintCell(g, cellRect, column); } cellRect.x += columnWidth; } } else { for (int column = cMax; column >= cMin; column--) { aColumn = cm.getColumn(column); columnWidth = aColumn.getWidth(); cellRect.width = columnWidth; if (aColumn != draggedColumn) { paintCell(g, cellRect, column); } cellRect.x += columnWidth; } } // Paint the dragged column if we are dragging. if (draggedColumn != null) { int draggedColumnIndex = viewIndexForColumn(draggedColumn); Rectangle draggedCellRect = header.getHeaderRect(draggedColumnIndex); // Draw a gray well in place of the moving column. g.setColor(header.getParent().getBackground()); g.fillRect(draggedCellRect.x, draggedCellRect.y, draggedCellRect.width, draggedCellRect.height); draggedCellRect.x += header.getDraggedDistance(); // Fill the background. g.setColor(header.getBackground()); g.fillRect(draggedCellRect.x, draggedCellRect.y, draggedCellRect.width, draggedCellRect.height); paintCell(g, draggedCellRect, draggedColumnIndex); } // Remove all components in the rendererPane. rendererPane.removeAll(); } protected void paintBackground(Graphics g, Rectangle cellRect, int col) { Component component = getHeaderRenderer(col); int x = cellRect.x; int y = cellRect.y; int w = cellRect.width; int h = cellRect.height; if (header.getBackground() instanceof ColorUIResource) { if ((col == rolloverCol) && (component != null) && component.isEnabled()) { JTattooUtilities.fillHorGradient(g, AbstractLookAndFeel.getTheme().getRolloverColors(), x, y, w, h); } else if (drawAlwaysActive() || JTattooUtilities.isFrameActive(header)) { JTattooUtilities.fillHorGradient(g, AbstractLookAndFeel.getTheme().getColHeaderColors(), x, y, w, h); } else { JTattooUtilities.fillHorGradient(g, AbstractLookAndFeel.getTheme().getInActiveColors(), x, y, w, h); } } else { g.setColor(header.getBackground()); g.fillRect(x, y, w, h); } } protected void paintCell(Graphics g, Rectangle cellRect, int col) { if (header == null) { return; } Component component = getHeaderRenderer(col); if (!(component instanceof BaseDefaultHeaderRenderer)) { paintBackground(g, cellRect, col); } rendererPane.paintComponent(g, component, header, cellRect.x, cellRect.y, cellRect.width, cellRect.height, true); } private int viewIndexForColumn(TableColumn aColumn) { if (header == null) { return -1; } TableColumnModel cm = header.getColumnModel(); for (int column = 0; column < cm.getColumnCount(); column++) { if (cm.getColumn(column) == aColumn) { return column; } } return -1; } //---------------------------------------------------------------------------------------------------------------------- // inner classes //---------------------------------------------------------------------------------------------------------------------- private class BaseDefaultHeaderRenderer extends DefaultTableCellRenderer { public BaseDefaultHeaderRenderer() { super(); } public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { return new MyRenderComponent(table, value, isSelected, hasFocus, row, column); } } private class MyRenderComponent extends JLabel { private JTable table = null; private int col = 0; public MyRenderComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) { super(); this.table = table; this.col = col; if (value != null) { setText(value.toString()); } else { setText(""); } setOpaque(false); if (table != null && table.getClientProperty("TableHeader.font") != null) { setFont((Font)table.getClientProperty("TableHeader.font")); } else { setFont(UIManager.getFont("TableHeader.font")); } if (col == rolloverCol) { setForeground(AbstractLookAndFeel.getTheme().getRolloverForegroundColor()); } else { setForeground(UIManager.getColor("TableHeader.foreground")); } setHorizontalAlignment(JLabel.CENTER); setHorizontalTextPosition(SwingConstants.LEADING); setBorder(UIManager.getBorder("TableHeader.cellBorder")); if (table != null && (JTattooUtilities.getJavaVersion() >= 1.6) && (UIManager.getLookAndFeel() instanceof AbstractLookAndFeel)) { RowSorter rowSorter = table.getRowSorter(); List keyList = rowSorter == null ? null : rowSorter.getSortKeys(); if ((keyList != null) && (keyList.size() > 0)) { RowSorter.SortKey sortKey = (RowSorter.SortKey) keyList.get(0); if (sortKey.getColumn() == table.convertColumnIndexToModel(col)) { AbstractIconFactory iconFactory = ((AbstractLookAndFeel) UIManager.getLookAndFeel()).getIconFactory(); if (sortKey.getSortOrder().equals(SortOrder.ASCENDING)) { setIcon(iconFactory.getUpArrowIcon()); } else if (sortKey.getSortOrder().equals(SortOrder.DESCENDING)) { setIcon(iconFactory.getDownArrowIcon()); } } } } } protected void paintBackground(Graphics g) { // BugFix: 12.12.2013 // Currently I don't know why header is sometimes null, but if it's null it's better to ignore // the background instead of throwing a NPE. if (header == null) { JTattooUtilities.fillHorGradient(g, AbstractLookAndFeel.getTheme().getColHeaderColors(), 0, 0, getWidth(), getHeight()); return; } int draggedColumn = -1; if (header.getTable() != null && header.getDraggedColumn() != null) { draggedColumn = header.getColumnModel().getColumnIndex(header.getDraggedColumn().getIdentifier()); } int w = getWidth(); int h = getHeight(); if ((table != null) && table.isEnabled() && (col == rolloverCol || col == draggedColumn)) { JTattooUtilities.fillHorGradient(g, AbstractLookAndFeel.getTheme().getRolloverColors(), 0, 0, w, h); if (drawRolloverBar()) { g.setColor(AbstractLookAndFeel.getFocusColor()); g.drawLine(0, 0, w - 1, 0); g.drawLine(0, 1, w - 1, 1); g.drawLine(0, 2, w - 1, 2); } } else if (drawAlwaysActive() || JTattooUtilities.isFrameActive(header)) { if (header.getBackground() instanceof ColorUIResource) { JTattooUtilities.fillHorGradient(g, AbstractLookAndFeel.getTheme().getColHeaderColors(), 0, 0, w, h); } else { g.setColor(header.getBackground()); g.fillRect(0, 0, w, h); } } else { if (header.getBackground() instanceof ColorUIResource) { JTattooUtilities.fillHorGradient(g, AbstractLookAndFeel.getTheme().getInActiveColors(), 0, 0, w, h); } else { g.setColor(header.getBackground()); g.fillRect(0, 0, w, h); } } } public void paint(Graphics g) { paintBackground(g); super.paint(g); } } }