/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package com.bearsoft.gui.grid.header.cell;
import com.bearsoft.gui.grid.IconCache;
import com.bearsoft.gui.grid.header.GridColumnsNode;
import com.bearsoft.gui.grid.header.MultiLevelHeader;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.RowSorter;
import javax.swing.SortOrder;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.MatteBorder;
import javax.swing.text.View;
/**
*
* @author mg
*/
public class HeaderCell extends JEditorPane {
public static final Color defaultEdgeColor = new Color(118, 187, 246);
public static final Color defaultBottomColor = new Color(248, 169, 0);
public static final Color defaultBottomLightColor = new Color(252, 194, 71);
private static final int SORTING_INDEX_TEXT_INSET = 2;
private static final Font SORTING_ORDER_FONT = new Font(Font.SERIF, 0, 9);
public static final String HTML_TEMPLATE = ""
+ "<html>"
+ " <head>"
+ " </head>"
+ " <body>"
+ " <p style=\"margin-top:0;font-family:%s;font-size:%dpt;font-weight:%s\" align=center>"
+ "%s"
+ " </p>"
+ " </body>"
+ "</html>";
protected MultiLevelHeader header;
protected GridColumnsNode colGroup;
protected JPanel samplePanel = new JPanel();
protected boolean rolledover = false;
protected boolean leftRolledover = false;
protected boolean rightRolledover = false;
protected Color uiEdgeColor;
protected Color rolledOverOutlineColor = new Color(168, 216, 235);
protected Color rolledOverFillColor = new Color(231, 239, 243);
protected PropertyChangeListener groupListener = (PropertyChangeEvent evt) -> {
if ("background".equals(evt.getPropertyName())) {
setBackground((Color) evt.getNewValue());
} else if ("foreground".equals(evt.getPropertyName())) {
setForeground((Color) evt.getNewValue());
} else if ("font".equals(evt.getPropertyName())) {
setFont((Font) evt.getNewValue());
} else if ("title".equals(evt.getPropertyName())
&& (evt.getNewValue() == null || evt.getNewValue() instanceof String)) {
applyTitle();
} else if ("width".equals(evt.getPropertyName()) || "preferredWidth".equals(evt.getPropertyName())
|| "maxWidth".equals(evt.getPropertyName()) || "minWidth".equals(evt.getPropertyName())) {
invalidate();
}
};
public HeaderCell(GridColumnsNode aColGroup, MultiLevelHeader aHeader) {
super();
setEditable(false);
setFocusable(false);
setContentType("text/html");
header = aHeader;
setColGroup(aColGroup);
setBorder(createCellRaisedBorder());
setAutoscrolls(false);
CellHighlighter highlighter = new CellHighlighter(this);
addMouseListener(highlighter);
addMouseMotionListener(highlighter);
CellResizer resizer = new CellResizer(this, aHeader);
addMouseListener(resizer);
addMouseMotionListener(resizer);
CellMover mover = new CellMover(this);
addMouseListener(mover);
addMouseMotionListener(mover);
CellSortingToggler toggler = new CellSortingToggler(this);
addMouseListener(toggler);
setOpaque(false);
updateUIData();
setDoubleBuffered(true);
setOpaque(false);
putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, true);
}
protected void applyTitle() {
if (colGroup != null) {
String title = colGroup.getTitle();
setText(String.format(HTML_TEMPLATE, getFont().getFamily(), getFont().getSize(), getFont().isBold() ? "bold" : "normal", title != null ? title : ""));
}
}
@Override
public void setFont(Font font) {
super.setFont(font);
applyTitle();
}
@Override
public void setForeground(Color fg) {
super.setForeground(fg);
}
/*
public static java.awt.Font toNativeFont(com.eas.gui.Font aFont) {
return new java.awt.Font(aFont.getFamily(), CascadedStyle.fontStyleToNativeFontStyle(aFont.getStyle()), aFont.getSize());
}
*/
protected final void updateUIData() {
uiEdgeColor = UIManager.getColor("InternalFrame.activeTitleGradient");
}
public MultiLevelHeader getHeader() {
return header;
}
@Override
public Dimension getMinimumSize() {
if (colGroup.isLeaf()) {
Dimension d = super.getMinimumSize();
View view = getUI().getRootView(this);
if (view != null) {
d.width = Math.round(view.getMinimumSpan(View.X_AXIS));
}
return new Dimension(Math.max(d.width, colGroup.getMinWidth()), d.height);
} else {
Dimension d = super.getPreferredSize();
return new Dimension(0, d.height);
}
}
@Override
public Dimension getMaximumSize() {
if (colGroup.isLeaf()) {
Dimension d = super.getMaximumSize();
return new Dimension(Math.min(d.width, colGroup.getMaxWidth()), d.height);
} else {
Dimension d = super.getPreferredSize();
return new Dimension(Integer.MAX_VALUE, d.height);
}
}
@Override
public Dimension getPreferredSize() {
if (colGroup.isLeaf()) {
int colGroupPWidth = colGroup.getWidth();
setSize(colGroupPWidth, Integer.MAX_VALUE / 2);
Dimension d = super.getPreferredSize();
return new Dimension(colGroupPWidth, d.height);
} else {
Dimension d = super.getPreferredSize();
return new Dimension(0, d.height);
}
}
private int checkSortOrder() {
if (colGroup.isLeaf() && colGroup.getTableColumn() != null) {
int modelIndex = colGroup.getTableColumn().getModelIndex();
List<? extends RowSorter.SortKey> sortKeys = header.getRowSorter().getSortKeys();
for (int i = 0; i < sortKeys.size(); i++) {
RowSorter.SortKey sk = sortKeys.get(i);
if (sk.getColumn() == modelIndex) {
return i;
}
}
}
return -1;
}
private Border createCellRaisedBorder() {
MatteBorder innerBorder = new MatteBorder(1, 1, 0, 0, getBackground().brighter());
MatteBorder outerBorder = new MatteBorder(0, 0, 1, 1, getBackground().darker());
CompoundBorder border = new CompoundBorder(innerBorder, outerBorder);
return border;
}
public Border createCellLoweredBorder() {
MatteBorder innerBorder = new MatteBorder(0, 0, 1, 1, getBackground().brighter());
MatteBorder outerBorder = new MatteBorder(1, 1, 0, 0, getBackground().darker());
CompoundBorder border = new CompoundBorder(innerBorder, outerBorder);
return border;
}
@Override
public void updateUI() {
super.updateUI();
if (samplePanel != null) {
samplePanel.updateUI();
setBackground(samplePanel.getBackground());
updateUIData();
}
}
public GridColumnsNode getColGroup() {
return colGroup;
}
public void setColGroup(GridColumnsNode aValue) {
if (colGroup != aValue) {
if (colGroup != null) {
colGroup.getChangeSupport().removePropertyChangeListener(groupListener);
}
colGroup = aValue;
if (colGroup != null) {
colGroup.getChangeSupport().addPropertyChangeListener(groupListener);
}
applyTitle();
}
}
public boolean isRolledover() {
return rolledover;
}
public void setRolledover(boolean aValue) {
rolledover = aValue;
repaint();
}
public boolean isLeftRolledover() {
return leftRolledover;
}
public void setLeftRolledover(boolean aValue) {
leftRolledover = aValue;
repaint();
}
public boolean isRightRolledover() {
return rightRolledover;
}
public void setRightRolledover(boolean aValue) {
rightRolledover = aValue;
repaint();
}
@Override
protected void paintBorder(Graphics g) {
super.paintBorder(g);
if (leftRolledover || rightRolledover) {
Dimension d = getSize();
Color edgeColor = uiEdgeColor != null ? uiEdgeColor : defaultEdgeColor;
Color oldEdgeColor = g.getColor();
try {
g.setColor(rolledOverOutlineColor);
g.drawRect(0, 0, d.width, d.height);
g.setColor(edgeColor.darker());
if (leftRolledover) {
g.fillRect(1, 0, Math.round(MultiLevelHeader.PICK_MARGIN_SIZE), d.height);
}
if (rightRolledover) {
g.fillRect(d.width - Math.round(MultiLevelHeader.PICK_MARGIN_SIZE) - 2, 0, Math.round(MultiLevelHeader.PICK_MARGIN_SIZE), d.height);
}
} finally {
g.setColor(oldEdgeColor);
}
}
paintSorting(g);
}
@Override
protected void paintComponent(Graphics g) {
if (g instanceof Graphics2D) {
Graphics2D g2d = (Graphics2D) g.create();
Dimension d = getSize();
if (leftRolledover || rightRolledover) {
g2d.setColor(rolledOverFillColor);
g2d.fillRect(0, 0, d.width, d.height);
}
if (getColGroup().isLeaf() && !rolledover && !leftRolledover && !rightRolledover) {
Color bottomColor = getBackground();
Paint gradient2 = new GradientPaint(new Point2D.Float(0, d.height - 5), bottomColor, new Point2D.Float(0, d.height + 10), bottomColor.darker());
Paint oldPaint = g2d.getPaint();
try {
g2d.setPaint(gradient2);
g2d.fillRect(0, d.height - 3, d.width, d.height);
} finally {
g2d.setPaint(oldPaint);
}
}
if (rolledover && !leftRolledover && !rightRolledover) {
Color oldColor = g2d.getColor();
try {
g2d.setColor(defaultBottomColor);
g2d.fillRect(0, d.height - 3, d.width, d.height);
g2d.setColor(defaultBottomLightColor);
g2d.fillRect(0, d.height - 2, d.width, d.height);
} finally {
g2d.setColor(oldColor);
}
}
}
// The folowing line replaces super.paintComponenet(g) call
// because some LAFs fill the background and despite opaque flag!
getUI().paint(g, this);
}
private void paintSorting(Graphics g) {
if (header.getRowSorter() != null) {
int sortIndex = checkSortOrder();
if (colGroup.isLeaf() && sortIndex != -1) {
Rectangle bounds = getBounds();
bounds.x = 0;
bounds.y = 0;
int sX = -1;
int sH = -1;
SortOrder sOrder = ((RowSorter.SortKey) header.getRowSorter().getSortKeys().get(sortIndex)).getSortOrder();
if (sOrder != SortOrder.UNSORTED) {
String sIndex = String.valueOf(sortIndex + 1);
Rectangle2D sOrderBounds = g.getFontMetrics().getStringBounds(sIndex, g);
Font oldFont = g.getFont();
Color oldCol = g.getColor();
try {
g.setColor(Color.gray);
g.setFont(SORTING_ORDER_FONT);
sX = bounds.x + (int) (bounds.width - sOrderBounds.getWidth() - SORTING_INDEX_TEXT_INSET);
sH = (int) sOrderBounds.getHeight();
g.drawString(sIndex, sX, bounds.y + sH - SORTING_INDEX_TEXT_INSET);
} finally {
g.setFont(oldFont);
g.setColor(oldCol);
}
}
if (sOrder == SortOrder.ASCENDING) {
g.drawImage(IconCache.getImage("ascending.png"), sX - 12, bounds.y - SORTING_INDEX_TEXT_INSET + 2, null);
} else if (sOrder == SortOrder.DESCENDING) {
g.drawImage(IconCache.getImage("descending.png"), sX - 12, bounds.y - SORTING_INDEX_TEXT_INSET + 2, null);
}
}
}
}
public static JScrollPane getFirstScrollPane(Component aComp) {
Component lParent = aComp;
while (lParent != null && !(lParent instanceof JScrollPane)) {
lParent = lParent.getParent();
}
if (lParent != null && lParent instanceof JScrollPane) {
return (JScrollPane) lParent;
}
return null;
}
public static boolean isValidCellBoundary(Component aTarget) {
JScrollPane scroll = getFirstScrollPane(aTarget);
if (scroll != null && (scroll.getHorizontalScrollBar() == null || !scroll.getHorizontalScrollBar().isVisible())) {
Point rightOnScroll = SwingUtilities.convertPoint(aTarget, new Point(aTarget.getWidth(), 1), scroll);
int scrollRightBoundary = (scroll.getWidth() - (scroll.getInsets() != null ? scroll.getInsets().right : 0));
return (scrollRightBoundary - rightOnScroll.x) > MultiLevelHeader.PICK_MARGIN_SIZE;
}
return true;
}
}