Browse Source

TableUI added.

pull/1/head
weisj 5 years ago
parent
commit
f603f8fc55
  1. 28
      src/main/java/com/weis/darklaf/ui/MimaTableCellBorder.java
  2. 30
      src/main/java/com/weis/darklaf/ui/table/DarkTableBorder.java
  3. 17
      src/main/java/com/weis/darklaf/ui/table/DarkTableCellBorder.java
  4. 30
      src/main/java/com/weis/darklaf/ui/table/DarkTableHeaderBorder.java
  5. 26
      src/main/java/com/weis/darklaf/ui/table/DarkTableHeaderCorner.java
  6. 231
      src/main/java/com/weis/darklaf/ui/table/DarkTableHeaderUI.java
  7. 901
      src/main/java/com/weis/darklaf/ui/table/DarkTableHeaderUIBridge.java
  8. 341
      src/main/java/com/weis/darklaf/ui/table/DarkTableUI.java
  9. 432
      src/main/java/com/weis/darklaf/ui/table/DarkTableUIBridge.java

28
src/main/java/com/weis/darklaf/ui/MimaTableCellBorder.java

@ -1,28 +0,0 @@
package com.weis.darklaf.ui;
import com.weis.darklaf.components.border.AdaptiveLineBorder;
import java.awt.*;
/**
* Table cell border. Prevents content to be shifted when selected.
*
* @author Jannis Weis
* @since 2018
*/
public class MimaTableCellBorder extends AdaptiveLineBorder {
/**
* Create new Cell border.
*/
public MimaTableCellBorder() {
super(1, 1, 1, 1, "Border.line1");
}
@Override
public Insets getBorderInsets(final Component c) {
var i = super.getBorderInsets(c);
i.left += 1;
return i;
}
}

30
src/main/java/com/weis/darklaf/ui/table/DarkTableBorder.java

@ -0,0 +1,30 @@
package com.weis.darklaf.ui.table;
import com.weis.darklaf.components.border.MutableLineBorder;
import javax.swing.*;
import javax.swing.plaf.UIResource;
import java.awt.*;
public class DarkTableBorder extends MutableLineBorder implements UIResource {
public DarkTableBorder() {
super(1, 1, 1, 1, null);
}
@Override
public void paintBorder(final Component c, final Graphics g, final int x, final int y,
final int width, final int height) {
setColor(getBorderColor());
super.paintBorder(c, g, x, y, width, height);
}
protected Color getBorderColor() {
return UIManager.getColor("TableHeader.borderColor");
}
@Override
public boolean isBorderOpaque() {
return true;
}
}

17
src/main/java/com/weis/darklaf/ui/table/DarkTableCellBorder.java

@ -0,0 +1,17 @@
package com.weis.darklaf.ui.table;
import javax.swing.border.EmptyBorder;
import javax.swing.plaf.UIResource;
/**
* Table cell border. Prevents content to be shifted when selected.
*
* @author Jannis Weis
* @since 2018
*/
public class DarkTableCellBorder extends EmptyBorder implements UIResource {
public DarkTableCellBorder() {
super(2, 5, 2, 5);
}
}

30
src/main/java/com/weis/darklaf/ui/table/DarkTableHeaderBorder.java

@ -0,0 +1,30 @@
package com.weis.darklaf.ui.table;
import com.weis.darklaf.components.border.MutableLineBorder;
import javax.swing.*;
import javax.swing.plaf.UIResource;
import java.awt.*;
public class DarkTableHeaderBorder extends MutableLineBorder implements UIResource {
public DarkTableHeaderBorder() {
super(0, 0, 1, 0, null);
}
@Override
public void paintBorder(final Component c, final Graphics g, final int x, final int y,
final int width, final int height) {
setColor(getBorderColor());
super.paintBorder(c, g, x, y, width, height);
}
protected Color getBorderColor() {
return UIManager.getColor("TableHeader.borderColor");
}
@Override
public boolean isBorderOpaque() {
return true;
}
}

26
src/main/java/com/weis/darklaf/ui/table/DarkTableHeaderCorner.java

@ -0,0 +1,26 @@
package com.weis.darklaf.ui.table;
import javax.swing.*;
import javax.swing.plaf.UIResource;
import java.awt.*;
public class DarkTableHeaderCorner extends JComponent implements UIResource {
@Override
protected void paintComponent(final Graphics g) {
super.paintComponent(g);
g.setColor(getHeaderBackground());
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(getBorderColor());
g.fillRect(0, getHeight() - 1, getWidth(), 1);
}
protected Color getBorderColor() {
return UIManager.getColor("TableHeader.borderColor");
}
protected Color getHeaderBackground() {
return UIManager.getColor("TableHeader.background");
}
}

231
src/main/java/com/weis/darklaf/ui/table/DarkTableHeaderUI.java

