blob: bb323aec5e1af0720f79e29d5576feb399f8120f [file] [log] [blame]
/*
* Copyright 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.user.cellview.client;
import com.google.gwt.cell.client.Cell.Context;
import com.google.gwt.dom.builder.shared.TableCellBuilder;
import com.google.gwt.dom.builder.shared.TableRowBuilder;
import com.google.gwt.user.cellview.client.AbstractCellTable.Style;
import com.google.gwt.user.cellview.client.ColumnSortList.ColumnSortInfo;
/**
* Default implementation of {@link HeaderBuilder} that renders columns.
*
* @param <T> the data type of the table
*/
public class DefaultHeaderOrFooterBuilder<T> extends AbstractHeaderOrFooterBuilder<T> {
/**
* Create a new DefaultHeaderBuilder for the header of footer section.
*
* @param table the table being built
* @param isFooter true if building the footer, false if the header
*/
public DefaultHeaderOrFooterBuilder(AbstractCellTable<T> table, boolean isFooter) {
super(table, isFooter);
}
@Override
protected boolean buildHeaderOrFooterImpl() {
AbstractCellTable<T> table = getTable();
boolean isFooter = isBuildingFooter();
// Early exit if there aren't any columns to render.
int columnCount = table.getColumnCount();
if (columnCount == 0) {
// Nothing to render;
return false;
}
// Early exit if there aren't any headers in the columns to render.
boolean hasHeader = false;
for (int i = 0; i < columnCount; i++) {
if (getHeader(i) != null) {
hasHeader = true;
break;
}
}
if (hasHeader == false) {
return false;
}
// Get information about the sorted column.
ColumnSortList sortList = table.getColumnSortList();
ColumnSortInfo sortedInfo = (sortList.size() == 0) ? null : sortList.get(0);
Column<?, ?> sortedColumn = (sortedInfo == null) ? null : sortedInfo.getColumn();
boolean isSortAscending = (sortedInfo == null) ? false : sortedInfo.isAscending();
// Get the common style names.
Style style = getTable().getResources().style();
String className = isBuildingFooter() ? style.footer() : style.header();
String sortableStyle = " " + style.sortableHeader();
String sortedStyle =
" " + (isSortAscending ? style.sortedHeaderAscending() : style.sortedHeaderDescending());
// Setup the first column.
Header<?> prevHeader = getHeader(0);
Column<T, ?> column = getTable().getColumn(0);
int prevColspan = 1;
boolean isSortable = false;
boolean isSorted = false;
StringBuilder classesBuilder = new StringBuilder(className);
classesBuilder.append(" " + (isFooter ? style.firstColumnFooter() : style.firstColumnHeader()));
if (!isFooter && column.isSortable()) {
isSortable = true;
isSorted = (column == sortedColumn);
}
// Loop through all column headers.
TableRowBuilder tr = startRow();
int curColumn;
for (curColumn = 1; curColumn < columnCount; curColumn++) {
Header<?> header = getHeader(curColumn);
if (header != prevHeader) {
// The header has changed, so append the previous one.
buildTableHeader(tr, column, prevHeader, isSortable, isSorted, isSortAscending,
classesBuilder, sortableStyle, sortedStyle, prevColspan, curColumn);
// Reset the previous header.
prevHeader = header;
prevColspan = 1;
classesBuilder = new StringBuilder(className);
isSortable = false;
isSorted = false;
} else {
// Increment the colspan if the headers == each other.
prevColspan++;
}
// Update the sorted state.
column = table.getColumn(curColumn);
if (!isFooter && column.isSortable()) {
isSortable = true;
isSorted = (column == sortedColumn);
}
}
// The first and last columns could be the same column.
classesBuilder.append(" ").append(
isFooter ? style.lastColumnFooter() : style.lastColumnHeader());
// Render the last header.
buildTableHeader(tr, column, prevHeader, isSortable, isSorted, isSortAscending,
classesBuilder, sortableStyle, sortedStyle, prevColspan, curColumn);
// End the row.
tr.endTR();
return true;
}
/**
* Build the table header for the column.
*/
private void buildTableHeader(TableRowBuilder tr, Column<T, ?> column, Header<?> header,
boolean isSortable, boolean isSorted, boolean isSortAscending, StringBuilder classesBuilder,
String sortableStyle, String sortedStyle, int prevColspan, int curColumn) {
if (isSortable) {
classesBuilder.append(sortableStyle);
}
if (isSorted) {
classesBuilder.append(sortedStyle);
}
appendExtraStyles(header, classesBuilder);
TableCellBuilder th = tr.startTH().colSpan(prevColspan).className(classesBuilder.toString());
enableColumnHandlers(th, column);
if (header != null) {
// Build the header.
Context context = new Context(0, curColumn - prevColspan, header.getKey());
if (isSortable) {
// TODO: Figure out aria-label and translation of label text
th.attribute("role", "button");
th.tabIndex(-1);
}
renderSortableHeader(th, context, header, isSorted, isSortAscending);
}
th.endTH();
}
/**
* 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);
}
}
}