/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.eas.grid.builders;
import com.eas.grid.HasColumn;
import com.eas.grid.ThemedGridResources;
import com.eas.grid.columns.header.HasSortList;
import com.eas.grid.columns.header.HeaderAnalyzer;
import com.eas.grid.columns.header.HeaderNode;
import com.google.gwt.cell.client.Cell;
import com.google.gwt.dom.builder.shared.StylesBuilder;
import com.google.gwt.dom.builder.shared.TableCellBuilder;
import com.google.gwt.dom.builder.shared.TableRowBuilder;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.FontStyle;
import com.google.gwt.dom.client.Style.FontWeight;
import com.google.gwt.user.cellview.client.AbstractCellTable;
import com.google.gwt.user.cellview.client.AbstractHeaderOrFooterBuilder;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.ColumnSortList;
import com.google.gwt.user.cellview.client.Header;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
*
* @author mg
* @param <T>
*/
public class ThemedHeaderOrFooterBuilder<T> extends AbstractHeaderOrFooterBuilder<T> {
protected int rowsHeight = 18;
protected List<HeaderNode<T>> headerNodes;
protected HasSortList sortListHolder;
public ThemedHeaderOrFooterBuilder(AbstractCellTable<T> table, boolean isFooter) {
super(table, isFooter);
}
public ThemedHeaderOrFooterBuilder(AbstractCellTable<T> table, boolean isFooter, HasSortList aSortListHolder) {
super(table, isFooter);
sortListHolder = aSortListHolder;
}
public ThemedHeaderOrFooterBuilder(AbstractCellTable<T> table, boolean isFooter, List<HeaderNode<T>> aHeaderNodes) {
super(table, isFooter);
headerNodes = aHeaderNodes;
}
public ThemedHeaderOrFooterBuilder(AbstractCellTable<T> table, boolean isFooter, List<HeaderNode<T>> aHeaderNodes, int aRowsHeight) {
super(table, isFooter);
rowsHeight = aRowsHeight;
headerNodes = aHeaderNodes;
}
public HasSortList getSortListHolder() {
return sortListHolder;
}
public void setSortListHolder(HasSortList sortListHolder) {
this.sortListHolder = sortListHolder;
}
public int getRowsHeight() {
return rowsHeight;
}
public void setRowsHeight(int aValue) {
rowsHeight = aValue;
}
public List<HeaderNode<T>> getHeaderNodes() {
return headerNodes;
}
public void setHeaderNodes(List<HeaderNode<T>> aNodes) {
if (headerNodes != aNodes) {
headerNodes = aNodes;
HeaderAnalyzer.analyze(headerNodes);
}
}
@Override
public boolean isColumn(Element elem) {
return super.isColumn(elem);
}
@Override
public Column<T, ?> getColumn(Element elem) {
return super.getColumn(elem);
}
@Override
protected boolean buildHeaderOrFooterImpl() {
AbstractCellTable<T> table = getTable();
boolean isFooter = isBuildingFooter();
int columnCount = table.getColumnCount();
if (columnCount > 0) {
// Early exit if there aren't any headers or footers in the columns
// to render.
boolean hasHeadersOrFooters = false;
for (int i = 0; i < columnCount; i++) {
if (getHeader(i) != null) {
hasHeadersOrFooters = true;
break;
}
}
if (hasHeadersOrFooters) {
List<HeaderNode<T>> headersForest;
if (headerNodes == null) {
headersForest = new ArrayList<>();
for (int curColumn = 0; curColumn < columnCount; curColumn++) {
Header<?> headerOrFooter = getHeader(curColumn);
HeaderNode<T> hn = new HeaderNode<T>();
hn.setHeader((Header<String>) headerOrFooter);
headersForest.add(hn);
}
} else {
headersForest = headerNodes;
}
// Get information about the sorted columns.
ColumnSortList sortList;
if (sortListHolder != null) {
sortList = sortListHolder.getSortList();
} else {
sortList = table.getColumnSortList();
}
Map<Column<T, ?>, ColumnSortList.ColumnSortInfo> sortedColumns = new HashMap<>();
if (sortList != null) {
for (int i = 0; i < sortList.size(); i++) {
ColumnSortList.ColumnSortInfo sInfo = sortList.get(i);
sortedColumns.put((Column<T, ?>) sInfo.getColumn(), sInfo);
}
}
buildNodes(headersForest, sortedColumns);
return true;
} else {
// No headers to render;
return false;
}
} else {
// Nothing to render;
return false;
}
}
protected void buildNodes(List<HeaderNode<T>> aHeaders, Map<Column<T, ?>, ColumnSortList.ColumnSortInfo> sortedColumns) {
// AbstractCellTable<T> table = getTable();
List<HeaderNode<T>> children = new ArrayList<>();
boolean isFooter = isBuildingFooter();
// Get the common style names.
String className = isBuildingFooter() ? ThemedGridResources.instance.cellTableStyle().cellTableFooter() : ThemedGridResources.instance.cellTableStyle().cellTableHeader();
String sortableStyle = ThemedGridResources.instance.cellTableStyle().cellTableSortableHeader();
String sortedAscStyle = ThemedGridResources.instance.cellTableStyle().cellTableSortedHeaderAscending();
String sortedDescStyle = ThemedGridResources.instance.cellTableStyle().cellTableSortedHeaderDescending();
TableRowBuilder tr = startRow();
// Loop through all column header nodes.
for (int i = 0; i < aHeaders.size(); i++) {
HeaderNode<T> headerNode = aHeaders.get(i);
children.addAll(headerNode.getChildren());
Header<?> headerOrFooter = headerNode.getHeader();
Column<T, ?> column = null;
if (headerOrFooter instanceof HasColumn<?>)
column = ((HasColumn<T>) headerOrFooter).getColumn();
boolean isSortable = !isFooter && column != null && column.isSortable();
ColumnSortList.ColumnSortInfo sortedInfo = sortedColumns.get(column);
boolean isSorted = sortedInfo != null;
StringBuilder classesBuilder = new StringBuilder(className);
boolean isSortAscending = isSortable && sortedInfo != null ? sortedInfo.isAscending() : false;
if (isSortable) {
if (classesBuilder.length() > 0) {
classesBuilder.append(" ");
}
classesBuilder.append(sortableStyle);
if (isSorted) {
if (classesBuilder.length() > 0) {
classesBuilder.append(" ");
}
classesBuilder.append(isSortAscending ? sortedAscStyle : sortedDescStyle);
}
}
// Render the header or footer.
TableCellBuilder th = tr.startTH();
if (headerNode.getDepthRemainder() > 0)
th.rowSpan(headerNode.getDepthRemainder() + 1);
if (headerNode.getLeavesCount() > 1)
th.colSpan(headerNode.getLeavesCount());
th.className(classesBuilder.toString());
StylesBuilder thStyles = th.style();
if (headerNode.getBackground() != null) {
thStyles.trustedBackgroundColor(headerNode.getBackground().toStyled());
}
if (headerNode.getForeground() != null) {
thStyles.trustedColor(headerNode.getForeground().toStyled());
}
if (headerNode.getFont() != null) {
thStyles.trustedProperty("font-family", headerNode.getFont().getFamily());
thStyles.fontSize(headerNode.getFont().getSize(), Style.Unit.PX);
thStyles.fontStyle(headerNode.getFont().isItalic() ? FontStyle.ITALIC : FontStyle.NORMAL);
thStyles.fontWeight(headerNode.getFont().isBold() ? FontWeight.BOLD : FontWeight.NORMAL);
}
if (headerOrFooter != null) {
appendExtraStyles(headerOrFooter, classesBuilder);
if (column != null) {
enableColumnHandlers(th, column);
}
// Build the header.
Cell.Context context = new Cell.Context(0, i, headerOrFooter.getKey());
// Add div element with aria button role
if (isSortable) {
// TODO: Figure out aria-label and translation
// of label text
th.attribute("role", "button");
th.tabIndex(-1);
}
renderSortableHeader(th, context, headerOrFooter, isSorted, isSortAscending);
}
th.endTH();
}
// End the row.
tr.endTR();
if (!children.isEmpty()) {
buildNodes(children, sortedColumns);
}
}
/**
* Append the extra style names for the header.
*
* @param header
* the header that may contain extra styles, it can be null
* @param classesBuilder
* the string builder for the TD classes
*/
private <H> void appendExtraStyles(Header<H> header, StringBuilder classesBuilder) {
if (header == null) {
return;
}
String headerStyleNames = header.getHeaderStyleNames();
if (headerStyleNames != null) {
classesBuilder.append(" ");
classesBuilder.append(headerStyleNames);
}
}
}