@ -0,0 +1,231 @@
package com.weis.darklaf.ui.table;
import com.bulenkov.iconloader.util.GraphicsConfig;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import java.awt.*;
public class DarkTableHeaderUI extends DarkTableHeaderUIBridge {
private static final int HEADER_HEIGHT = 26;
@NotNull
@Contract("_ -> new")
public static ComponentUI createUI(final JComponent c) {
return new DarkTableHeaderUI();
}
@Override
public void installUI(final JComponent c) {
super.installUI(c);
var dim = header.getPreferredSize();
header.setPreferredSize(new Dimension(dim.width, Math.max(dim.height, HEADER_HEIGHT)));
if (header.getDefaultRenderer() instanceof DefaultTableCellRenderer) {
DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) header.getDefaultRenderer();
renderer.setHorizontalAlignment(SwingConstants.LEADING);
}
}
@Override
protected void installDefaults() {
super.installDefaults();
LookAndFeel.installBorder(header, "TableHeader.border");
}
@Override
protected void uninstallDefaults() {
super.uninstallDefaults();
if (header.getBorder() instanceof UIResource) {
LookAndFeel.uninstallBorder(header);
}
}
@Override
public void paint(final Graphics g2, final @NotNull JComponent c) {
final Graphics2D g = (Graphics2D) g2;
final GraphicsConfig config = new GraphicsConfig(g);
int h = c.getHeight();
int w = c.getWidth();
g.setColor(getHeaderBackground());
g.fillRect(0, 0, w, h);
if (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;
}
Color borderColor = c.getBorder() instanceof DarkTableBorder
? ((DarkTableBorder) c.getBorder()).getBorderColor()
: getBorderColor();
g.setColor(borderColor);
TableColumn draggedColumn = header.getDraggedColumn();
int columnWidth;
Rectangle cellRect = header.getHeaderRect(ltr ? cMin : cMax);
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;
if (column != cMax) {
g.setColor(borderColor);
g.fillRect(cellRect.x - 1, 0, 1, h);
}
}
} 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;
if (column != cMin) {
g.setColor(borderColor);
g.fillRect(cellRect.x - 1, 0, 1, h);
}
}
}
// Paint the dragged column if we are dragging.
if (draggedColumn != null) {
int draggedColumnIndex = viewIndexForColumn(draggedColumn);
boolean scrollPaneRtl = isScrollPaneRtl();
Rectangle draggedCellRect = header.getHeaderRect(draggedColumnIndex);
int dist = DarkTableUI.adjustDistance(header.getDraggedDistance(), draggedCellRect, header.getTable());
// 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);
g.setColor(borderColor);
if (scrollBarVisible()) {
if (ltr) {
if (!scrollPaneRtl) {
g.fillRect(draggedCellRect.x + draggedCellRect.width - 1, draggedCellRect.y,
1, draggedCellRect.height);
} else {
if (draggedColumnIndex != cMax) {
g.fillRect(draggedCellRect.x + draggedCellRect.width - 1, draggedCellRect.y,
1, draggedCellRect.height);
}
if (draggedColumnIndex == cMin) {
g.fillRect(draggedCellRect.x, draggedCellRect.y, 1, draggedCellRect.height);
}
}
} else {
if (!scrollPaneRtl) {
g.fillRect(draggedCellRect.x + draggedCellRect.width - 1, draggedCellRect.y,
1, draggedCellRect.height);
} else {
if (draggedColumnIndex != cMin) {
g.fillRect(draggedCellRect.x + draggedCellRect.width - 1, draggedCellRect.y,
1, draggedCellRect.height);
}
if (draggedColumnIndex == cMax) {
g.fillRect(draggedCellRect.x, draggedCellRect.y, 1, draggedCellRect.height);
}
}
}
} else {
if (ltr) {
if (draggedColumnIndex != cMax) {
g.fillRect(draggedCellRect.x + draggedCellRect.width - 1, draggedCellRect.y,
1, draggedCellRect.height);
}
} else {
if (draggedColumnIndex != cMin) {
g.fillRect(draggedCellRect.x + draggedCellRect.width - 1, draggedCellRect.y,
1, draggedCellRect.height);
}
}
}
draggedCellRect.x += dist;
// Fill the background.
g.setColor(header.getBackground());
g.fillRect(draggedCellRect.x, draggedCellRect.y,
draggedCellRect.width, draggedCellRect.height);
paintCell(g, draggedCellRect, draggedColumnIndex);
g.setColor(borderColor);
boolean onLeftEdge = ltr ? draggedColumnIndex == cMin : draggedColumnIndex == cMax;
boolean onRightEdge = ltr ? draggedColumnIndex == cMax : draggedColumnIndex == cMin;
//left
if (dist != 0 || !onLeftEdge) {
g.fillRect(draggedCellRect.x - 1, draggedCellRect.y, 1, draggedCellRect.height);
}
//right
if (dist != 0 || !onRightEdge) {
g.fillRect(draggedCellRect.x + draggedCellRect.width - 1, draggedCellRect.y,
1, draggedCellRect.height);
}
}
// Remove all components in the rendererPane.
rendererPane.removeAll();
config.restore();
}
protected boolean isScrollPaneRtl() {
if (!isInScrollPane()) return false;
Container comp = SwingUtilities.getUnwrappedParent(header).getParent();
return !comp.getComponentOrientation().isLeftToRight();
}
protected boolean scrollBarVisible() {
Container comp = SwingUtilities.getUnwrappedParent(header);
if (comp != null) {
comp = comp.getParent();
}
return comp instanceof JScrollPane && ((JScrollPane) comp).getVerticalScrollBar().isVisible();
}
protected boolean isInScrollPane() {
Container comp = SwingUtilities.getUnwrappedParent(header);
if (comp != null) {
comp = comp.getParent();
}
return comp instanceof JScrollPane;
}
protected Color getBorderColor() {
return UIManager.getColor("TableHeader.borderColor");
}
protected Color getHeaderBackground() {
return UIManager.getColor("TableHeader.background");
}
}

901
src/main/java/com/weis/darklaf/ui/table/DarkTableHeaderUIBridge.java

