Reimplement Table aggregation API #PL-2292

This commit is contained in:
Yuriy Artamonov 2014-09-10 07:29:10 +00:00
parent c52c1f40d6
commit 57a367d944
30 changed files with 1037 additions and 184 deletions

View File

@ -60,7 +60,7 @@ def webToolkitLegacyModule = project(':cuba-web6-toolkit')
def webModuleThemes = project(':cuba-web-themes')
def webLegacyModuleThemes = project(':cuba-web6-themes')
def vaadinVersion = '7.2.6.cuba.0'
def vaadinVersion = '7.2.6.cuba.1'
def vaadinLegacyVersion = '6.6.1.161'
def springVersion = '3.2.8.RELEASE'
def springSecurityVersion = '3.2.3.RELEASE'

View File

@ -14,45 +14,50 @@ import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* @author gorodnov
* @version $Id$
*/
public class Aggregations {
private static final Aggregations instance;
private static Aggregations instance = null;
static {
instance = new Aggregations();
instance.register(Datatypes.getNN(BigDecimal.class), new BigDecimalAggregation());
instance.register(Datatypes.getNN(Integer.class), new LongAggregation());
instance.register(Datatypes.getNN(Long.class), new LongAggregation());
instance.register(Datatypes.getNN(Double.class), new DoubleAggregation());
instance.register(Datatypes.getNN(Date.class), new DateAggregation());
instance.register(Datatypes.getNN(Boolean.class), new BasicAggregation<>(Boolean.class));
instance.register(Datatypes.getNN(byte[].class), new BasicAggregation<>(byte[].class));
instance.register(Datatypes.getNN(String.class), new BasicAggregation<>(String.class));
instance.register(Datatypes.getNN(UUID.class), new BasicAggregation<>(UUID.class));
}
public static Aggregations getInstance() {
return instance;
}
private Map<String, Aggregation> aggregationByName;
private Map<Class, Aggregation> aggregationByDatatype;
private Aggregations() {
aggregationByName = new HashMap<String, Aggregation>();
aggregationByDatatype = new HashMap<Class, Aggregation>();
aggregationByName = new HashMap<>();
aggregationByDatatype = new HashMap<>();
}
public static Aggregations getInstance() {
if (instance == null) {
instance = new Aggregations();
instance.register(Datatypes.getNN(BigDecimal.class), new BigDecimalAggregation());
instance.register(Datatypes.getNN(Integer.class), new LongAggregation());
instance.register(Datatypes.getNN(Long.class), new LongAggregation());
instance.register(Datatypes.getNN(Double.class), new DoubleAggregation());
instance.register(Datatypes.getNN(Date.class), new DateAggregation());
instance.register(Datatypes.getNN(Boolean.class), new BasicAggregation<Boolean>(Boolean.class));
instance.register(Datatypes.getNN(byte[].class), new BasicAggregation<byte[]>(byte[].class));
// instance.register(Datatypes.getNN(Enum.class), new BasicAggregation());
instance.register(Datatypes.getNN(String.class), new BasicAggregation<String>(String.class));
instance.register(Datatypes.getNN(UUID.class), new BasicAggregation<UUID>(UUID.class));
}
return instance;
}
public <T> void register(Datatype datatype, Aggregation<T> aggregation) {
protected <T> void register(Datatype datatype, Aggregation<T> aggregation) {
aggregationByDatatype.put(datatype.getJavaClass(), aggregation);
aggregationByName.put(datatype.getName(), aggregation);
}
public <T> Aggregation<T> get(String name) {
return aggregationByName.get(name);
@SuppressWarnings("unchecked")
public static <T> Aggregation<T> get(String name) {
return getInstance().aggregationByName.get(name);
}
public <T> Aggregation<T> get(Class<T> clazz) {
return aggregationByDatatype.get(clazz);
@SuppressWarnings("unchecked")
public static <T> Aggregation<T> get(Class<T> clazz) {
return getInstance().aggregationByDatatype.get(clazz);
}
}
}

View File

@ -8,6 +8,10 @@ import com.haulmont.cuba.gui.aggregation.Aggregation;
import java.util.Collection;
/**
* @author gorodnov
* @version $Id$
*/
public class BasicAggregation<T> implements Aggregation<T> {
private Class<T> clazz;
@ -16,47 +20,58 @@ public class BasicAggregation<T> implements Aggregation<T> {
this.clazz = clazz;
}
@Override
public T sum(Collection<T> items) {
throw new UnsupportedOperationException();
}
@Override
public boolean allowSum() {
return false;
}
@Override
public T avg(Collection<T> items) {
throw new UnsupportedOperationException();
}
@Override
public boolean allowAvg() {
return false;
}
@Override
public T min(Collection<T> items) {
throw new UnsupportedOperationException();
}
@Override
public boolean allowMin() {
return false;
}
@Override
public T max(Collection<T> items) {
throw new UnsupportedOperationException();
}
@Override
public boolean allowMax() {
return false;
}
@Override
public int count(Collection<T> items) {
return items.size();
}
@Override
public boolean allowCount() {
return true;
}
@Override
public Class<T> getJavaClass() {
return clazz;
}
}
}

View File

@ -8,6 +8,10 @@ import com.haulmont.cuba.gui.aggregation.NumberAggregationHelper;
import java.util.Collection;
/**
* @author gorodnov
* @version $Id$
*/
public abstract class BasicNumberAggregation<T extends Number> extends BasicAggregation <T> {
protected BasicNumberAggregation(Class<T> clazz) {
@ -79,4 +83,4 @@ public abstract class BasicNumberAggregation<T extends Number> extends BasicAggr
}
protected abstract T convert(Double result);
}
}

View File

@ -6,13 +6,18 @@ package com.haulmont.cuba.gui.aggregation.impl;
import java.math.BigDecimal;
/**
* @author gorodnov
* @version $Id$
*/
public class BigDecimalAggregation extends BasicNumberAggregation<BigDecimal> {
public BigDecimalAggregation() {
super(BigDecimal.class);
}
@Override
public BigDecimal convert(Double result) {
return BigDecimal.valueOf(result);
}
}
}

View File

@ -9,6 +9,10 @@ import com.haulmont.cuba.gui.aggregation.NumberAggregationHelper;
import java.util.Date;
import java.util.Collection;
/**
* @author gorodnov
* @version $Id$
*/
public class DateAggregation extends BasicAggregation<Date> {
public DateAggregation() {
super(Date.class);

View File

@ -4,12 +4,17 @@
*/
package com.haulmont.cuba.gui.aggregation.impl;
/**
* @author gorodnov
* @version $Id$
*/
public class DoubleAggregation extends BasicNumberAggregation<Double> {
public DoubleAggregation() {
super(Double.class);
}
@Override
public Double convert(Double result) {
return result;
}
}
}

View File

@ -4,12 +4,17 @@
*/
package com.haulmont.cuba.gui.aggregation.impl;
/**
* @author gorodnov
* @version $Id$
*/
public class LongAggregation extends BasicNumberAggregation<Long> {
public LongAggregation() {
super(Long.class);
}
@Override
protected Long convert(Double result) {
return result.longValue();
}
}
}

View File

