package de.muntjak.tinylookandfeel.table;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.plaf.UIResource;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;
import de.muntjak.tinylookandfeel.Theme;
import de.muntjak.tinylookandfeel.TinyTableHeaderUI;
import de.muntjak.tinylookandfeel.controlpanel.ColorRoutines;
/**
* This TableCellRenderer is installed on the table header
* in TinyTableHeaderUI.installDefaults() so we can change the
* border on rollover and show an arrow icon for sorted columns.
* @author Hans Bickel
*
*/
public class TinyTableHeaderRenderer extends DefaultTableCellRenderer implements UIResource {
private static final Icon arrowNo = new Arrow(true, -1);
// arrows array will be lazily filled
private static final Icon[][] arrows = new Icon[2][4];
private int[] horizontalAlignments;
public TinyTableHeaderRenderer() {
setHorizontalAlignment(CENTER);
setHorizontalTextPosition(LEFT);
}
/**
* Sets horizontal alignments of renderers where an index
* in the argument array corresponds to a column index.
* @param alignments array of the following constants
* defined in <code>SwingConstants</code>:
* <code>LEFT</code>,
* <code>CENTER</code>,
* <code>RIGHT</code>,
* <code>LEADING</code> (the default for text-only labels) or
* <code>TRAILING</code>.
*/
public void setHorizontalAlignments(int[] alignments) {
horizontalAlignments = alignments;
}
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column)
{
LookAndFeel laf = UIManager.getLookAndFeel();
if(laf == null || !"TinyLookAndFeel".equals(laf.getName())) {
if(table != null) {
JTableHeader header = table.getTableHeader();
if(header != null) {
setBackground(header.getBackground());
setForeground(header.getForeground());
setFont(header.getFont());
}
}
setIcon(null);
setText((value == null) ? "" : value.toString());
setBorder(UIManager.getBorder("TableHeader.cellBorder"));
return this;
}
boolean isRolloverColumn = false;
Icon icon = arrowNo;
int sortingDirection = SortableTableData.SORT_ASCENDING;
int priority = -1;
boolean paintArrow = false;
if(table != null) {
JTableHeader header = table.getTableHeader();
if(header != null) {
Object o = header.getClientProperty(TinyTableHeaderUI.ROLLOVER_COLUMN_KEY);
if(o != null) {
int rolloverColumn = ((Integer)o).intValue();
if(rolloverColumn == column) {
isRolloverColumn = true;
}
}
o = header.getClientProperty(TinyTableHeaderUI.SORTED_COLUMN_KEY);
if(o != null) {
int sc[] = (int[])o;
priority = -1;
for(int i = 0; i < sc.length; i++) {
if(sc[i] == column) {
priority = i;
}
}
if(priority > -1) {
paintArrow = true;
o = header.getClientProperty(TinyTableHeaderUI.SORTING_DIRECTION_KEY);
if(o != null) {
int[] sd = (int[])o;
sortingDirection = sd[priority];
}
}
}
if(isRolloverColumn) {
setBackground(Theme.tableHeaderRolloverBackColor[Theme.style].getColor());
}
else {
setBackground(header.getBackground());
}
setForeground(header.getForeground());
setFont(header.getFont());
}
TableModel model = table.getModel();
if(model instanceof SortableTableData) {
if(paintArrow) {
int pri = Math.min(3, priority);
if(sortingDirection == SortableTableData.SORT_ASCENDING) {
if(arrows[0][pri] == null) {
arrows[0][pri] = new Arrow(false, priority);
}
icon = arrows[0][pri];
}
else {
if(arrows[1][pri] == null) {
arrows[1][pri] = new Arrow(true, priority);
}
icon = arrows[1][pri];
}
}
else {
int modelColumn = table.getColumnModel().getColumn(column).getModelIndex();
if(!((SortableTableData)model).isColumnSortable(modelColumn)) {
icon = null;
}
}
}
else {
icon = null;
setToolTipText(null);
}
}
setIcon(icon);
setText((value == null) ? "" : value.toString());
if(isRolloverColumn) {
setBorder(UIManager.getBorder("TableHeader.cellRolloverBorder"));
}
else {
setBorder(UIManager.getBorder("TableHeader.cellBorder"));
}
int modelColumn = table.getColumnModel().getColumn(column).getModelIndex();
if(horizontalAlignments != null && horizontalAlignments.length > modelColumn) {
setHorizontalAlignment(horizontalAlignments[modelColumn]);
}
return this;
}
private static class Arrow implements Icon {
private static final int height = 11;
private boolean descending;
private int priority;
public Arrow(boolean descending, int priority) {
this.descending = descending;
this.priority = Math.min(3, priority);
}
public void paintIcon(Component c, Graphics g, int x, int y) {
if(priority == -1) return; // empty icon
// In a compound sort, make each successive triangle
// smaller than the previous one
int dx = priority;
int dy = (height - 5 + priority) / 2;
g.translate(x + dx, y + dy);
g.setColor(Theme.tableHeaderArrowColor[Theme.style].getColor());
if(descending) {
switch(priority) {
case 0:
g.drawLine(4, 4, 4, 4);
g.drawLine(3, 3, 5, 3);
g.drawLine(2, 2, 6, 2);
g.drawLine(1, 1, 7, 1);
g.drawLine(0, 0, 8, 0);
break;
case 1:
g.drawLine(3, 3, 3, 3);
g.drawLine(2, 2, 4, 2);
g.drawLine(1, 1, 5, 1);
g.drawLine(0, 0, 6, 0);
break;
case 2:
g.drawLine(2, 2, 2, 2);
g.drawLine(1, 1, 3, 1);
g.drawLine(0, 0, 4, 0);
break;
case 3:
default:
g.drawLine(1, 1, 1, 1);
g.drawLine(0, 0, 2, 0);
break;
}
}
else {
switch(priority) {
case 0:
g.drawLine(4, 0, 4, 0);
g.drawLine(3, 1, 5, 1);
g.drawLine(2, 2, 6, 2);
g.drawLine(1, 3, 7, 3);
g.drawLine(0, 4, 8, 4);
break;
case 1:
g.drawLine(3, 0, 3, 0);
g.drawLine(2, 1, 4, 1);
g.drawLine(1, 2, 5, 2);
g.drawLine(0, 3, 6, 3);
break;
case 2:
g.drawLine(2, 0, 2, 0);
g.drawLine(1, 1, 3, 1);
g.drawLine(0, 2, 4, 2);
break;
case 3:
default:
g.drawLine(1, 0, 1, 0);
g.drawLine(0, 1, 2, 1);
break;
}
}
g.translate(-(x + dx), -(y + dy));
}
public int getIconWidth() {
return 9;
}
public int getIconHeight() {
return height;
}
}
}