@ -0,0 +1,901 @@
package com.weis.darklaf.ui.table;
import com.weis.darklaf.util.DarkUIUtil;
import org.jetbrains.annotations.NotNull;
import sun.swing.SwingUtilities2;
import sun.swing.UIAction;
import javax.swing.*;
import javax.swing.event.MouseInputListener;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicTableHeaderUI;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseEvent;
import java.util.Enumeration;
public class DarkTableHeaderUIBridge extends BasicTableHeaderUI {
protected static Cursor resizeCursor = Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR);
//
// Instance Variables
//
protected static FocusListener focusListener = new FocusListener() {
public void focusGained(@NotNull final FocusEvent e) {
repaintHeader(e.getSource());
}
public void focusLost(@NotNull final FocusEvent e) {
repaintHeader(e.getSource());
}
protected void repaintHeader(final Object source) {
if (source instanceof JTableHeader) {
JTableHeader th = (JTableHeader) source;
DarkTableHeaderUIBridge ui =
(DarkTableHeaderUIBridge) DarkUIUtil.getUIOfType(th.getUI(), DarkTableHeaderUIBridge.class);
if (ui == null) {
return;
}
th.repaint(th.getHeaderRect(ui.getSelectedColumnIndex()));
}
}
};
// The column header over which the mouse currently is.
protected int rolloverColumn = -1;
// The column that should be highlighted when the table header has the focus.
protected int selectedColumnIndex = 0; // Read ONLY via getSelectedColumnIndex!
/**
* Returns a new instance of {@code DarkTableHeaderUIBridge}.
*
* @param h a component.
* @return a new instance of {@code DarkTableHeaderUIBridge}
*/
public static ComponentUI createUI(final JComponent h) {
return new DarkTableHeaderUIBridge();
}
//
// Factory methods for the Listeners
//
protected static boolean canResize(final TableColumn column,
final JTableHeader header) {
return (column != null) && header.getResizingAllowed()
&& column.getResizable();
}
//
// The installation/uninstall procedures and support
//
/**
* Creates the mouse listener for the {@code JTableHeader}.
*
* @return the mouse listener for the {@code JTableHeader}
*/
protected MouseInputListener createMouseInputListener() {
return new DarkTableHeaderUIBridge.MouseInputHandler();
}
// Installation
public void installUI(final JComponent c) {
super.installUI(c);
}
/**
* Initializes JTableHeader properties such as font, foreground, and background.
* The font, foreground, and background properties are only set if their
* current value is either null or a UIResource, other properties are set
* if the current value is null.
*
* @see #installUI
*/
protected void installDefaults() {
LookAndFeel.installColorsAndFont(header, "TableHeader.background",
"TableHeader.foreground", "TableHeader.font");
LookAndFeel.installProperty(header, "opaque", Boolean.TRUE);
}
/**
* Attaches listeners to the JTableHeader.
*/
protected void installListeners() {
mouseInputListener = createMouseInputListener();
header.addMouseListener(mouseInputListener);
header.addMouseMotionListener(mouseInputListener);
header.addFocusListener(focusListener);
}
// Uninstall methods
public void uninstallUI(final JComponent c) {
uninstallDefaults();
uninstallListeners();
uninstallKeyboardActions();
header.remove(rendererPane);
rendererPane = null;
header = null;
}
/**
* Uninstalls default properties
*/
protected void uninstallDefaults() {
}
/**
* Unregisters listeners.
*/
protected void uninstallListeners() {
header.removeMouseListener(mouseInputListener);
header.removeMouseMotionListener(mouseInputListener);
header.removeFocusListener(focusListener);
mouseInputListener = null;
}
/**
* Unregisters default key actions.
*/
protected void uninstallKeyboardActions() {
SwingUtilities.replaceUIInputMap(header, JComponent.WHEN_FOCUSED, null);
SwingUtilities.replaceUIActionMap(header, null);
}
//
// Support for mouse rollover
//
/**
* Returns the index of the column header over which the mouse
* currently is. When the mouse is not over the table header,
* -1 is returned.
*
* @return the index of the current rollover column
* @see #rolloverColumnUpdated(int, int)
* @since 1.6
*/
protected int getRolloverColumn() {
return rolloverColumn;
}
/**
* This method gets called every time when a rollover column in the table
* header is updated. Every look and feel that supports a rollover effect
* in a table header should override this method and repaint the header.
*
* @param oldColumn the index of the previous rollover column or -1 if the
* mouse was not over a column
* @param newColumn the index of the new rollover column or -1 if the mouse
* is not over a column
* @see #getRolloverColumn()
* @see JTableHeader#getHeaderRect(int)
* @since 1.6
*/
protected void rolloverColumnUpdated(final int oldColumn, final int newColumn) {
}
protected void updateRolloverColumn(final MouseEvent e) {
if (header.getDraggedColumn() == null &&
header.contains(e.getPoint())) {
int col = header.columnAtPoint(e.getPoint());
if (col != rolloverColumn) {
int oldRolloverColumn = rolloverColumn;
rolloverColumn = col;
rolloverColumnUpdated(oldRolloverColumn, rolloverColumn);
}
}
}
//
// Support for keyboard and mouse access
//
protected int selectNextColumn(final boolean doIt) {
int newIndex = getSelectedColumnIndex();
if (newIndex < header.getColumnModel().getColumnCount() - 1) {
newIndex++;
if (doIt) {
selectColumn(newIndex);
}
}
return newIndex;
}
protected int selectPreviousColumn(final boolean doIt) {
int newIndex = getSelectedColumnIndex();
if (newIndex > 0) {
newIndex--;
if (doIt) {
selectColumn(newIndex);
}
}
return newIndex;
}
/**
* Selects the specified column in the table header. Repaints the
* affected header cells and makes sure the newly selected one is visible.
*/
void selectColumn(final int newColIndex) {
selectColumn(newColIndex, true);
}
void selectColumn(final int newColIndex, final boolean doScroll) {
Rectangle repaintRect = header.getHeaderRect(selectedColumnIndex);
header.repaint(repaintRect);
selectedColumnIndex = newColIndex;
repaintRect = header.getHeaderRect(newColIndex);
header.repaint(repaintRect);
if (doScroll) {
scrollToColumn(newColIndex);
}
return;
}
/**
* Used by selectColumn to scroll horizontally, if necessary,
* to ensure that the newly selected column is visible.
*/
protected void scrollToColumn(final int col) {
Container container;
JTable table;
//Test whether the header is in a scroll pane and has a table.
if ((header.getParent() == null) ||
((container = header.getParent().getParent()) == null) ||
!(container instanceof JScrollPane) ||
((table = header.getTable()) == null)) {
return;
}
//Now scroll, if necessary.
Rectangle vis = table.getVisibleRect();
Rectangle cellBounds = table.getCellRect(0, col, true);
vis.x = cellBounds.x;
vis.width = cellBounds.width;
table.scrollRectToVisible(vis);
}
protected int getSelectedColumnIndex() {
int numCols = header.getColumnModel().getColumnCount();
if (selectedColumnIndex >= numCols && numCols > 0) {
selectedColumnIndex = numCols - 1;
}
return selectedColumnIndex;
}
protected int changeColumnWidth(final TableColumn resizingColumn,
final JTableHeader th,
final int oldWidth, final int newWidth) {
resizingColumn.setWidth(newWidth);
Container container;
JTable table;
if ((th.getParent() == null) ||
((container = th.getParent().getParent()) == null) ||
!(container instanceof JScrollPane) ||
((table = th.getTable()) == null)) {
return 0;
}
if (!container.getComponentOrientation().isLeftToRight() &&
!th.getComponentOrientation().isLeftToRight()) {
JViewport viewport = ((JScrollPane) container).getViewport();
int viewportWidth = viewport.getWidth();
int diff = newWidth - oldWidth;
int newHeaderWidth = table.getWidth() + diff;
/* Resize a table */
Dimension tableSize = table.getSize();
tableSize.width += diff;
table.setSize(tableSize);
/* If this table is in AUTO_RESIZE_OFF mode and
* has a horizontal scrollbar, we need to update
* a view's position.
*/
if ((newHeaderWidth >= viewportWidth) &&
(table.getAutoResizeMode() == JTable.AUTO_RESIZE_OFF)) {
Point p = viewport.getViewPosition();
p.x = Math.max(0, Math.min(newHeaderWidth - viewportWidth,
p.x + diff));
viewport.setViewPosition(p);
return diff;
}
}
return 0;
}
/**
* Returns the baseline.
*
* @throws NullPointerException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
* @see javax.swing.JComponent#getBaseline(int, int)
* @since 1.6
*/
public int getBaseline(final JComponent c, final int width, final int height) {
super.getBaseline(c, width, height);
int baseline = -1;
TableColumnModel columnModel = header.getColumnModel();
for (int column = 0; column < columnModel.getColumnCount();
column++) {
TableColumn aColumn = columnModel.getColumn(column);
Component comp = getHeaderRenderer(column);
Dimension pref = comp.getPreferredSize();
int columnBaseline = comp.getBaseline(pref.width, height);
if (columnBaseline >= 0) {
if (baseline == -1) {
baseline = columnBaseline;
} else if (baseline != columnBaseline) {
baseline = -1;
break;
}
}
}
return baseline;
}
//
// Baseline
//
public void paint(final Graphics g, final JComponent c) {
if (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();
int columnWidth;
Rectangle cellRect = header.getHeaderRect(ltr ? cMin : cMax);
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();
}
//
// Paint Methods and support
//
protected Component getHeaderRenderer(final int columnIndex) {
TableColumn aColumn = header.getColumnModel().getColumn(columnIndex);
TableCellRenderer renderer = aColumn.getHeaderRenderer();
if (renderer == null) {
renderer = header.getDefaultRenderer();
}
boolean hasFocus = !header.isPaintingForPrint()
&& (columnIndex == getSelectedColumnIndex())
&& header.hasFocus();
return renderer.getTableCellRendererComponent(header.getTable(),
aColumn.getHeaderValue(),
false, hasFocus,
-1, columnIndex);
}
protected void paintCell(final Graphics g, final Rectangle cellRect, final int columnIndex) {
Component component = getHeaderRenderer(columnIndex);
rendererPane.paintComponent(g, component, header, cellRect.x, cellRect.y,
cellRect.width, cellRect.height, true);
}
protected int viewIndexForColumn(final TableColumn aColumn) {
TableColumnModel cm = header.getColumnModel();
for (int column = 0; column < cm.getColumnCount(); column++) {
if (cm.getColumn(column) == aColumn) {
return column;
}
}
return -1;
}
protected int getHeaderHeight() {
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;
}
//
// Size Methods
//
protected Dimension createHeaderSize(long width) {
// None of the callers include the intercell spacing, do it here.
if (width > Integer.MAX_VALUE) {
width = Integer.MAX_VALUE;
}
return new Dimension((int) width, getHeaderHeight());
}
/**
* Return the minimum size of the header. The minimum width is the sum
* of the minimum widths of each column (plus inter-cell spacing).
*/
public Dimension getMinimumSize(final JComponent c) {
long width = 0;
Enumeration<TableColumn> enumeration = header.getColumnModel().getColumns();
while (enumeration.hasMoreElements()) {
TableColumn aColumn = enumeration.nextElement();
width = width + aColumn.getMinWidth();
}
return createHeaderSize(width);
}
/**
* 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).
*/
public Dimension getPreferredSize(final JComponent c) {
long width = 0;
Enumeration<TableColumn> enumeration = header.getColumnModel().getColumns();
while (enumeration.hasMoreElements()) {
TableColumn aColumn = enumeration.nextElement();
width = width + aColumn.getPreferredWidth();
}
return createHeaderSize(width);
}
/**
* Return the maximum size of the header. The maximum width is the sum
* of the maximum widths of each column (plus inter-cell spacing).
*/
public Dimension getMaximumSize(final JComponent c) {
long width = 0;
Enumeration<TableColumn> enumeration = header.getColumnModel().getColumns();
while (enumeration.hasMoreElements()) {
TableColumn aColumn = enumeration.nextElement();
width = width + aColumn.getMaxWidth();
}
return createHeaderSize(width);
}
protected static class Actions extends UIAction {
public static final String TOGGLE_SORT_ORDER =
"toggleSortOrder";
public static final String SELECT_COLUMN_TO_LEFT =
"selectColumnToLeft";
public static final String SELECT_COLUMN_TO_RIGHT =
"selectColumnToRight";
public static final String MOVE_COLUMN_LEFT =
"moveColumnLeft";
public static final String MOVE_COLUMN_RIGHT =
"moveColumnRight";
public static final String RESIZE_LEFT =
"resizeLeft";
public static final String RESIZE_RIGHT =
"resizeRight";
public static final String FOCUS_TABLE =
"focusTable";
public Actions(final String name) {
super(name);
}
@Override
public boolean accept(final Object sender) {
if (sender instanceof JTableHeader) {
JTableHeader th = (JTableHeader) sender;
TableColumnModel cm = th.getColumnModel();
if (cm.getColumnCount() <= 0) {
return false;
}
String key = getName();
DarkTableHeaderUIBridge ui =
(DarkTableHeaderUIBridge) DarkUIUtil.getUIOfType(th.getUI(), DarkTableHeaderUIBridge.class);
if (ui != null) {
if (key == MOVE_COLUMN_LEFT) {
return th.getReorderingAllowed()
&& maybeMoveColumn(true, th, ui, false);
} else if (key == MOVE_COLUMN_RIGHT) {
return th.getReorderingAllowed()
&& maybeMoveColumn(false, th, ui, false);
} else if (key == RESIZE_LEFT ||
key == RESIZE_RIGHT) {
return canResize(cm.getColumn(ui.getSelectedColumnIndex()), th);
} else if (key == FOCUS_TABLE) {
return (th.getTable() != null);
}
}
}
return true;
}
public void actionPerformed(final ActionEvent e) {
JTableHeader th = (JTableHeader) e.getSource();
DarkTableHeaderUIBridge ui =
(DarkTableHeaderUIBridge) DarkUIUtil.getUIOfType(th.getUI(), DarkTableHeaderUIBridge.class);
if (ui == null) {
return;
}
String name = getName();
if (TOGGLE_SORT_ORDER == name) {
JTable table = th.getTable();
RowSorter<?> sorter = table == null ? null : table.getRowSorter();
if (sorter != null) {
int columnIndex = ui.getSelectedColumnIndex();
columnIndex = table.convertColumnIndexToModel(
columnIndex);
sorter.toggleSortOrder(columnIndex);
}
} else if (SELECT_COLUMN_TO_LEFT == name) {
if (th.getComponentOrientation().isLeftToRight()) {
ui.selectPreviousColumn(true);
} else {
ui.selectNextColumn(true);
}
} else if (SELECT_COLUMN_TO_RIGHT == name) {
if (th.getComponentOrientation().isLeftToRight()) {
ui.selectNextColumn(true);
} else {
ui.selectPreviousColumn(true);
}
} else if (MOVE_COLUMN_LEFT == name) {
moveColumn(true, th, ui);
} else if (MOVE_COLUMN_RIGHT == name) {
moveColumn(false, th, ui);
} else if (RESIZE_LEFT == name) {
resize(true, th, ui);
} else if (RESIZE_RIGHT == name) {
resize(false, th, ui);
} else if (FOCUS_TABLE == name) {
JTable table = th.getTable();
if (table != null) {
table.requestFocusInWindow();
}
}
}
protected void moveColumn(final boolean leftArrow, final JTableHeader th,
final DarkTableHeaderUIBridge ui) {
maybeMoveColumn(leftArrow, th, ui, true);
}
protected boolean maybeMoveColumn(final boolean leftArrow, final JTableHeader th,
final DarkTableHeaderUIBridge ui, final boolean doIt) {
int oldIndex = ui.getSelectedColumnIndex();
int newIndex;
if (th.getComponentOrientation().isLeftToRight()) {
newIndex = leftArrow ? ui.selectPreviousColumn(doIt)
: ui.selectNextColumn(doIt);
} else {
newIndex = leftArrow ? ui.selectNextColumn(doIt)
: ui.selectPreviousColumn(doIt);
}
if (newIndex != oldIndex) {
if (doIt) {
th.getColumnModel().moveColumn(oldIndex, newIndex);
} else {
return true; // we'd do the move if asked
}
}
return false;
}
protected void resize(final boolean leftArrow, final JTableHeader th,
final DarkTableHeaderUIBridge ui) {
int columnIndex = ui.getSelectedColumnIndex();
TableColumn resizingColumn =
th.getColumnModel().getColumn(columnIndex);
th.setResizingColumn(resizingColumn);
int oldWidth = resizingColumn.getWidth();
int newWidth = oldWidth;
if (th.getComponentOrientation().isLeftToRight()) {
newWidth = newWidth + (leftArrow ? -1 : 1);
} else {
newWidth = newWidth + (leftArrow ? 1 : -1);
}
ui.changeColumnWidth(resizingColumn, th, oldWidth, newWidth);
}
}
/**
* This class should be treated as a &quot;protected&quot; inner class.
* Instantiate it only within subclasses of {@code DarkTableHeaderUIBridge}.
*/
public class MouseInputHandler implements MouseInputListener {
protected int mouseXOffset;
protected Cursor otherCursor = resizeCursor;
public void mouseClicked(final MouseEvent e) {
if (!header.isEnabled()) {
return;
}
if (e.getClickCount() % 2 == 1 &&
SwingUtilities.isLeftMouseButton(e)) {
JTable table = header.getTable();
RowSorter<?> sorter;
if (table != null && (sorter = table.getRowSorter()) != null) {
int columnIndex = header.columnAtPoint(e.getPoint());
if (columnIndex != -1) {
columnIndex = table.convertColumnIndexToModel(
columnIndex);
sorter.toggleSortOrder(columnIndex);
}
}
}
}
protected TableColumn getResizingColumn(final Point p) {
return getResizingColumn(p, header.columnAtPoint(p));
}
protected TableColumn getResizingColumn(final Point p, final int column) {
if (column == -1) {
return null;
}
Rectangle r = header.getHeaderRect(column);
r.grow(-3, 0);
if (r.contains(p)) {
return null;
}
int midPoint = r.x + r.width / 2;
int columnIndex;
if (header.getComponentOrientation().isLeftToRight()) {
columnIndex = (p.x < midPoint) ? column - 1 : column;
} else {
columnIndex = (p.x < midPoint) ? column : column - 1;
}
if (columnIndex == -1) {
return null;
}
return header.getColumnModel().getColumn(columnIndex);
}
public void mousePressed(final MouseEvent e) {
if (!header.isEnabled()) {
return;
}
header.setDraggedColumn(null);
header.setResizingColumn(null);
header.setDraggedDistance(0);
Point p = e.getPoint();
// First find which header cell was hit
TableColumnModel columnModel = header.getColumnModel();
int index = header.columnAtPoint(p);
if (index != -1) {
// The last 3 pixels + 3 pixels of next column are for resizing
TableColumn resizingColumn = getResizingColumn(p, index);
if (canResize(resizingColumn, header)) {
header.setResizingColumn(resizingColumn);
if (header.getComponentOrientation().isLeftToRight()) {
mouseXOffset = p.x - resizingColumn.getWidth();
} else {
mouseXOffset = p.x + resizingColumn.getWidth();
}
} else if (header.getReorderingAllowed()) {
TableColumn hitColumn = columnModel.getColumn(index);
header.setDraggedColumn(hitColumn);
mouseXOffset = p.x;
}
}
if (header.getReorderingAllowed()) {
int oldRolloverColumn = rolloverColumn;
rolloverColumn = -1;
rolloverColumnUpdated(oldRolloverColumn, rolloverColumn);
}
}
protected void swapCursor() {
Cursor tmp = header.getCursor();
header.setCursor(otherCursor);
otherCursor = tmp;
}
public void mouseMoved(final MouseEvent e) {
if (!header.isEnabled()) {
return;
}
if (canResize(getResizingColumn(e.getPoint()), header) !=
(header.getCursor() == resizeCursor)) {
swapCursor();
}
updateRolloverColumn(e);
}
public void mouseDragged(final MouseEvent e) {
if (!header.isEnabled()) {
return;
}
int mouseX = e.getX();
TableColumn resizingColumn = header.getResizingColumn();
TableColumn draggedColumn = header.getDraggedColumn();
boolean headerLeftToRight = header.getComponentOrientation().isLeftToRight();
if (resizingColumn != null) {
int oldWidth = resizingColumn.getWidth();
int newWidth;
if (headerLeftToRight) {
newWidth = mouseX - mouseXOffset;
} else {
newWidth = mouseXOffset - mouseX;
}
mouseXOffset += changeColumnWidth(resizingColumn, header,
oldWidth, newWidth);
} else if (draggedColumn != null) {
TableColumnModel cm = header.getColumnModel();
int draggedDistance = mouseX - mouseXOffset;
int direction = (draggedDistance < 0) ? -1 : 1;
int columnIndex = viewIndexForColumn(draggedColumn);
int newColumnIndex = columnIndex + (headerLeftToRight ? direction : -direction);
if (0 <= newColumnIndex && newColumnIndex < cm.getColumnCount()) {
int width = cm.getColumn(newColumnIndex).getWidth();
if (Math.abs(draggedDistance) > (width / 2)) {
mouseXOffset = mouseXOffset + direction * width;
header.setDraggedDistance(draggedDistance - direction * width);
//Cache the selected column.
int selectedIndex = SwingUtilities2.convertColumnIndexToModel(header.getColumnModel(),
getSelectedColumnIndex());
//Now do the move.
cm.moveColumn(columnIndex, newColumnIndex);
//Update the selected index.
selectColumn(SwingUtilities2.convertColumnIndexToView(header.getColumnModel(), selectedIndex),
false);
return;
}
}
setDraggedDistance(draggedDistance, columnIndex);
}
updateRolloverColumn(e);
}
public void mouseReleased(final MouseEvent e) {
if (!header.isEnabled()) {
return;
}
setDraggedDistance(0, viewIndexForColumn(header.getDraggedColumn()));
header.setResizingColumn(null);
header.setDraggedColumn(null);
updateRolloverColumn(e);
}
public void mouseEntered(final MouseEvent e) {
if (!header.isEnabled()) {
return;
}
updateRolloverColumn(e);
}
public void mouseExited(final MouseEvent e) {
if (!header.isEnabled()) {
return;
}
int oldRolloverColumn = rolloverColumn;
rolloverColumn = -1;
rolloverColumnUpdated(oldRolloverColumn, rolloverColumn);
}
//
// Protected & protected Methods
//
protected void setDraggedDistance(final int draggedDistance, final int column) {
header.setDraggedDistance(draggedDistance);
if (column != -1) {
header.getColumnModel().moveColumn(column, column);
}
}
}
}