@ -4,13 +4,13 @@
*/
package com.haulmont.cuba.gui.components;
import com.haulmont.chile.core.model.MetaPropertyPath;
/**
* @param <P>
*
* @author gorodnov
* @version $Id$
*/
public class AggregationInfo<P> {
public class AggregationInfo {
public enum Type {
SUM,
@ -20,15 +20,15 @@ public class AggregationInfo<P> {
MAX
}
private P propertyPath;
private MetaPropertyPath propertyPath;
private Type type;
private Formatter formatter;
public P getPropertyPath() {
public MetaPropertyPath getPropertyPath() {
return propertyPath;
}
public void setPropertyPath(P propertyPath) {
public void setPropertyPath(MetaPropertyPath propertyPath) {
this.propertyPath = propertyPath;
}

View File

@ -13,9 +13,12 @@ import com.haulmont.cuba.gui.components.AggregationInfo;
import java.util.*;
/**
* @author grachev
* @version $Id$
*/
public abstract class AggregatableDelegate<K> {
public Map<Object, String> aggregate(AggregationInfo<MetaPropertyPath>[] aggregationInfos, Collection<K> itemIds) {
public Map<Object, String> aggregate(AggregationInfo[] aggregationInfos, Collection<K> itemIds) {
if (aggregationInfos == null || aggregationInfos.length == 0) {
throw new NullPointerException("Aggregation must be executed at least by one field");
}
@ -23,12 +26,11 @@ public abstract class AggregatableDelegate<K> {
return doAggregation(itemIds, aggregationInfos);
}
protected Map<Object, String> doAggregation(Collection<K> itemIds, AggregationInfo<MetaPropertyPath>[] aggregationInfos) {
final Map<Object, String> aggregationResults = new HashMap<Object, String>();
for (final AggregationInfo<MetaPropertyPath> aggregationInfo : aggregationInfos) {
final Aggregation aggregation = Aggregations.getInstance()
.get(aggregationInfo.getPropertyPath().getRangeJavaClass());
protected Map<Object, String> doAggregation(Collection<K> itemIds, AggregationInfo[] aggregationInfos) {
final Map<Object, String> aggregationResults = new HashMap<>();
for (AggregationInfo aggregationInfo : aggregationInfos) {
Class rangeJavaClass = aggregationInfo.getPropertyPath().getRangeJavaClass();
final Aggregation aggregation = Aggregations.get(rangeJavaClass);
final Object value = doPropertyAggregation(aggregationInfo, aggregation, itemIds);
@ -50,11 +52,9 @@ public abstract class AggregatableDelegate<K> {
return aggregationResults;
}
protected Object doPropertyAggregation(
AggregationInfo<MetaPropertyPath> aggregationInfo,
Aggregation aggregation,
Collection<K> itemIds
) {
@SuppressWarnings("unchecked")
protected Object doPropertyAggregation(AggregationInfo aggregationInfo, Aggregation aggregation,
Collection<K> itemIds) {
List items = valuesByProperty(aggregationInfo.getPropertyPath(), itemIds);
switch (aggregationInfo.getType()) {
case COUNT:
@ -74,7 +74,7 @@ public abstract class AggregatableDelegate<K> {
}
protected List valuesByProperty(MetaPropertyPath propertyPath, Collection<K> itemIds) {
final List<Object> values = new ArrayList<Object>(itemIds.size());
final List<Object> values = new ArrayList<>(itemIds.size());
for (final K itemId : itemIds) {
final Object value = getItemValue(propertyPath, itemId);
if (value != null) {
@ -87,4 +87,4 @@ public abstract class AggregatableDelegate<K> {
public abstract Object getItem(K itemId);
public abstract Object getItemValue(MetaPropertyPath property, K itemId);
}
}

View File

@ -311,6 +311,7 @@
<xs:attribute name="columnControlVisible" type="xs:boolean"/>
<xs:attribute name="aggregatable" type="xs:boolean"/>
<xs:attribute name="showTotalAggregation" type="xs:boolean"/>
<xs:attribute name="presentations" type="xs:boolean"/>
<xs:attribute name="allowPopupMenu" type="xs:boolean"/>
<xs:attribute name="allowMultiStringCells" type="xs:boolean"/>
@ -834,15 +835,14 @@
<xs:complexType name="tableColumnComponent">
<xs:sequence>
<xs:element name="formatter" minOccurs="0" maxOccurs="1" type="formatterType"/>
<!--<xs:element name="calculatable" minOccurs="0" maxOccurs="1"/>-->
<!--<xs:element name="aggregation" minOccurs="0" maxOccurs="1">-->
<!--<xs:complexType>-->
<!--<xs:sequence>-->
<!--<xs:element name="formatter" minOccurs="0" maxOccurs="1" type="formatterType"/>-->
<!--</xs:sequence>-->
<!--<xs:attribute name="type" type="aggregation" use="required"/>-->
<!--</xs:complexType>-->
<!--</xs:element>-->
<xs:element name="aggregation" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element name="formatter" minOccurs="0" maxOccurs="1" type="formatterType"/>
</xs:sequence>
<xs:attribute name="type" type="aggregation" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attributeGroup ref="requiresId"/>
@ -853,6 +853,7 @@
<xs:attribute name="clickAction" type="xs:string"/>
<xs:attribute name="collapsed" type="xs:boolean"/>
<xs:attribute name="maxTextLength" type="xs:integer"/>
<xs:attribute name="calculatable" type="xs:boolean"/>
<!-- Additional attributes, use only for editable table -->
<xs:attributeGroup ref="hasOptions"/>

View File

@ -297,7 +297,7 @@ public abstract class AbstractTableLoader<T extends Table> extends ComponentLoad
Element aggregationElement = columnElement.element("aggregation");
if (aggregationElement != null) {
final AggregationInfo aggregation = new AggregationInfo();
aggregation.setPropertyPath(column.getId());
aggregation.setPropertyPath((MetaPropertyPath) column.getId());
aggregation.setType(AggregationInfo.Type.valueOf(aggregationElement.attributeValue("type")));
Formatter formatter = loadFormatter(aggregationElement);
aggregation.setFormatter(formatter == null ? column.getFormatter() : formatter);

View File

@ -0,0 +1,31 @@
/*
* Copyright (c) 2008-2014 Haulmont. All rights reserved.
* Use is subject to license terms, see http://www.cuba-platform.com/license for details.
*/
package com.haulmont.cuba.web.toolkit.ui.client.aggregation;
import com.vaadin.client.ui.VScrollTable;
/**
* VScrollTable API wrapper for {@link TableAggregationRow}
*
* @author artamonov
* @version $Id$
*/
public interface AggregatableTable {
VScrollTable.TableHead getHead();
String getStylePrimaryName();
String[] getVisibleColOrder();
String getColKeyByIndex(int index);
int getColWidth(String colKey);
void setColWidth(int colIndex, int w, boolean isDefinedWidth);
boolean isTextSelectionEnabled();
}

View File

@ -0,0 +1,196 @@
/*
* Copyright (c) 2008-2014 Haulmont. All rights reserved.
* Use is subject to license terms, see http://www.cuba-platform.com/license for details.
*/
package com.haulmont.cuba.web.toolkit.ui.client.aggregation;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.Widget;
import com.haulmont.cuba.web.toolkit.ui.client.Tools;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.UIDL;
import com.vaadin.client.ui.VScrollTable;
import java.util.Iterator;
import java.util.LinkedList;
/**
* Special aggregation row for {@link com.haulmont.cuba.web.toolkit.ui.client.table.CubaScrollTableWidget} and
* {@link com.haulmont.cuba.web.toolkit.ui.client.treetable.CubaTreeTableWidget}
*
* @author artamonov
* @version $Id$
*/
public class TableAggregationRow extends Panel {
protected boolean initialized = false;
protected char[] aligns;
protected Element tr;
protected AggregatableTable tableWidget;
public TableAggregationRow(AggregatableTable tableWidget) {
this.tableWidget = tableWidget;
setElement(Document.get().createDivElement());
getElement().setClassName(tableWidget.getStylePrimaryName() + "-arow");
getElement().getStyle().setOverflow(Style.Overflow.HIDDEN);
}
@Override
public Iterator<Widget> iterator() {
return new LinkedList<Widget>().iterator();
}
@Override
public boolean remove(Widget child) {
return false;
}
public void updateFromUIDL(UIDL uidl) {
if (getElement().hasChildNodes()) {
getElement().removeAllChildren();
}
aligns = tableWidget.getHead().getColumnAlignments();
if (uidl.getChildCount() > 0) {
final Element table = DOM.createTable();
table.setAttribute("cellpadding", "0");
table.setAttribute("cellspacing", "0");
final Element tBody = DOM.createTBody();
tr = DOM.createTR();
tr.setClassName(tableWidget.getStylePrimaryName() + "-arow-row");
addCellsFromUIDL(uidl);
tBody.appendChild(tr);
table.appendChild(tBody);
getElement().appendChild(table);
}
initialized = getElement().hasChildNodes();
}
protected void addCellsFromUIDL(UIDL uidl) {
int colIndex = 0;
final Iterator cells = uidl.getChildIterator();
while (cells.hasNext() && colIndex < tableWidget.getVisibleColOrder().length) {
String columnId = tableWidget.getVisibleColOrder()[colIndex];
if (addSpecificCell(columnId, colIndex)) {
colIndex++;
continue;
}
final Object cell = cells.next();
String style = "";
if (uidl.hasAttribute("style-" + columnId)) {
style = uidl.getStringAttribute("style-" + columnId);
}
boolean sorted = tableWidget.getHead().getHeaderCell(colIndex).isSorted();
if (cell instanceof String) {
addCell((String) cell, aligns[colIndex], style, sorted);
}
final String colKey = tableWidget.getColKeyByIndex(colIndex);
int colWidth;
if ((colWidth = tableWidget.getColWidth(colKey)) > -1) {
tableWidget.setColWidth(colIndex, colWidth, false);
}
colIndex++;
}
}
// Extension point for GroupTable divider column
protected boolean addSpecificCell(String columnId, int colIndex) {
return false;
}
protected void addCell(String text, char align, String style, boolean sorted) {
final TableCellElement td = DOM.createTD().cast();
final Element container = DOM.createDiv();
container.setClassName(tableWidget.getStylePrimaryName() + "-cell-wrapper");
td.setClassName(tableWidget.getStylePrimaryName() + "-cell-content");
if (style != null && !style.equals("")) {
td.addClassName(tableWidget.getStylePrimaryName() + "-cell-content-" + style);
}
if (sorted) {
td.addClassName(tableWidget.getStylePrimaryName() + "-cell-content-sorted");
}
container.setInnerText(text);
setAlign(align, container);
td.appendChild(container);
tr.appendChild(td);
Tools.textSelectionEnable(td, tableWidget.isTextSelectionEnabled());
}
protected void setAlign(char align, final Element container) {
// CAUTION: copied from VScrollTableRow
switch (align) {
case VScrollTable.ALIGN_CENTER:
container.getStyle().setProperty("textAlign", "center");
break;
case VScrollTable.ALIGN_LEFT:
container.getStyle().setProperty("textAlign", "left");
break;
case VScrollTable.ALIGN_RIGHT:
default:
container.getStyle().setProperty("textAlign", "right");
break;
}
}
public void setCellWidth(int cellIx, int width) {
// CAUTION: copied from VScrollTableRow with small changes
final Element cell = DOM.getChild(tr, cellIx);
Style wrapperStyle = cell.getFirstChildElement().getStyle();
int wrapperWidth = width;
if (BrowserInfo.get().isWebkit()
|| BrowserInfo.get().isOpera10()) {
/*
* Some versions of Webkit and Opera ignore the width
* definition of zero width table cells. Instead, use 1px
* and compensate with a negative margin.
*/
if (width == 0) {
wrapperWidth = 1;
wrapperStyle.setMarginRight(-1, Style.Unit.PX);
} else {
wrapperStyle.clearMarginRight();
}
}
wrapperStyle.setPropertyPx("width", wrapperWidth);
cell.getStyle().setPropertyPx("width", width);
}
public boolean isInitialized() {
return initialized;
}
public void setHorizontalScrollPosition(int scrollLeft) {
getElement().setPropertyInt("scrollLeft", scrollLeft);
}
}

View File

@ -11,13 +11,16 @@ import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.haulmont.cuba.web.toolkit.ui.client.Tools;
import com.haulmont.cuba.web.toolkit.ui.client.aggregation.TableAggregationRow;
import com.haulmont.cuba.web.toolkit.ui.client.table.CubaScrollTableWidget;
import com.vaadin.client.BrowserInfo;
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.UIDL;
import com.vaadin.client.Util;
import com.vaadin.shared.ui.table.TableConstants;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
@ -245,6 +248,21 @@ public class CubaGroupTableWidget extends CubaScrollTableWidget {
return new GroupTableFooter();
}
@Override
protected TableAggregationRow createAggregationRow() {
return new TableAggregationRow(getAggregatableTable()) {
@Override
protected boolean addSpecificCell(String columnId, int colIndex) {
if (GROUP_DIVIDER_COLUMN_KEY.equals(columnId)) {
addCell("", aligns[colIndex], "", false);
return true;
}
return super.addSpecificCell(columnId, colIndex);
}
};
}
protected class GroupTableHead extends CubaScrollTableHead {
public GroupTableHead() {
availableCells.put(GROUP_DIVIDER_COLUMN_KEY, new GroupDividerHeaderCell());
@ -300,7 +318,7 @@ public class CubaGroupTableWidget extends CubaScrollTableWidget {
}
protected class CubaGroupTableRow extends CubaScrollTableRow {
private TableCellElement groupDividerCell;
protected TableCellElement groupDividerCell;
public CubaGroupTableRow(UIDL uidl, char[] aligns) {
super(uidl, aligns);
@ -337,6 +355,9 @@ public class CubaGroupTableWidget extends CubaScrollTableWidget {
private String groupKey;
private boolean expanded;
private Integer colSpan;
private Boolean hasCells;
public CubaGroupTableGroupRow(UIDL uidl, char[] aligns) {
super(uidl, aligns);
}
@ -355,7 +376,7 @@ public class CubaGroupTableWidget extends CubaScrollTableWidget {
protected void setWidthForSpannedCell() {
int spanWidth = 0;
for (int ix = groupColIndex; ix < tHead.getVisibleCellCount(); ix++) {
for (int ix = groupColIndex; ix < colSpan; ix++) {
spanWidth += tHead.getHeaderCell(ix).getOffsetWidth();
}
Util.setWidthExcludingPaddingAndBorder((Element) getElement().getChild(groupColIndex),
@ -371,7 +392,7 @@ public class CubaGroupTableWidget extends CubaScrollTableWidget {
if (currentColIndex < visibleColOrder.length) {
String colKey = uidl.getStringAttribute("colKey");
while (currentColIndex < visibleColOrder.length && !visibleColOrder[currentColIndex].equals(colKey)) {
//draw empty cells
//draw empty cells
Element td = DOM.createTD();
final TableCellElement tdCell = td.cast();
@ -392,6 +413,51 @@ public class CubaGroupTableWidget extends CubaScrollTableWidget {
addGroupCell(uidl.getStringAttribute("groupCaption"));
if (uidl.getChildCount() > 0) {
Iterator cells = uidl.getChildIterator();
while (colIndex < visibleColOrder.length) {
String columnId = visibleColOrder[colIndex];
if (GROUP_DIVIDER_COLUMN_KEY.equals(columnId)) { //paint cell for columns group divider
addDividerCell(aligns[colIndex]);
} else if (cells.hasNext()) {
final Object cell = cells.next();
String style = "";
if (uidl.hasAttribute("style-" + columnId)) {
style = uidl.getStringAttribute("style-" + columnId);
}
String description = null;
if (uidl.hasAttribute("descr-" + columnId)) {
description = uidl.getStringAttribute("descr-"
+ columnId);
}
boolean sorted = tHead.getHeaderCell(colIndex).isSorted();
if (cell instanceof String) {
addCell(uidl, cell.toString(), aligns[colIndex], style,
isRenderHtmlInCells(), sorted, description);
} else {
final ComponentConnector cellContent = client
.getPaintable((UIDL) cell);
addCell(uidl, cellContent.getWidget(), aligns[colIndex],
style, sorted, description);
}
}
colIndex++;
}
colSpan = 0;
hasCells = true;
} else {
TableCellElement td = getElement().getLastChild().cast();
colSpan = visibleColOrder.length - groupColIndex;
td.setColSpan(colSpan);
hasCells = false;
}
Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {
@Override
public void execute() {
@ -402,7 +468,7 @@ public class CubaGroupTableWidget extends CubaScrollTableWidget {
@Override
protected void setCellWidth(int cellIx, int width) {
if (groupColIndex > cellIx) {
if (hasCells || groupColIndex > cellIx) {
super.setCellWidth(cellIx, width);
} else {
setWidthForSpannedCell();
@ -413,7 +479,6 @@ public class CubaGroupTableWidget extends CubaScrollTableWidget {
// String only content is optimized by not using Label widget
Element tdElement = DOM.createTD();
final TableCellElement td = tdElement.cast();
td.setColSpan(visibleColOrder.length - groupColIndex);
initCellWithText(text, ALIGN_LEFT, "", false, true, null, td);
// Enchance DOM for table cell

View File

@ -122,4 +122,12 @@ public class CubaScrollTableConnector extends TableConnector {
}
}
}
@Override
protected void updateAdditionalRowData(UIDL uidl) {
UIDL arow = uidl.getChildByTagName("arow");
if (arow != null) {
getWidget().updateAggregationRow(arow);
}
}
}

View File

@ -6,17 +6,19 @@
package com.haulmont.cuba.web.toolkit.ui.client.table;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.event.dom.client.*;
import com.google.gwt.event.logical.shared.CloseEvent;
import com.google.gwt.event.logical.shared.CloseHandler;
import com.google.gwt.user.client.DOM;
import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.*;
import com.haulmont.cuba.web.toolkit.ui.client.Tools;
import com.haulmont.cuba.web.toolkit.ui.client.aggregation.AggregatableTable;
import com.haulmont.cuba.web.toolkit.ui.client.aggregation.TableAggregationRow;
import com.haulmont.cuba.web.toolkit.ui.client.logging.ClientLogger;
import com.haulmont.cuba.web.toolkit.ui.client.logging.ClientLoggerFactory;
import com.vaadin.client.Focusable;
@ -47,6 +49,8 @@ public class CubaScrollTableWidget extends VScrollTable implements ShortcutActio
protected boolean allowMultiStringCells = false;
protected TableAggregationRow aggregationRow;
protected CubaScrollTableWidget() {
// handle shortcuts
DOM.sinkEvents(getElement(), Event.ONKEYDOWN);
@ -150,6 +154,23 @@ public class CubaScrollTableWidget extends VScrollTable implements ShortcutActio
return (int) Math.round(totalRows * scrollBody.getRowHeight(true));
}
@Override
protected void setColWidth(int colIndex, int w, boolean isDefinedWidth) {
super.setColWidth(colIndex, w, isDefinedWidth);
if (aggregationRow != null && aggregationRow.isInitialized()) {
aggregationRow.setCellWidth(colIndex, w);
}
}
@Override
public int getAdditionalRowsHeight() {
if (aggregationRow != null) {
return aggregationRow.getOffsetHeight();
}
return 0;
}
@Override
protected TableHead createTableHead() {
return new CubaScrollTableHead();
@ -172,6 +193,71 @@ public class CubaScrollTableWidget extends VScrollTable implements ShortcutActio
}
}
protected void updateAggregationRow(UIDL uidl) {
if (aggregationRow == null) {
aggregationRow = createAggregationRow();
insert(aggregationRow, getWidgetIndex(scrollBodyPanel));
}
aggregationRow.updateFromUIDL(uidl);
aggregationRow.setHorizontalScrollPosition(scrollLeft);
}
protected TableAggregationRow createAggregationRow() {
return new TableAggregationRow(getAggregatableTable());
}
protected AggregatableTable getAggregatableTable() {
return new AggregatableTable() {
@Override
public TableHead getHead() {
return tHead;
}
@Override
public String getStylePrimaryName() {
return CubaScrollTableWidget.this.getStylePrimaryName();
}
@Override
public String[] getVisibleColOrder() {
return visibleColOrder;
}
@Override
public String getColKeyByIndex(int index) {
return CubaScrollTableWidget.this.getColKeyByIndex(index);
}
@Override
public int getColWidth(String colKey) {
return CubaScrollTableWidget.this.getColWidth(colKey);
}
@Override
public void setColWidth(int colIndex, int w, boolean isDefinedWidth) {
CubaScrollTableWidget.this.setColWidth(colIndex, w, isDefinedWidth);
}
@Override
public boolean isTextSelectionEnabled() {
return textSelectionEnabled;
}
};
}
@Override
public void onScroll(ScrollEvent event) {
if (isLazyScrollerActive()) {
return;
}
super.onScroll(event);
if (aggregationRow != null) {
aggregationRow.setHorizontalScrollPosition(scrollLeft);
}
}
protected class CubaScrollTableHead extends TableHead {
protected final SimplePanel presentationsEditIcon = GWT.create(SimplePanel.class);

View File

@ -125,4 +125,12 @@ public class CubaTreeTableConnector extends TreeTableConnector {
}
}
}
@Override
protected void updateAdditionalRowData(UIDL uidl) {
UIDL arow = uidl.getChildByTagName("arow");
if (arow != null) {
getWidget().updateAggregationRow(arow);
}
}
}

View File

@ -17,6 +17,8 @@ import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.*;
import com.haulmont.cuba.web.toolkit.ui.client.Tools;
import com.haulmont.cuba.web.toolkit.ui.client.aggregation.AggregatableTable;
import com.haulmont.cuba.web.toolkit.ui.client.aggregation.TableAggregationRow;
import com.haulmont.cuba.web.toolkit.ui.client.logging.ClientLogger;
import com.haulmont.cuba.web.toolkit.ui.client.logging.ClientLoggerFactory;
import com.vaadin.client.UIDL;
@ -45,6 +47,8 @@ public class CubaTreeTableWidget extends VTreeTable implements ShortcutActionHan
protected ClientLogger logger = ClientLoggerFactory.getLogger("CubaTreeTableWidget");
protected boolean allowMultiStringCells = false;
protected TableAggregationRow aggregationRow;
public CubaTreeTableWidget() {
hideColumnControlAfterClick = false;
}
@ -147,6 +151,23 @@ public class CubaTreeTableWidget extends VTreeTable implements ShortcutActionHan
return currentRow == focusedRow && (!focusedRow.isSelected());
}
@Override
protected void setColWidth(int colIndex, int w, boolean isDefinedWidth) {
super.setColWidth(colIndex, w, isDefinedWidth);
if (aggregationRow != null && aggregationRow.isInitialized()) {
aggregationRow.setCellWidth(colIndex, w);
}
}
@Override
public int getAdditionalRowsHeight() {
if (aggregationRow != null) {
return aggregationRow.getOffsetHeight();
}
return 0;
}
@Override
protected TableHead createTableHead() {
return new CubaTreeTableTableHead();
@ -168,6 +189,67 @@ public class CubaTreeTableWidget extends VTreeTable implements ShortcutActionHan
Tools.textSelectionEnable(scrollBody.getElement(), textSelectionEnabled);
}
protected void updateAggregationRow(UIDL uidl) {
if (aggregationRow == null) {
aggregationRow = createAggregationRow();
insert(aggregationRow, getWidgetIndex(scrollBodyPanel));
}
aggregationRow.updateFromUIDL(uidl);
aggregationRow.setHorizontalScrollPosition(scrollLeft);
}
protected TableAggregationRow createAggregationRow() {
return new TableAggregationRow(new AggregatableTable() {
@Override
public TableHead getHead() {
return tHead;
}
@Override
public String getStylePrimaryName() {
return CubaTreeTableWidget.this.getStylePrimaryName();
}
@Override
public String[] getVisibleColOrder() {
return visibleColOrder;
}
@Override
public String getColKeyByIndex(int index) {
return CubaTreeTableWidget.this.getColKeyByIndex(index);
}
@Override
public int getColWidth(String colKey) {
return CubaTreeTableWidget.this.getColWidth(colKey);
}
@Override
public void setColWidth(int colIndex, int w, boolean isDefinedWidth) {
CubaTreeTableWidget.this.setColWidth(colIndex, w, isDefinedWidth);
}
@Override
public boolean isTextSelectionEnabled() {
return textSelectionEnabled;
}
});
}
@Override
public void onScroll(ScrollEvent event) {
if (isLazyScrollerActive()) {
return;
}
super.onScroll(event);
if (aggregationRow != null) {
aggregationRow.setHorizontalScrollPosition(scrollLeft);
}
}
protected class CubaTreeTableTableHead extends TableHead {
protected final SimplePanel presentationsEditIcon = GWT.create(SimplePanel.class);

View File

@ -5,6 +5,8 @@
package com.haulmont.cuba.web.gui.components;
import com.haulmont.bali.util.Dom4j;
import com.haulmont.chile.core.datatypes.Datatype;
import com.haulmont.chile.core.datatypes.Datatypes;
import com.haulmont.chile.core.model.Instance;
import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.chile.core.model.MetaProperty;
@ -17,6 +19,7 @@ import com.haulmont.cuba.gui.WindowManager;
import com.haulmont.cuba.gui.components.*;
import com.haulmont.cuba.gui.components.CheckBox;
import com.haulmont.cuba.gui.components.Field;
import com.haulmont.cuba.gui.components.Formatter;
import com.haulmont.cuba.gui.components.Table;
import com.haulmont.cuba.gui.components.Window;
import com.haulmont.cuba.gui.data.*;
@ -99,7 +102,7 @@ public abstract class WebAbstractTable<T extends com.vaadin.ui.Table & CubaEnhan
protected RowsCount rowsCount;
protected Map<Table.Column, Object> aggregationCells = null;
protected Map<Table.Column, String> aggregationCells = null;
protected boolean usePresentations;
@ -111,10 +114,6 @@ public abstract class WebAbstractTable<T extends com.vaadin.ui.Table & CubaEnhan
// Map column id to Printable representation
protected Map<String, Printable> printables = new HashMap<>();
// disabled for #PL-2035
// Disable listener that points component value to follow the ds item.
// protected boolean disableItemListener = false;
protected static final int MAX_TEXT_LENGTH_GAP = 10;
protected Security security = AppBeans.get(Security.class);
@ -156,8 +155,9 @@ public abstract class WebAbstractTable<T extends com.vaadin.ui.Table & CubaEnhan
columns.remove(column.getId());
columnsOrder.remove(column);
// todo artamonov remove after fix #VAADIN-12980
component.refreshRowCache();
if (!(component.getContainerDataSource() instanceof com.vaadin.data.Container.ItemSetChangeNotifier)) {
component.refreshRowCache();
}
column.setOwner(null);
}
@ -398,28 +398,22 @@ public abstract class WebAbstractTable<T extends com.vaadin.ui.Table & CubaEnhan
@Override
public boolean isAggregatable() {
return false;
// vaadin7
// return component.isAggregatable();
return component.isAggregatable();
}
@Override
public void setAggregatable(boolean aggregatable) {
// vaadin7
// component.setAggregatable(aggregatable);
component.setAggregatable(aggregatable);
}
@Override
public void setShowTotalAggregation(boolean showAggregation) {
// vaadin7
// component.setShowTotalAggregation(showAggregation);
component.setShowTotalAggregation(showAggregation);
}
@Override
public boolean isShowTotalAggregation() {
return false;
// vaadin7
// return component.isShowTotalAggregation();
return component.isShowTotalAggregation();
}
@Override
@ -462,8 +456,6 @@ public abstract class WebAbstractTable<T extends com.vaadin.ui.Table & CubaEnhan
if (datasource == null) return;
final Set<Entity> selected = getSelected();
// disabled for #PL-2035
// disableItemListener = true;
if (selected.isEmpty()) {
datasource.setItem(null);
} else {
@ -472,8 +464,6 @@ public abstract class WebAbstractTable<T extends com.vaadin.ui.Table & CubaEnhan
datasource.setItem(null);
datasource.setItem(selected.iterator().next());
}
// disabled for #PL-2035
// disableItemListener = false;
}
});
@ -718,11 +708,10 @@ public abstract class WebAbstractTable<T extends com.vaadin.ui.Table & CubaEnhan
component.setColumnCollapsed(column.getId(), true);
}
// vaadin7
// if (column.getAggregation() != null && isAggregatable()) {
// component.addContainerPropertyAggregation(column.getId(),
// WebComponentsHelper.convertAggregationType(column.getAggregation().getType()));
// }
if (column.getAggregation() != null && isAggregatable()) {
component.addContainerPropertyAggregation(column.getId(),
WebComponentsHelper.convertAggregationType(column.getAggregation().getType()));
}
}
}
@ -739,14 +728,14 @@ public abstract class WebAbstractTable<T extends com.vaadin.ui.Table & CubaEnhan
}
}
// vaadin7
// if (aggregationCells != null) {
// getDatasource().addListener(createAggregationDatasourceListener());
// }
if (aggregationCells != null) {
getDatasource().addListener(createAggregationDatasourceListener());
}
setVisibleColumns(getPropertyColumns());
if (AppBeans.get(UserSessionSource.class).getUserSession().isSpecificPermitted(ShowInfoAction.ACTION_PERMISSION)) {
Security security = AppBeans.get(Security.NAME);
if (security.isSpecificPermitted(ShowInfoAction.ACTION_PERMISSION)) {
ShowInfoAction action = (ShowInfoAction) getAction(ShowInfoAction.ACTION_ID);
if (action == null) {
action = new ShowInfoAction();
@ -755,12 +744,15 @@ public abstract class WebAbstractTable<T extends com.vaadin.ui.Table & CubaEnhan
action.setDatasource(datasource);
}
if (rowsCount != null)
if (rowsCount != null) {
rowsCount.setDatasource(datasource);
}
datasource.addListener(new CollectionDsActionsNotifier(this) {
@Override
public void collectionChanged(CollectionDatasource ds, Operation operation, List<Entity> items) {
super.collectionChanged(ds, operation, items);
// #PL-2035, reload selection from ds
Set<Object> selectedItemIds = getSelectedItemIds();
if (selectedItemIds == null) {
@ -786,18 +778,6 @@ public abstract class WebAbstractTable<T extends com.vaadin.ui.Table & CubaEnhan
}
});
// disabled for #PL-2035
// noinspection unchecked
// datasource.addListener(new CollectionDsActionsNotifier(this) {
// @Override
// public void itemChanged(Datasource ds, Entity prevItem, Entity item) {
// super.itemChanged(ds, prevItem, item);
// if (!disableItemListener && !getSelected().contains(item)) {
// setSelected(item);
// }
// }
// });
for (Action action : getActions()) {
action.refreshState();
}
@ -1339,18 +1319,45 @@ public abstract class WebAbstractTable<T extends com.vaadin.ui.Table & CubaEnhan
return results;
}
protected Map<Object, Object> __handleAggregationResults(AggregationContainer.Context context, Map<Object, Object> results) {
protected Map<Object, Object> __handleAggregationResults(AggregationContainer.Context context,
Map<Object, Object> results) {
for (final Map.Entry<Object, Object> entry : results.entrySet()) {
final Table.Column column = columns.get(entry.getKey());
com.vaadin.ui.Label cell;
if ((cell = (com.vaadin.ui.Label) aggregationCells.get(column)) != null) {
WebComponentsHelper.setLabelText(cell, entry.getValue(), column.getFormatter());
entry.setValue(cell);
if (aggregationCells.get(column) != null) {
Object value = entry.getValue();
String cellText = getFormattedValue(column, value);
entry.setValue(cellText);
}
}
return results;
}
protected String getFormattedValue(Column column, Object value) {
String cellText;
if (value == null) {
cellText = "";
} else {
if (value instanceof String) {
cellText = (String) value;
} else {
Formatter formatter = column.getFormatter();
if (formatter != null) {
cellText = formatter.format(value);
} else {
Datatype datatype = Datatypes.get(value.getClass());
if (datatype != null) {
UserSessionSource sessionSource = AppBeans.get(UserSessionSource.NAME);
cellText = datatype.format(value, sessionSource.getLocale());
} else {
cellText = value.toString();
}
}
}
}
return cellText;
}
protected class TablePropertyWrapper extends PropertyWrapper {
private ValueChangeListener calcListener;
@ -1622,14 +1629,7 @@ public abstract class WebAbstractTable<T extends com.vaadin.ui.Table & CubaEnhan
if (aggregationCells == null) {
aggregationCells = new HashMap<>();
}
aggregationCells.put(column, createAggregationCell());
}
protected com.vaadin.ui.Label createAggregationCell() {
com.vaadin.ui.Label label = new com.vaadin.ui.Label();
label.setWidth("-1px");
label.setParent(component);
return label;
aggregationCells.put(column, "");
}
protected CollectionDatasourceListener createAggregationDatasourceListener() {
@ -1640,9 +1640,8 @@ public abstract class WebAbstractTable<T extends com.vaadin.ui.Table & CubaEnhan
@Override
public void valueChanged(Entity source, String property, Object prevValue, Object value) {
// vaadin7
// final CollectionDatasource ds = WebAbstractTable.this.getDatasource();
// component.aggregate(new AggregationContainer.Context(ds.getItemIds()));
final CollectionDatasource ds = WebAbstractTable.this.getDatasource();
component.aggregate(new AggregationContainer.Context(ds.getItemIds()));
}
}

View File

@ -114,30 +114,29 @@ public class WebGroupTable extends WebAbstractTable<CubaGroupTable> implements G
@Override
protected Map<Object, Object> __handleAggregationResults(AggregationContainer.Context context, Map<Object, Object> results) {
// vaadin7
// if (context instanceof com.haulmont.cuba.web.toolkit.ui.GroupTable.GroupAggregationContext) {
//
// com.haulmont.cuba.web.toolkit.ui.GroupTable.GroupAggregationContext groupContext =
// (com.haulmont.cuba.web.toolkit.ui.GroupTable.GroupAggregationContext) context;
//
// for (final Map.Entry<Object, Object> entry : results.entrySet()) {
// final Table.Column column = columns.get(entry.getKey());
// GroupAggregationCells cells;
// if ((cells = groupAggregationCells.get(column)) != null) {
// com.vaadin.ui.Label cell = cells.getCell(groupContext.getGroupId());
// if (cell != null) {
// WebComponentsHelper.setLabelText(cell, entry.getValue(), column.getFormatter());
// entry.setValue(cell);
// }
// }
// }
//
// return results;
//
// } else {
// return super.__handleAggregationResults(context, results);
// }
return Collections.emptyMap();
if (context instanceof CubaGroupTable.GroupAggregationContext) {
CubaGroupTable.GroupAggregationContext groupContext = (CubaGroupTable.GroupAggregationContext) context;
for (final Map.Entry<Object, Object> entry : results.entrySet()) {
final Table.Column column = columns.get(entry.getKey());
GroupAggregationCells cells;
if ((cells = groupAggregationCells.get(column)) != null) {
String value = cells.getValue(groupContext.getGroupId());
String cellText = getFormattedValue(column, value);
entry.setValue(cellText);
String groupValue = cells.getValue(groupContext.getGroupId());
if (groupValue != null) {
String groupCellText = getFormattedValue(column, groupValue);
entry.setValue(groupCellText);
}
}
}
return results;
} else {
return super.__handleAggregationResults(context, results);
}
}
@Override
@ -155,6 +154,7 @@ public class WebGroupTable extends WebAbstractTable<CubaGroupTable> implements G
component.expand(groupId);
}
@SuppressWarnings("unchecked")
@Override
public void expandPath(Entity item) {
if (component.hasGroups()) {
@ -214,8 +214,7 @@ public class WebGroupTable extends WebAbstractTable<CubaGroupTable> implements G
}
protected class GroupTableDsWrapper extends SortableCollectionDsWrapper
implements GroupTableContainer,
AggregationContainer {
implements GroupTableContainer, AggregationContainer {
private boolean groupDatasource;
private List<Object> aggregationProperties = null;
@ -324,7 +323,7 @@ public class WebGroupTable extends WebAbstractTable<CubaGroupTable> implements G
groupCells = new GroupAggregationCells();
cells.put(column, groupCells);
}
groupCells.addCell(groupId, createAggregationCell());
groupCells.addCell(groupId, "");
}
}
@ -724,13 +723,13 @@ public class WebGroupTable extends WebAbstractTable<CubaGroupTable> implements G
}
protected class GroupAggregationCells {
private Map<Object, com.vaadin.ui.Label> cells = new HashMap<>();
private Map<Object, String> cells = new HashMap<>();
public void addCell(Object groupId, com.vaadin.ui.Label cell) {
cells.put(groupId, cell);
public void addCell(Object groupId, String value) {
cells.put(groupId, value);
}
public com.vaadin.ui.Label getCell(Object groupId) {
public String getValue(Object groupId) {
return cells.get(groupId);
}
}
@ -748,11 +747,7 @@ public class WebGroupTable extends WebAbstractTable<CubaGroupTable> implements G
}
protected void recalcAggregation(GroupInfo groupInfo) {
// vaadin7
// component.aggregate(new com.haulmont.cuba.web.toolkit.ui.GroupTable.GroupAggregationContext(
// component,
// groupInfo
// ));
component.aggregate(new CubaGroupTable.GroupAggregationContext(component, groupInfo));
}
}
}

View File

@ -160,11 +160,13 @@ public class WebTreeTable extends WebAbstractTable<CubaTreeTable> implements Tre
};
}
@SuppressWarnings("unchecked")
@Override
public boolean isCaption(Object itemId) {
return treeTableDatasource && ((TreeTableDatasource) datasource).isCaption(itemId);
}
@SuppressWarnings("unchecked")
@Override
public String getCaption(Object itemId) {
if (treeTableDatasource) {
@ -212,11 +214,13 @@ public class WebTreeTable extends WebAbstractTable<CubaTreeTable> implements Tre
return properties;
}
@SuppressWarnings("unchecked")
@Override
public Object nextItemId(Object itemId) {
return ((CollectionDatasource.Sortable) datasource).nextItemId(itemId);
}
@SuppressWarnings("unchecked")
@Override
public Object prevItemId(Object itemId) {
return ((CollectionDatasource.Sortable) datasource).prevItemId(itemId);
@ -232,11 +236,13 @@ public class WebTreeTable extends WebAbstractTable<CubaTreeTable> implements Tre
return ((CollectionDatasource.Sortable) datasource).lastItemId();
}
@SuppressWarnings("unchecked")
@Override
public boolean isFirstId(Object itemId) {
return ((CollectionDatasource.Sortable) datasource).isFirstId(itemId);
}
@SuppressWarnings("unchecked")
@Override
public boolean isLastId(Object itemId) {
return ((CollectionDatasource.Sortable) datasource).isLastId(itemId);
@ -268,7 +274,7 @@ public class WebTreeTable extends WebAbstractTable<CubaTreeTable> implements Tre
@Override
public void addContainerPropertyAggregation(Object propertyId, Type type) {
if (aggregationProperties == null) {
aggregationProperties = new LinkedList<Object>();
aggregationProperties = new LinkedList<>();
} else if (aggregationProperties.contains(propertyId)) {
throw new IllegalStateException("Such aggregation property is already exists");
}

View File

@ -17,4 +17,4 @@ public interface TreeTableContainer extends TableContainer, Container.Hierarchic
boolean setCaption(Object itemId, String caption);
int getLevel(Object itemId);
}
}

View File

@ -6,6 +6,7 @@
package com.haulmont.cuba.web.toolkit.ui;
import com.haulmont.cuba.web.gui.components.presentations.TablePresentations;
import com.haulmont.cuba.web.toolkit.data.AggregationContainer;
import com.vaadin.ui.Layout;
import com.vaadin.ui.Table;
@ -15,7 +16,7 @@ import com.vaadin.ui.Table;
* @author artamonov
* @version $Id$
*/
public interface CubaEnhancedTable {
public interface CubaEnhancedTable extends AggregationContainer {
void setContextMenuPopup(Layout contextMenu);
void hideContextMenuPopup();
@ -50,4 +51,10 @@ public interface CubaEnhancedTable {
* <b>For internal use only.</b>
*/
void addGeneratedColumnInternal(Object id, Table.ColumnGenerator generatedColumn);
boolean isAggregatable();
void setAggregatable(boolean aggregatable);
boolean isShowTotalAggregation();
void setShowTotalAggregation(boolean showTotalAggregation);
}

View File

@ -8,6 +8,7 @@ package com.haulmont.cuba.web.toolkit.ui;
import com.haulmont.chile.core.model.MetaPropertyPath;
import com.haulmont.cuba.gui.data.GroupInfo;
import com.haulmont.cuba.web.gui.data.PropertyValueStringify;
import com.haulmont.cuba.web.toolkit.data.AggregationContainer;
import com.haulmont.cuba.web.toolkit.data.GroupTableContainer;
import com.haulmont.cuba.web.toolkit.data.util.GroupTableContainerWrapper;
import com.vaadin.data.Container;
@ -190,6 +191,9 @@ public class CubaGroupTable extends CubaTable implements GroupTableContainer {
protected void paintRowAttributes(PaintTarget target, Object itemId) throws PaintException {
super.paintRowAttributes(target, itemId);
boolean hasAggregation = items instanceof AggregationContainer && isAggregatable()
&& !((AggregationContainer) items).getAggregationPropertyIds().isEmpty();
boolean hasGroups = hasGroups();
if (hasGroups) {
if (isGroup(itemId)) {
@ -201,7 +205,58 @@ public class CubaGroupTable extends CubaTable implements GroupTableContainer {
final Object propertyValue = getGroupPropertyValue(itemId);
target.addAttribute("groupCaption", formatGroupPropertyValue(itemId, propertyValue));
// todo aggregation
if (hasAggregation) {
paintGroupAggregation(target, itemId,
((AggregationContainer) items).aggregate(new GroupAggregationContext(this, itemId)));
}
}
}
}
@Override
protected Collection<?> getAggregationItemIds() {
if (hasGroups()) {
List itemIds = new LinkedList();
for (final Object groupId : rootGroups()) {
itemIds.addAll(getGroupItemIds(groupId));
}
return itemIds;
} else {
return items.getItemIds();
}
}
protected void paintGroupAggregation(PaintTarget target, Object groupId, Map<Object, Object> aggregations)
throws PaintException {
boolean paintGroupProperty = false;
final Collection groupProperties = getGroupProperties();
final Object groupProperty = getGroupProperty(groupId);
for (final Object columnId : visibleColumns) {
if (columnId == null || isColumnCollapsed(columnId)) {
continue;
}
if (groupProperties.contains(columnId) && !paintGroupProperty) {
if (columnId.equals(groupProperty)) {
paintGroupProperty = true;
}
continue;
}
if (getCellStyleGenerator() != null) {
String cellStyle = getCellStyleGenerator().getStyle(this, null, columnId);
if (cellStyle != null && !cellStyle.equals("")) {
target.addAttribute("style-" + columnIdMap.key(columnId), cellStyle + "-ag");
}
}
String value = (String) aggregations.get(columnId);
if (value != null) {
target.addText(value);
} else {
target.addText("");
}
}
}
@ -404,4 +459,17 @@ public class CubaGroupTable extends CubaTable implements GroupTableContainer {
public interface GroupPropertyValueFormatter {
String format(Object groupId, @Nullable Object value);
}
public static class GroupAggregationContext extends Context {
private Object groupId;
public GroupAggregationContext(GroupTableContainer datasource, Object groupId) {
super(datasource.getGroupItemIds(groupId));
this.groupId = groupId;
}
public Object getGroupId() {
return groupId;
}
}
}

View File

@ -9,6 +9,7 @@ import com.google.common.collect.Iterables;
import com.haulmont.cuba.web.gui.components.presentations.TablePresentations;
import com.haulmont.cuba.web.gui.data.PropertyValueStringify;
import com.haulmont.cuba.web.toolkit.ShortcutActionManager;
import com.haulmont.cuba.web.toolkit.data.AggregationContainer;
import com.haulmont.cuba.web.toolkit.data.TableContainer;
import com.haulmont.cuba.web.toolkit.ui.client.table.CubaTableClientRpc;
import com.haulmont.cuba.web.toolkit.ui.client.table.CubaTableState;
@ -42,6 +43,10 @@ public class CubaTable extends com.vaadin.ui.Table implements TableContainer, Cu
protected boolean autowirePropertyDsForFields = false;
protected boolean showTotalAggregation = true;
protected boolean aggregatable = false;
@Override
protected CubaTableState getState() {
return (CubaTableState) super.getState();
@ -330,4 +335,129 @@ public class CubaTable extends com.vaadin.ui.Table implements TableContainer, Cu
public void refreshCellStyles() {
super.refreshRenderedCells();
}
@Override
public boolean removeContainerProperty(Object propertyId) throws UnsupportedOperationException {
if (editableColumns != null) {
editableColumns.remove(propertyId);
}
if (isAggregatable() && items instanceof AggregationContainer) {
removeContainerPropertyAggregation(propertyId);
}
boolean removed = super.removeContainerProperty(propertyId);
if (removed) {
resetPageBuffer();
}
return removed;
}
@Override
public boolean isAggregatable() {
return this.aggregatable;
}
@Override
public void setAggregatable(boolean aggregatable) {
if (this.aggregatable != aggregatable) {
this.aggregatable = aggregatable;
markAsDirty();
}
}
@Override
public boolean isShowTotalAggregation() {
return showTotalAggregation;
}
@Override
public void setShowTotalAggregation(boolean showTotalAggregation) {
if (this.showTotalAggregation != showTotalAggregation) {
this.showTotalAggregation = showTotalAggregation;
markAsDirty();
}
}
@Override
public Collection getAggregationPropertyIds() {
if (items instanceof AggregationContainer) {
return ((AggregationContainer) items).getAggregationPropertyIds();
}
throw new IllegalStateException("Table container is not AggregationContainer: " + items.getClass());
}
@Override
public Type getContainerPropertyAggregation(Object propertyId) {
if (items instanceof AggregationContainer) {
return ((AggregationContainer) items).getContainerPropertyAggregation(propertyId);
}
throw new IllegalStateException("Table container is not AggregationContainer: " + items.getClass());
}
@Override
public void addContainerPropertyAggregation(Object propertyId, Type type) {
if (items instanceof AggregationContainer) {
((AggregationContainer) items).addContainerPropertyAggregation(propertyId, type);
} else {
throw new IllegalStateException("Table container is not AggregationContainer: " + items.getClass());
}
}
@Override
public void removeContainerPropertyAggregation(Object propertyId) {
if (items instanceof AggregationContainer) {
((AggregationContainer) items).removeContainerPropertyAggregation(propertyId);
} else {
throw new IllegalStateException("Table container is not AggregationContainer: " + items.getClass());
}
}
@Override
public Map<Object, Object> aggregate(Context context) {
if (items instanceof AggregationContainer && isAggregatable()) {
return ((AggregationContainer) items).aggregate(context);
}
throw new IllegalStateException("Table container is not AggregationContainer: " + items.getClass());
}
@Override
protected void paintAdditionalData(PaintTarget target) throws PaintException {
if (reqFirstRowToPaint == -1) {
boolean hasAggregation = items instanceof AggregationContainer && isAggregatable()
&& !((AggregationContainer) items).getAggregationPropertyIds().isEmpty();
if (hasAggregation && isShowTotalAggregation()) {
Context context = new Context(getAggregationItemIds());
paintAggregationRow(target, ((AggregationContainer) items).aggregate(context));
}
}
}
protected Collection<?> getAggregationItemIds() {
return items.getItemIds();
}
protected void paintAggregationRow(PaintTarget target, Map<Object, Object> aggregations) throws PaintException {
target.startTag("arow");
for (final Object columnId : visibleColumns) {
if (columnId == null || isColumnCollapsed(columnId)) {
continue;
}
if (getCellStyleGenerator() != null) {
String cellStyle = getCellStyleGenerator().getStyle(this, null, columnId);
if (cellStyle != null && !cellStyle.equals("")) {
target.addAttribute("style-"
+ columnIdMap.key(columnId), cellStyle + "-ag");
}
}
String value = (String) aggregations.get(columnId);
target.addText(value);
}
target.endTag("arow");
}
}

View File

@ -9,6 +9,7 @@ import com.google.common.collect.Iterables;
import com.haulmont.cuba.web.gui.components.presentations.TablePresentations;
import com.haulmont.cuba.web.gui.data.PropertyValueStringify;
import com.haulmont.cuba.web.toolkit.ShortcutActionManager;
import com.haulmont.cuba.web.toolkit.data.AggregationContainer;
import com.haulmont.cuba.web.toolkit.data.TableContainer;
import com.haulmont.cuba.web.toolkit.data.TreeTableContainer;
import com.haulmont.cuba.web.toolkit.data.util.TreeTableContainerWrapper;
@ -46,6 +47,10 @@ public class CubaTreeTable extends com.vaadin.ui.TreeTable implements TreeTableC
protected boolean autowirePropertyDsForFields = false;
protected boolean showTotalAggregation = true;
protected boolean aggregatable = false;
@Override
protected CubaTreeTableState getState() {
return (CubaTreeTableState) super.getState();
@ -394,4 +399,120 @@ public class CubaTreeTable extends com.vaadin.ui.TreeTable implements TreeTableC
public void refreshCellStyles() {
super.refreshRenderedCells();
}
@Override
public boolean removeContainerProperty(Object propertyId) throws UnsupportedOperationException {
if (editableColumns != null) {
editableColumns.remove(propertyId);
}
if (isAggregatable() && items instanceof AggregationContainer) {
removeContainerPropertyAggregation(propertyId);
}
boolean removed = super.removeContainerProperty(propertyId);
if (removed) {
resetPageBuffer();
}
return removed;
}
@Override
public boolean isAggregatable() {
return this.aggregatable;
}
@Override
public void setAggregatable(boolean aggregatable) {
if (this.aggregatable != aggregatable) {
this.aggregatable = aggregatable;
markAsDirty();
}
}
@Override
public boolean isShowTotalAggregation() {
return showTotalAggregation;
}
@Override
public void setShowTotalAggregation(boolean showTotalAggregation) {
if (this.showTotalAggregation != showTotalAggregation) {
this.showTotalAggregation = showTotalAggregation;
markAsDirty();
}
}
@Override
public Collection getAggregationPropertyIds() {
if (items instanceof AggregationContainer) {
return ((AggregationContainer) items).getAggregationPropertyIds();
}
throw new IllegalStateException("Table container is not AggregationContainer: " + items.getClass());
}
@Override
public Type getContainerPropertyAggregation(Object propertyId) {
if (items instanceof AggregationContainer) {
return ((AggregationContainer) items).getContainerPropertyAggregation(propertyId);
}
throw new IllegalStateException("Table container is not AggregationContainer: " + items.getClass());
}
@Override
public void addContainerPropertyAggregation(Object propertyId, Type type) {
if (items instanceof AggregationContainer) {
((AggregationContainer) items).addContainerPropertyAggregation(propertyId, type);
} else {
throw new IllegalStateException("Table container is not AggregationContainer: " + items.getClass());
}
}
@Override
public void removeContainerPropertyAggregation(Object propertyId) {
if (items instanceof AggregationContainer) {
((AggregationContainer) items).removeContainerPropertyAggregation(propertyId);
} else {
throw new IllegalStateException("Table container is not AggregationContainer: " + items.getClass());
}
}
@Override
public Map<Object, Object> aggregate(Context context) {
if (items instanceof AggregationContainer && isAggregatable()) {
return ((AggregationContainer) items).aggregate(context);
}
throw new IllegalStateException("Table container is not AggregationContainer: " + items.getClass());
}
@Override
protected void paintAdditionalData(PaintTarget target) throws PaintException {
if (reqFirstRowToPaint == -1 && items instanceof AggregationContainer && isAggregatable()
&& !((AggregationContainer) items).getAggregationPropertyIds().isEmpty() && isShowTotalAggregation()) {
paintAggregationRow(target, ((AggregationContainer) items).aggregate(new Context(items.getItemIds())));
}
}
protected void paintAggregationRow(PaintTarget target, Map<Object, Object> aggregations) throws PaintException {
target.startTag("arow");
for (final Object columnId : visibleColumns) {
if (columnId == null || isColumnCollapsed(columnId)) {
continue;
}
if (getCellStyleGenerator() != null) {
String cellStyle = getCellStyleGenerator().getStyle(this, null, columnId);
if (cellStyle != null && !cellStyle.equals("")) {
target.addAttribute("style-"
+ columnIdMap.key(columnId), cellStyle + "-ag");
}
}
String value = (String) aggregations.get(columnId);
target.addText(value);
}
target.endTag("arow");
}
}

View File

@ -9,6 +9,26 @@
.#{$primaryStyleName} {
text-align: left;
.v-table-arow {
@include box-defaults;
border-top: 1px solid $theme_fieldBorderColor;
border-left: 1px solid $theme_fieldBorderColor;
border-right: 1px solid $theme_fieldBorderColor;
}
.v-table-arow-row {
@include box-defaults;
height: 24px;
background: #ccc;
border-right: 1px solid $theme_fieldBorderColor;
}
.v-table-arow-row > .v-table-cell-content {
border-bottom: 0;
}
.v-table-cell-content.boolean-cell-true .v-table-cell-wrapper {
color: transparent;
font-size: 0px;

View File

@ -69,6 +69,7 @@ $theme_tableRowOddBackgroundColor: #f6f8fa;
$theme_tableRowSelectionBackgroundColor: #c3e1ff;
$theme_tableRowHoverBackgroundColor: #f5f4b9;
$theme_tableCellSeparatorColor: #edf3f9;
$theme_tableAggregationRowColor: #8398af;
$theme_treeSelectionColor: #5daee8;
$theme_treeCaptionColor: #1e3146;

View File

@ -440,26 +440,12 @@
border-top: 1px solid #71a4d5;
border-left: 1px solid #71a4d5;
border-right: 1px solid #71a4d5;
background: #ccc;
}
.v-table-arow-row {
background: #ccc;
}
/* IE6 hack */
/** html .v-table-scrollposition {*/
/*background: transparent;*/
/*
AlphaImageLoader uses src attribute relative to host page, not CSS
We need multiple different filters because we cannot be sure how host page is served compared to theme resources
TODO: This actually does not work as expected, since only the last filter is applied.
*/
/*filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="../../ITMILL/themes/saneco/table/img/scroll-position-bg.png", sizingMethod="scale");*/
/*filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="../ITMILL/themes/saneco/table/img/scroll-position-bg.png", sizingMethod="scale");*/
/*filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="ITMILL/themes/saneco/table/img/scroll-position-bg.png", sizingMethod="scale");*/
/*filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="/ITMILL/themes/saneco/table/img/scroll-position-bg.png", sizingMethod="scale");*/
/*}*/
.v-pager {
height: 20px;
padding-right: 5px;