341
src/main/java/com/weis/darklaf/ui/table/DarkTableUI.java

@ -0,0 +1,341 @@
package com.weis.darklaf.ui.table;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import sun.swing.SwingUtilities2;
import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import java.awt.*;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
public class DarkTableUI extends DarkTableUIBridge {
private static final int ROW_HEIGHT = 22;
private final FocusListener focusListener = new FocusListener() {
@Override
public void focusGained(final FocusEvent e) {
var bg = table.getSelectionBackground();
if (bg instanceof UIResource) {
table.setSelectionBackground(UIManager.getColor("Table.focusSelectionBackground"));
}
table.repaint();
}
@Override
public void focusLost(final FocusEvent e) {
var bg = table.getSelectionBackground();
if (bg instanceof UIResource) {
table.setSelectionBackground(UIManager.getColor("Table.selectionBackground"));
}
table.repaint();
}
};
@NotNull
@Contract("_ -> new")
public static ComponentUI createUI(final JComponent c) {
return new DarkTableUI();
}
protected static int adjustDistance(final int distance, @NotNull final Rectangle rect,
@NotNull final JTable comp) {
int dist = distance;
int min = 0;
int max = comp.getX() + comp.getWidth();
if (rect.x + dist <= min) {
dist = min - rect.x;
}
if (rect.x + rect.width + dist >= max) {
dist = max - rect.x - rect.width;
}
return dist;
}
@Override
protected void installDefaults() {
super.installDefaults();
table.setRowHeight(ROW_HEIGHT);
}
@Override
protected void installListeners() {
super.installListeners();
table.addFocusListener(focusListener);
}
@Override
protected void uninstallListeners() {
super.uninstallListeners();
table.removeFocusListener(focusListener);
}
@Override
protected void paintDraggedArea(@NotNull final Graphics g, final int rMin, final int rMax,
final int cMin, final int cMax,
final TableColumn draggedColumn, final int distance) {
int draggedColumnIndex = viewIndexForColumn(draggedColumn);
Rectangle minCell = table.getCellRect(rMin, draggedColumnIndex, true);
Rectangle maxCell = table.getCellRect(rMax, draggedColumnIndex, true);
Rectangle vacatedColumnRect = minCell.union(maxCell);
int dist = adjustDistance(distance, vacatedColumnRect, table);
// Paint a gray well in place of the moving column.
g.setColor(table.getParent().getBackground());
g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,
vacatedColumnRect.width - 1, vacatedColumnRect.height);
// Move to the where the cell has been dragged.
vacatedColumnRect.x += dist;
boolean scrollVisible = scrollBarVisible();
boolean drawBottomBorder = !table.getShowHorizontalLines() && !scrollVisible;
boolean ltr = table.getComponentOrientation().isLeftToRight();
// Fill the background.
g.setColor(table.getBackground());
g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,
vacatedColumnRect.width, vacatedColumnRect.height);
// Paint the vertical grid lines if necessary.
if (table.getShowVerticalLines()) {
g.setColor(table.getGridColor());
int x1 = vacatedColumnRect.x;
int y1 = vacatedColumnRect.y;
int x2 = x1 + vacatedColumnRect.width - 1;
int y2 = y1 + vacatedColumnRect.height - 1;
boolean onLeftEdge = ltr ? draggedColumnIndex == cMin : draggedColumnIndex == cMax;
boolean onRightEdge = ltr ? draggedColumnIndex == cMax : draggedColumnIndex == cMin;
if (scrollBarVisible()) {
if (isScrollPaneRtl()) {
onLeftEdge = false;
} else {
onRightEdge = false;
}
}
// Left
if (dist != 0 || !onLeftEdge) {
if (draggedColumnIndex == cMin && scrollBarVisible() && isScrollPaneRtl()) x1++;
g.fillRect(x1 - 1, y1, 1, y2 - y1);
}
// Right
if (dist != 0 || !onRightEdge) {
g.fillRect(x2, y1, 1, y2 - y1);
}
}
for (int row = rMin; row <= rMax; row++) {
// Render the cell value
Rectangle r = table.getCellRect(row, draggedColumnIndex, false);
r.x += dist;
paintCell(g, r, row, draggedColumnIndex, cMin, cMax);
// Paint the (lower) horizontal grid line if necessary.
if (table.getShowHorizontalLines() || (!scrollVisible && row == rMax)) {
g.setColor(table.getGridColor());
if (drawBottomBorder) {
g.setColor(getBorderColor());
}
Rectangle rcr = table.getCellRect(row, draggedColumnIndex, true);
rcr.x += dist;
int x1 = rcr.x - 1;
int y1 = rcr.y;
int x2 = x1 + rcr.width + 1;
int y2 = y1 + rcr.height - 1;
g.fillRect(x1, y2, x2 - x1, 1);
}
}
if (drawBottomBorder) {
var rect = table.getCellRect(rMax, draggedColumnIndex, true);
int y = rect.y + rect.height - 1;
g.setColor(getBorderColor());
g.fillRect(rect.x, y, rect.width, 1);
}
}
@Override
protected void paintGrid(@NotNull final Graphics g,
final int rMin, final int rMax, final int cMin, final int cMax) {
g.setColor(table.getGridColor());
Rectangle minCell = table.getCellRect(rMin, cMin, true);
Rectangle maxCell = table.getCellRect(rMax, cMax, true);
Rectangle damagedArea = minCell.union(maxCell);
int draggedIndex = viewIndexForColumn(table.getTableHeader().getDraggedColumn());
if (table.getShowHorizontalLines()) {
int tableWidth = damagedArea.x + damagedArea.width;
if (table.getComponentOrientation().isLeftToRight()) {
if (draggedIndex == cMax) {
tableWidth -= 1;
}
} else {
if (draggedIndex == cMin) {
tableWidth -= 1;
}
}
int y = damagedArea.y;
for (int row = rMin; row <= rMax; row++) {
y += table.getRowHeight(row);
SwingUtilities2.drawHLine(g, damagedArea.x, tableWidth - 1, y - 1);
}
}
boolean scrollPaneRtl = isScrollPaneRtl();
boolean scrollVisible = scrollBarVisible();
if (table.getShowVerticalLines()) {
TableColumnModel cm = table.getColumnModel();
int tableHeight = damagedArea.y + damagedArea.height;
int x;
boolean ltr = table.getComponentOrientation().isLeftToRight();
if (ltr) {
x = damagedArea.x;
if (scrollPaneRtl && scrollBarVisible()) {
SwingUtilities2.drawVLine(g, x, 0, tableHeight - 1);
}
for (int column = cMin; column <= cMax; column++) {
int w = cm.getColumn(column).getWidth();
x += w;
if (showVerticalLine(true, scrollVisible, !scrollPaneRtl, column, draggedIndex, cMin, cMax)) {
SwingUtilities2.drawVLine(g, x - 1, 0, tableHeight - 1);
}
}
} else {
x = damagedArea.x;
if (scrollPaneRtl && scrollBarVisible()) {
SwingUtilities2.drawVLine(g, x, 0, tableHeight - 1);
}
for (int column = cMax; column >= cMin; column--) {
int w = cm.getColumn(column).getWidth();
x += w;
if (showVerticalLine(false, scrollVisible, !scrollPaneRtl, column, draggedIndex, cMin, cMax)) {
SwingUtilities2.drawVLine(g, x - 1, 0, tableHeight - 1);
}
}
}
}
if (!table.getShowHorizontalLines() && table.getRowCount() != 0 && !scrollVisible) {
g.setColor(getBorderColor());
int y = table.getHeight() - 1;
g.fillRect(0, y, table.getWidth(), 1);
}
}
protected Color getBorderColor() {
return UIManager.getColor("TableHeader.borderColor");
}
protected boolean isScrollPaneRtl() {
if (!isInScrollPane()) return false;
Container comp = SwingUtilities.getUnwrappedParent(table).getParent();
return !comp.getComponentOrientation().isLeftToRight();
}
protected boolean scrollBarVisible() {
Container comp = SwingUtilities.getUnwrappedParent(table);
if (comp != null) {
comp = comp.getParent();
}
return comp instanceof JScrollPane && ((JScrollPane) comp).getVerticalScrollBar().isVisible();
}
protected boolean isInScrollPane() {
Container comp = SwingUtilities.getUnwrappedParent(table);
if (comp != null) {
comp = comp.getParent();
}
return comp instanceof JScrollPane;
}
protected boolean showVerticalLine(final boolean ltr, final boolean scrollVisible,
final boolean scrollLtR, final int column, final int draggedIndex,
final int cMin, final int cMax) {
int dist = adjustDistance(table.getTableHeader().getDraggedDistance(),
table.getCellRect(0, draggedIndex, true),
table);
boolean isDragged = column == draggedIndex && dist != 0;
if (!scrollVisible) {
if (ltr) {
return column != cMax;
} else {
return column != cMin;
}
} else {
if (ltr) {
if (scrollLtR) {
return column != cMax || !isDragged;
} else {
return column != cMax;
}
} else {
if (scrollLtR) {
return column != cMin || !isDragged;
} else {
return column != cMin;
}
}
}
}
@Override
protected void paintCell(final Graphics g, final Rectangle cellRect, final int row, final int column,
final int cMin, final int cMax) {
boolean scrollLtR = !isScrollPaneRtl();
boolean ltr = table.getComponentOrientation().isLeftToRight();
int draggedIndex = viewIndexForColumn(table.getTableHeader().getDraggedColumn());
int dist = adjustDistance(table.getTableHeader().getDraggedDistance(),
table.getCellRect(row, draggedIndex, true),
table);
boolean isDragged = column == draggedIndex && dist != 0;
var r = new Rectangle(cellRect);
if (!scrollBarVisible()) {
if (ltr) {
if (column == cMax && !isDragged) r.width += 1;
} else {
if (column == cMin && !isDragged) r.width += 1;
}
} else if (!scrollLtR) {
if (ltr) {
if (column == cMax && !isDragged) r.width += 1;
if (column == cMin && !isDragged) {
r.width -= 1;
r.x += 1;
}
} else {
if (column == cMin && !isDragged) r.width += 1;
if (column == cMax && !isDragged) {
r.width -= 1;
r.x += 1;
}
}
}
if (table.isEditing() && table.getEditingRow() == row &&
table.getEditingColumn() == column) {
Component component = table.getEditorComponent();
if (component instanceof JComponent) {
//Todo
var border = UIManager.getBorder("Table.cellEditorBorder");
((JComponent) component).setBorder(border);
}
component.setBounds(r);
component.validate();
} else {
TableCellRenderer renderer = table.getCellRenderer(row, column);
Component component = table.prepareRenderer(renderer, row, column);
rendererPane.paintComponent(g, component, table, r.x, r.y,
r.width, r.height, true);
}
}
}

432
src/main/java/com/weis/darklaf/ui/table/DarkTableUIBridge.java

@ -0,0 +1,432 @@
package com.weis.darklaf.ui.table;
import org.jetbrains.annotations.NotNull;
import sun.swing.SwingUtilities2;
import javax.swing.*;
import javax.swing.plaf.basic.BasicTableUI;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import java.awt.*;
public class DarkTableUIBridge extends BasicTableUI {
protected static int getAdjustedLead(final JTable table,
final boolean row,
final ListSelectionModel model) {
int index = model.getLeadSelectionIndex();
int compare = row ? table.getRowCount() : table.getColumnCount();
return index < compare ? index : -1;
}
protected static int getAdjustedLead(final JTable table, final boolean row) {
return row ? getAdjustedLead(table, row, table.getSelectionModel())
: getAdjustedLead(table, row, table.getColumnModel().getSelectionModel());
}
/**
* Paint a representation of the <code>table</code> instance
* that was set in installUI().
*/
public void paint(@NotNull final Graphics g, final JComponent c) {
Rectangle clip = g.getClipBounds();
Rectangle bounds = table.getBounds();
// account for the fact that the graphics has already been translated
// into the table's bounds
bounds.x = bounds.y = 0;
if (table.getRowCount() <= 0 || table.getColumnCount() <= 0 ||
// this check prevents us from painting the entire table
// when the clip doesn't intersect our bounds at all
!bounds.intersects(clip)) {
paintDropLines(g);
return;
}
boolean ltr = table.getComponentOrientation().isLeftToRight();
Point upperLeft, lowerRight;
// compute the visible part of table which needs to be painted
Rectangle visibleBounds = clip.intersection(bounds);
upperLeft = visibleBounds.getLocation();
lowerRight = new Point(visibleBounds.x + visibleBounds.width - 1,
visibleBounds.y + visibleBounds.height - 1);
int rMin = table.rowAtPoint(upperLeft);
int rMax = table.rowAtPoint(lowerRight);
// This should never happen (as long as our bounds intersect the clip,
// which is why we bail above if that is the case).
if (rMin == -1) {
rMin = 0;
}
// If the table does not have enough rows to fill the view we'll get -1.
// (We could also get -1 if our bounds don't intersect the clip,
// which is why we bail above if that is the case).
// Replace this with the index of the last row.
if (rMax == -1) {
rMax = table.getRowCount() - 1;
}
// For FIT_WIDTH, all columns should be printed irrespective of
// how many columns are visible. So, we used clip which is already set to
// total col width instead of visible region
// Since JTable.PrintMode is not accessible
// from here, we aet "Table.printMode" in TablePrintable#print and
// access from here.
Object printMode = table.getClientProperty("Table.printMode");
if ((printMode == JTable.PrintMode.FIT_WIDTH)) {
upperLeft = clip.getLocation();
lowerRight = new Point(clip.x + clip.width - 1,
clip.y + clip.height - 1);
}
int cMin = table.columnAtPoint(ltr ? upperLeft : lowerRight);
int cMax = table.columnAtPoint(ltr ? lowerRight : upperLeft);
// 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 = table.getColumnCount() - 1;
}
Container comp = SwingUtilities.getUnwrappedParent(table);
if (comp != null) {
comp = comp.getParent();
}
if (comp != null && !(comp instanceof JViewport) && !(comp instanceof JScrollPane)) {
// We did rMax-1 to paint the same number of rows that are drawn on console
// otherwise 1 extra row is printed per page than that are displayed
// when there is no scrollPane and we do printing of table
// but not when rmax is already pointing to index of last row
// and if there is any selected rows
if (rMax != (table.getRowCount() - 1) &&
(table.getSelectedRow() == -1)) {
// Do not decrement rMax if rMax becomes
// less than or equal to rMin
// else cells will not be painted
if (rMax - rMin > 1) {
rMax = rMax - 1;
}
}
}
// Paint the grid.
paintGrid(g, rMin, rMax, cMin, cMax);
// Paint the cells.
paintCells(g, rMin, rMax, cMin, cMax);
paintDropLines(g);
}
protected void paintDropLines(final Graphics g) {
JTable.DropLocation loc = table.getDropLocation();
if (loc == null) {
return;
}
Color color = UIManager.getColor("Table.dropLineColor");
Color shortColor = UIManager.getColor("Table.dropLineShortColor");
if (color == null && shortColor == null) {
return;
}
Rectangle rect;
rect = getHDropLineRect(loc);
if (rect != null) {
int x = rect.x;
int w = rect.width;
if (color != null) {
extendRect(rect, true);
g.setColor(color);
g.fillRect(rect.x, rect.y, rect.width, rect.height);
}
if (!loc.isInsertColumn() && shortColor != null) {
g.setColor(shortColor);
g.fillRect(x, rect.y, w, rect.height);
}
}
rect = getVDropLineRect(loc);
if (rect != null) {
int y = rect.y;
int h = rect.height;
if (color != null) {
extendRect(rect, false);
g.setColor(color);
g.fillRect(rect.x, rect.y, rect.width, rect.height);
}
if (!loc.isInsertRow() && shortColor != null) {
g.setColor(shortColor);
g.fillRect(rect.x, y, rect.width, h);
}
}
}
protected Rectangle getHDropLineRect(final JTable.DropLocation loc) {
if (!loc.isInsertRow()) {
return null;
}
int row = loc.getRow();
int col = loc.getColumn();
if (col >= table.getColumnCount()) {
col--;
}
Rectangle rect = table.getCellRect(row, col, true);
if (row >= table.getRowCount()) {
row--;
Rectangle prevRect = table.getCellRect(row, col, true);
rect.y = prevRect.y + prevRect.height;
}
if (rect.y == 0) {
rect.y = -1;
} else {
rect.y -= 2;
}
rect.height = 3;
return rect;
}
protected Rectangle getVDropLineRect(final JTable.DropLocation loc) {
if (!loc.isInsertColumn()) {
return null;
}
boolean ltr = table.getComponentOrientation().isLeftToRight();
int col = loc.getColumn();
Rectangle rect = table.getCellRect(loc.getRow(), col, true);
if (col >= table.getColumnCount()) {
col--;
rect = table.getCellRect(loc.getRow(), col, true);
if (ltr) {
rect.x = rect.x + rect.width;
}
} else if (!ltr) {
rect.x = rect.x + rect.width;
}
if (rect.x == 0) {
rect.x = -1;
} else {
rect.x -= 2;
}
rect.width = 3;
return rect;
}
protected Rectangle extendRect(final Rectangle rect, final boolean horizontal) {
if (rect == null) {
return rect;
}
if (horizontal) {
rect.x = 0;
rect.width = table.getWidth();
} else {
rect.y = 0;
if (table.getRowCount() != 0) {
Rectangle lastRect = table.getCellRect(table.getRowCount() - 1, 0, true);
rect.height = lastRect.y + lastRect.height;
} else {
rect.height = table.getHeight();
}
}
return rect;
}
/*
* Paints the grid lines within <I>aRect</I>, using the grid
* color set with <I>setGridColor</I>. Paints vertical lines
* if <code>getShowVerticalLines()</code> returns true and paints
* horizontal lines if <code>getShowHorizontalLines()</code>
* returns true.
*/
protected void paintGrid(final Graphics g, final int rMin, final int rMax, final int cMin, final int cMax) {
g.setColor(table.getGridColor());
Rectangle minCell = table.getCellRect(rMin, cMin, true);
Rectangle maxCell = table.getCellRect(rMax, cMax, true);
Rectangle damagedArea = minCell.union(maxCell);
if (table.getShowHorizontalLines()) {
int tableWidth = damagedArea.x + damagedArea.width;
int y = damagedArea.y;
for (int row = rMin; row <= rMax; row++) {
y += table.getRowHeight(row);
SwingUtilities2.drawHLine(g, damagedArea.x, tableWidth - 1, y - 1);
}
}
if (table.getShowVerticalLines()) {
TableColumnModel cm = table.getColumnModel();
int tableHeight = damagedArea.y + damagedArea.height;
int x;
if (table.getComponentOrientation().isLeftToRight()) {
x = damagedArea.x;
for (int column = cMin; column <= cMax; column++) {
int w = cm.getColumn(column).getWidth();
x += w;
SwingUtilities2.drawVLine(g, x - 1, 0, tableHeight - 1);
}
} else {
x = damagedArea.x;
for (int column = cMax; column >= cMin; column--) {
int w = cm.getColumn(column).getWidth();
x += w;
SwingUtilities2.drawVLine(g, x - 1, 0, tableHeight - 1);
}
}
}
}
protected int viewIndexForColumn(final TableColumn aColumn) {
TableColumnModel cm = table.getColumnModel();
for (int column = 0; column < cm.getColumnCount(); column++) {
if (cm.getColumn(column) == aColumn) {
return column;
}
}
return -1;
}
protected void paintCells(final Graphics g, final int rMin, final int rMax, final int cMin, final int cMax) {
JTableHeader header = table.getTableHeader();
TableColumn draggedColumn = (header == null) ? null : header.getDraggedColumn();
TableColumnModel cm = table.getColumnModel();
int columnMargin = cm.getColumnMargin();
Rectangle cellRect;
TableColumn aColumn;
int columnWidth;
if (table.getComponentOrientation().isLeftToRight()) {
for (int row = rMin; row <= rMax; row++) {
cellRect = table.getCellRect(row, cMin, false);
for (int column = cMin; column <= cMax; column++) {
aColumn = cm.getColumn(column);
columnWidth = aColumn.getWidth();
cellRect.width = columnWidth - columnMargin;
if (aColumn != draggedColumn) {
paintCell(g, cellRect, row, column, cMin, cMax);
}
cellRect.x += columnWidth;
}
}
} else {
for (int row = rMin; row <= rMax; row++) {
cellRect = table.getCellRect(row, cMin, false);
aColumn = cm.getColumn(cMin);
if (aColumn != draggedColumn) {
columnWidth = aColumn.getWidth();
cellRect.width = columnWidth - columnMargin;
paintCell(g, cellRect, row, cMin, cMin, cMax);
}
for (int column = cMin + 1; column <= cMax; column++) {
aColumn = cm.getColumn(column);
columnWidth = aColumn.getWidth();
cellRect.width = columnWidth - columnMargin;
cellRect.x -= columnWidth;
if (aColumn != draggedColumn) {
paintCell(g, cellRect, row, column, cMin, cMax);
}
}
}
}
// Paint the dragged column if we are dragging.
if (draggedColumn != null) {
paintDraggedArea(g, rMin, rMax, cMin, cMax, draggedColumn, header.getDraggedDistance());
}
// Remove any renderers that may be left in the rendererPane.
rendererPane.removeAll();
}
protected void paintDraggedArea(final Graphics g, final int rMin, final int rMax, final int cMin, final int cMax,
final TableColumn draggedColumn, final int distance) {
int draggedColumnIndex = viewIndexForColumn(draggedColumn);
Rectangle minCell = table.getCellRect(rMin, draggedColumnIndex, true);
Rectangle maxCell = table.getCellRect(rMax, draggedColumnIndex, true);
Rectangle vacatedColumnRect = minCell.union(maxCell);
// Paint a gray well in place of the moving column.
g.setColor(table.getParent().getBackground());
g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,
vacatedColumnRect.width, vacatedColumnRect.height);
// Move to the where the cell has been dragged.
vacatedColumnRect.x += distance;
// Fill the background.
g.setColor(table.getBackground());
g.fillRect(vacatedColumnRect.x, vacatedColumnRect.y,
vacatedColumnRect.width, vacatedColumnRect.height);
// Paint the vertical grid lines if necessary.
if (table.getShowVerticalLines()) {
g.setColor(table.getGridColor());
int x1 = vacatedColumnRect.x;
int y1 = vacatedColumnRect.y;
int x2 = x1 + vacatedColumnRect.width - 1;
int y2 = y1 + vacatedColumnRect.height - 1;
// Left
g.fillRect(x1 - 1, y1, 1, y2 - y1);
// Right
g.fillRect(x2 - 1, y1, 1, y2 - y1);
}
for (int row = rMin; row <= rMax; row++) {
// Render the cell value
Rectangle r = table.getCellRect(row, draggedColumnIndex, false);
r.x += distance;
paintCell(g, r, row, draggedColumnIndex, cMin, cMax);
// Paint the (lower) horizontal grid line if necessary.
if (table.getShowHorizontalLines()) {
g.setColor(table.getGridColor());
Rectangle rcr = table.getCellRect(row, draggedColumnIndex, true);
rcr.x += distance;
int x1 = rcr.x;
int y1 = rcr.y;
int x2 = x1 + rcr.width - 1;
int y2 = y1 + rcr.height - 1;
g.fillRect(x1 - 1, y2 - 1, x2 - x1, 1);
}
}
}
protected void paintCell(final Graphics g, final Rectangle cellRect, final int row, final int column,
final int cMin, final int cMax) {
if (table.isEditing() && table.getEditingRow() == row &&
table.getEditingColumn() == column) {
Component component = table.getEditorComponent();
component.setBounds(cellRect);
component.validate();
} else {
TableCellRenderer renderer = table.getCellRenderer(row, column);
Component component = table.prepareRenderer(renderer, row, column);
rendererPane.paintComponent(g, component, table, cellRect.x, cellRect.y,
cellRect.width, cellRect.height, true);
}
}
}
Loading…
Cancel
Save