From 57a367d9445ee8ca4464de539bf4a8782b6fe51c Mon Sep 17 00:00:00 2001 From: Yuriy Artamonov Date: Wed, 10 Sep 2014 07:29:10 +0000 Subject: [PATCH] Reimplement Table aggregation API #PL-2292 --- build.gradle | 2 +- .../cuba/gui/aggregation/Aggregations.java | 57 ++--- .../aggregation/impl/BasicAggregation.java | 17 +- .../impl/BasicNumberAggregation.java | 6 +- .../impl/BigDecimalAggregation.java | 7 +- .../gui/aggregation/impl/DateAggregation.java | 4 + .../aggregation/impl/DoubleAggregation.java | 7 +- .../gui/aggregation/impl/LongAggregation.java | 7 +- .../cuba/gui/components/AggregationInfo.java | 12 +- .../gui/data/impl/AggregatableDelegate.java | 30 +-- .../gui/src/com/haulmont/cuba/gui/window.xsd | 19 +- .../layout/loaders/AbstractTableLoader.java | 2 +- .../client/aggregation/AggregatableTable.java | 31 +++ .../aggregation/TableAggregationRow.java | 196 ++++++++++++++++++ .../grouptable/CubaGroupTableWidget.java | 75 ++++++- .../table/CubaScrollTableConnector.java | 8 + .../client/table/CubaScrollTableWidget.java | 88 +++++++- .../treetable/CubaTreeTableConnector.java | 8 + .../client/treetable/CubaTreeTableWidget.java | 82 ++++++++ .../web/gui/components/WebAbstractTable.java | 119 ++++++----- .../web/gui/components/WebGroupTable.java | 67 +++--- .../cuba/web/gui/components/WebTreeTable.java | 8 +- .../web/toolkit/data/TreeTableContainer.java | 2 +- .../web/toolkit/ui/CubaEnhancedTable.java | 9 +- .../cuba/web/toolkit/ui/CubaGroupTable.java | 70 ++++++- .../cuba/web/toolkit/ui/CubaTable.java | 130 ++++++++++++ .../cuba/web/toolkit/ui/CubaTreeTable.java | 121 +++++++++++ .../themes/havana/components/table/table.scss | 20 ++ .../web/themes/havana/havana-defaults.scss | 1 + .../themes/havana/components/table/table.scss | 16 +- 30 files changed, 1037 insertions(+), 184 deletions(-) create mode 100644 modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/aggregation/AggregatableTable.java create mode 100644 modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/aggregation/TableAggregationRow.java diff --git a/build.gradle b/build.gradle index 1ae126039b..b5be060754 100644 --- a/build.gradle +++ b/build.gradle @@ -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' diff --git a/modules/gui/src/com/haulmont/cuba/gui/aggregation/Aggregations.java b/modules/gui/src/com/haulmont/cuba/gui/aggregation/Aggregations.java index 9a981f34b9..1156aa7fca 100644 --- a/modules/gui/src/com/haulmont/cuba/gui/aggregation/Aggregations.java +++ b/modules/gui/src/com/haulmont/cuba/gui/aggregation/Aggregations.java @@ -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 aggregationByName; private Map aggregationByDatatype; private Aggregations() { - aggregationByName = new HashMap(); - aggregationByDatatype = new HashMap(); + 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.class)); - instance.register(Datatypes.getNN(byte[].class), new BasicAggregation(byte[].class)); -// instance.register(Datatypes.getNN(Enum.class), new BasicAggregation()); - instance.register(Datatypes.getNN(String.class), new BasicAggregation(String.class)); - instance.register(Datatypes.getNN(UUID.class), new BasicAggregation(UUID.class)); - } - return instance; - } - - public void register(Datatype datatype, Aggregation aggregation) { + protected void register(Datatype datatype, Aggregation aggregation) { aggregationByDatatype.put(datatype.getJavaClass(), aggregation); aggregationByName.put(datatype.getName(), aggregation); } - public Aggregation get(String name) { - return aggregationByName.get(name); + @SuppressWarnings("unchecked") + public static Aggregation get(String name) { + return getInstance().aggregationByName.get(name); } - public Aggregation get(Class clazz) { - return aggregationByDatatype.get(clazz); + @SuppressWarnings("unchecked") + public static Aggregation get(Class clazz) { + return getInstance().aggregationByDatatype.get(clazz); } -} +} \ No newline at end of file diff --git a/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/BasicAggregation.java b/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/BasicAggregation.java index 7c8c486c92..4bd33e8bc8 100644 --- a/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/BasicAggregation.java +++ b/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/BasicAggregation.java @@ -8,6 +8,10 @@ import com.haulmont.cuba.gui.aggregation.Aggregation; import java.util.Collection; +/** + * @author gorodnov + * @version $Id$ + */ public class BasicAggregation implements Aggregation { private Class clazz; @@ -16,47 +20,58 @@ public class BasicAggregation implements Aggregation { this.clazz = clazz; } + @Override public T sum(Collection items) { throw new UnsupportedOperationException(); } + @Override public boolean allowSum() { return false; } + @Override public T avg(Collection items) { throw new UnsupportedOperationException(); } + @Override public boolean allowAvg() { return false; } + @Override public T min(Collection items) { throw new UnsupportedOperationException(); } + @Override public boolean allowMin() { return false; } + @Override public T max(Collection items) { throw new UnsupportedOperationException(); } + @Override public boolean allowMax() { return false; } + @Override public int count(Collection items) { return items.size(); } + @Override public boolean allowCount() { return true; } + @Override public Class getJavaClass() { return clazz; } -} +} \ No newline at end of file diff --git a/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/BasicNumberAggregation.java b/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/BasicNumberAggregation.java index 6b33d905d8..8660ad4f2c 100644 --- a/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/BasicNumberAggregation.java +++ b/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/BasicNumberAggregation.java @@ -8,6 +8,10 @@ import com.haulmont.cuba.gui.aggregation.NumberAggregationHelper; import java.util.Collection; +/** + * @author gorodnov + * @version $Id$ + */ public abstract class BasicNumberAggregation extends BasicAggregation { protected BasicNumberAggregation(Class clazz) { @@ -79,4 +83,4 @@ public abstract class BasicNumberAggregation extends BasicAggr } protected abstract T convert(Double result); -} +} \ No newline at end of file diff --git a/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/BigDecimalAggregation.java b/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/BigDecimalAggregation.java index 926fb755a6..d075bb6873 100644 --- a/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/BigDecimalAggregation.java +++ b/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/BigDecimalAggregation.java @@ -6,13 +6,18 @@ package com.haulmont.cuba.gui.aggregation.impl; import java.math.BigDecimal; +/** + * @author gorodnov + * @version $Id$ + */ public class BigDecimalAggregation extends BasicNumberAggregation { public BigDecimalAggregation() { super(BigDecimal.class); } + @Override public BigDecimal convert(Double result) { return BigDecimal.valueOf(result); } -} +} \ No newline at end of file diff --git a/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/DateAggregation.java b/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/DateAggregation.java index 054f286c45..1532facde0 100644 --- a/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/DateAggregation.java +++ b/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/DateAggregation.java @@ -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 { public DateAggregation() { super(Date.class); diff --git a/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/DoubleAggregation.java b/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/DoubleAggregation.java index f9c39cd8f9..a94e7ca21f 100644 --- a/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/DoubleAggregation.java +++ b/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/DoubleAggregation.java @@ -4,12 +4,17 @@ */ package com.haulmont.cuba.gui.aggregation.impl; +/** + * @author gorodnov + * @version $Id$ + */ public class DoubleAggregation extends BasicNumberAggregation { public DoubleAggregation() { super(Double.class); } + @Override public Double convert(Double result) { return result; } -} +} \ No newline at end of file diff --git a/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/LongAggregation.java b/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/LongAggregation.java index e3687225f5..414a2e5a46 100644 --- a/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/LongAggregation.java +++ b/modules/gui/src/com/haulmont/cuba/gui/aggregation/impl/LongAggregation.java @@ -4,12 +4,17 @@ */ package com.haulmont.cuba.gui.aggregation.impl; +/** + * @author gorodnov + * @version $Id$ + */ public class LongAggregation extends BasicNumberAggregation { public LongAggregation() { super(Long.class); } + @Override protected Long convert(Double result) { return result.longValue(); } -} +} \ No newline at end of file diff --git a/modules/gui/src/com/haulmont/cuba/gui/components/AggregationInfo.java b/modules/gui/src/com/haulmont/cuba/gui/components/AggregationInfo.java index 9a94437aac..2ac26d9223 100644 --- a/modules/gui/src/com/haulmont/cuba/gui/components/AggregationInfo.java +++ b/modules/gui/src/com/haulmont/cuba/gui/components/AggregationInfo.java @@ -4,13 +4,13 @@ */ package com.haulmont.cuba.gui.components; +import com.haulmont.chile.core.model.MetaPropertyPath; + /** - * @param

- * * @author gorodnov * @version $Id$ */ -public class AggregationInfo

{ +public class AggregationInfo { public enum Type { SUM, @@ -20,15 +20,15 @@ public class AggregationInfo

{ 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; } diff --git a/modules/gui/src/com/haulmont/cuba/gui/data/impl/AggregatableDelegate.java b/modules/gui/src/com/haulmont/cuba/gui/data/impl/AggregatableDelegate.java index 2c31a412f1..fc173e6754 100644 --- a/modules/gui/src/com/haulmont/cuba/gui/data/impl/AggregatableDelegate.java +++ b/modules/gui/src/com/haulmont/cuba/gui/data/impl/AggregatableDelegate.java @@ -13,9 +13,12 @@ import com.haulmont.cuba.gui.components.AggregationInfo; import java.util.*; +/** + * @author grachev + * @version $Id$ + */ public abstract class AggregatableDelegate { - - public Map aggregate(AggregationInfo[] aggregationInfos, Collection itemIds) { + public Map aggregate(AggregationInfo[] aggregationInfos, Collection 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 { return doAggregation(itemIds, aggregationInfos); } - protected Map doAggregation(Collection itemIds, AggregationInfo[] aggregationInfos) { - final Map aggregationResults = new HashMap(); - for (final AggregationInfo aggregationInfo : aggregationInfos) { - - final Aggregation aggregation = Aggregations.getInstance() - .get(aggregationInfo.getPropertyPath().getRangeJavaClass()); + protected Map doAggregation(Collection itemIds, AggregationInfo[] aggregationInfos) { + final Map 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 { return aggregationResults; } - protected Object doPropertyAggregation( - AggregationInfo aggregationInfo, - Aggregation aggregation, - Collection itemIds - ) { + @SuppressWarnings("unchecked") + protected Object doPropertyAggregation(AggregationInfo aggregationInfo, Aggregation aggregation, + Collection itemIds) { List items = valuesByProperty(aggregationInfo.getPropertyPath(), itemIds); switch (aggregationInfo.getType()) { case COUNT: @@ -74,7 +74,7 @@ public abstract class AggregatableDelegate { } protected List valuesByProperty(MetaPropertyPath propertyPath, Collection itemIds) { - final List values = new ArrayList(itemIds.size()); + final List 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 { public abstract Object getItem(K itemId); public abstract Object getItemValue(MetaPropertyPath property, K itemId); -} +} \ No newline at end of file diff --git a/modules/gui/src/com/haulmont/cuba/gui/window.xsd b/modules/gui/src/com/haulmont/cuba/gui/window.xsd index 874aa3a8da..b9e3a4d562 100644 --- a/modules/gui/src/com/haulmont/cuba/gui/window.xsd +++ b/modules/gui/src/com/haulmont/cuba/gui/window.xsd @@ -311,6 +311,7 @@ + @@ -834,15 +835,14 @@ - - - - - - - - - + + + + + + + + @@ -853,6 +853,7 @@ + diff --git a/modules/gui/src/com/haulmont/cuba/gui/xml/layout/loaders/AbstractTableLoader.java b/modules/gui/src/com/haulmont/cuba/gui/xml/layout/loaders/AbstractTableLoader.java index 14080eaf4a..d4df879a6f 100644 --- a/modules/gui/src/com/haulmont/cuba/gui/xml/layout/loaders/AbstractTableLoader.java +++ b/modules/gui/src/com/haulmont/cuba/gui/xml/layout/loaders/AbstractTableLoader.java @@ -297,7 +297,7 @@ public abstract class AbstractTableLoader 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); diff --git a/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/aggregation/AggregatableTable.java b/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/aggregation/AggregatableTable.java new file mode 100644 index 0000000000..1c1dd38193 --- /dev/null +++ b/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/aggregation/AggregatableTable.java @@ -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(); +} \ No newline at end of file diff --git a/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/aggregation/TableAggregationRow.java b/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/aggregation/TableAggregationRow.java new file mode 100644 index 0000000000..9ecdcfb778 --- /dev/null +++ b/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/aggregation/TableAggregationRow.java @@ -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 iterator() { + return new LinkedList().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); + } +} \ No newline at end of file diff --git a/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/grouptable/CubaGroupTableWidget.java b/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/grouptable/CubaGroupTableWidget.java index 8089feb76a..bf85a82e16 100644 --- a/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/grouptable/CubaGroupTableWidget.java +++ b/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/grouptable/CubaGroupTableWidget.java @@ -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 diff --git a/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/table/CubaScrollTableConnector.java b/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/table/CubaScrollTableConnector.java index 2da6cf5008..a529642314 100644 --- a/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/table/CubaScrollTableConnector.java +++ b/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/table/CubaScrollTableConnector.java @@ -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); + } + } } \ No newline at end of file diff --git a/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/table/CubaScrollTableWidget.java b/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/table/CubaScrollTableWidget.java index 39cf405fba..a7586e8d02 100644 --- a/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/table/CubaScrollTableWidget.java +++ b/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/table/CubaScrollTableWidget.java @@ -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); diff --git a/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/treetable/CubaTreeTableConnector.java b/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/treetable/CubaTreeTableConnector.java index 135ffa2cae..2ae96dcf2b 100644 --- a/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/treetable/CubaTreeTableConnector.java +++ b/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/treetable/CubaTreeTableConnector.java @@ -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); + } + } } \ No newline at end of file diff --git a/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/treetable/CubaTreeTableWidget.java b/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/treetable/CubaTreeTableWidget.java index bf9bdaf626..54b5f7cb52 100644 --- a/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/treetable/CubaTreeTableWidget.java +++ b/modules/web-toolkit/src/com/haulmont/cuba/web/toolkit/ui/client/treetable/CubaTreeTableWidget.java @@ -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); diff --git a/modules/web/src/com/haulmont/cuba/web/gui/components/WebAbstractTable.java b/modules/web/src/com/haulmont/cuba/web/gui/components/WebAbstractTable.java index 400d42fe04..6677c66e04 100644 --- a/modules/web/src/com/haulmont/cuba/web/gui/components/WebAbstractTable.java +++ b/modules/web/src/com/haulmont/cuba/web/gui/components/WebAbstractTable.java @@ -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 aggregationCells = null; + protected Map aggregationCells = null; protected boolean usePresentations; @@ -111,10 +114,6 @@ public abstract class WebAbstractTable 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 selected = getSelected(); -// disabled for #PL-2035 -// disableItemListener = true; if (selected.isEmpty()) { datasource.setItem(null); } else { @@ -472,8 +464,6 @@ public abstract class WebAbstractTable items) { + super.collectionChanged(ds, operation, items); + // #PL-2035, reload selection from ds Set selectedItemIds = getSelectedItemIds(); if (selectedItemIds == null) { @@ -786,18 +778,6 @@ public abstract class WebAbstractTable __handleAggregationResults(AggregationContainer.Context context, Map results) { + protected Map __handleAggregationResults(AggregationContainer.Context context, + Map results) { for (final Map.Entry 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(); } - 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 implements G @Override protected Map __handleAggregationResults(AggregationContainer.Context context, Map 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 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 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 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 implements G } protected class GroupTableDsWrapper extends SortableCollectionDsWrapper - implements GroupTableContainer, - AggregationContainer { + implements GroupTableContainer, AggregationContainer { private boolean groupDatasource; private List aggregationProperties = null; @@ -324,7 +323,7 @@ public class WebGroupTable extends WebAbstractTable 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 implements G } protected class GroupAggregationCells { - private Map cells = new HashMap<>(); + private Map 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 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)); } } } \ No newline at end of file diff --git a/modules/web/src/com/haulmont/cuba/web/gui/components/WebTreeTable.java b/modules/web/src/com/haulmont/cuba/web/gui/components/WebTreeTable.java index 826a86d1f3..1c0c2e3731 100644 --- a/modules/web/src/com/haulmont/cuba/web/gui/components/WebTreeTable.java +++ b/modules/web/src/com/haulmont/cuba/web/gui/components/WebTreeTable.java @@ -160,11 +160,13 @@ public class WebTreeTable extends WebAbstractTable 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 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 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 implements Tre @Override public void addContainerPropertyAggregation(Object propertyId, Type type) { if (aggregationProperties == null) { - aggregationProperties = new LinkedList(); + aggregationProperties = new LinkedList<>(); } else if (aggregationProperties.contains(propertyId)) { throw new IllegalStateException("Such aggregation property is already exists"); } diff --git a/modules/web/src/com/haulmont/cuba/web/toolkit/data/TreeTableContainer.java b/modules/web/src/com/haulmont/cuba/web/toolkit/data/TreeTableContainer.java index 697bc12986..91a97d03fa 100644 --- a/modules/web/src/com/haulmont/cuba/web/toolkit/data/TreeTableContainer.java +++ b/modules/web/src/com/haulmont/cuba/web/toolkit/data/TreeTableContainer.java @@ -17,4 +17,4 @@ public interface TreeTableContainer extends TableContainer, Container.Hierarchic boolean setCaption(Object itemId, String caption); int getLevel(Object itemId); -} +} \ No newline at end of file diff --git a/modules/web/src/com/haulmont/cuba/web/toolkit/ui/CubaEnhancedTable.java b/modules/web/src/com/haulmont/cuba/web/toolkit/ui/CubaEnhancedTable.java index 9a9994f3ba..b11920010f 100644 --- a/modules/web/src/com/haulmont/cuba/web/toolkit/ui/CubaEnhancedTable.java +++ b/modules/web/src/com/haulmont/cuba/web/toolkit/ui/CubaEnhancedTable.java @@ -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 { * For internal use only. */ void addGeneratedColumnInternal(Object id, Table.ColumnGenerator generatedColumn); + + boolean isAggregatable(); + void setAggregatable(boolean aggregatable); + + boolean isShowTotalAggregation(); + void setShowTotalAggregation(boolean showTotalAggregation); } \ No newline at end of file diff --git a/modules/web/src/com/haulmont/cuba/web/toolkit/ui/CubaGroupTable.java b/modules/web/src/com/haulmont/cuba/web/toolkit/ui/CubaGroupTable.java index d70898f95b..576a5a68af 100644 --- a/modules/web/src/com/haulmont/cuba/web/toolkit/ui/CubaGroupTable.java +++ b/modules/web/src/com/haulmont/cuba/web/toolkit/ui/CubaGroupTable.java @@ -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 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; + } + } } \ No newline at end of file diff --git a/modules/web/src/com/haulmont/cuba/web/toolkit/ui/CubaTable.java b/modules/web/src/com/haulmont/cuba/web/toolkit/ui/CubaTable.java index 3e96412e76..1c063fbf89 100644 --- a/modules/web/src/com/haulmont/cuba/web/toolkit/ui/CubaTable.java +++ b/modules/web/src/com/haulmont/cuba/web/toolkit/ui/CubaTable.java @@ -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 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 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"); + } } \ No newline at end of file diff --git a/modules/web/src/com/haulmont/cuba/web/toolkit/ui/CubaTreeTable.java b/modules/web/src/com/haulmont/cuba/web/toolkit/ui/CubaTreeTable.java index da6815c1b6..60f7cef4d7 100644 --- a/modules/web/src/com/haulmont/cuba/web/toolkit/ui/CubaTreeTable.java +++ b/modules/web/src/com/haulmont/cuba/web/toolkit/ui/CubaTreeTable.java @@ -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 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 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"); + } } \ No newline at end of file diff --git a/modules/web/themes/havana/components/table/table.scss b/modules/web/themes/havana/components/table/table.scss index 4d5c445993..ec44d1bcca 100644 --- a/modules/web/themes/havana/components/table/table.scss +++ b/modules/web/themes/havana/components/table/table.scss @@ -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; diff --git a/modules/web/themes/havana/havana-defaults.scss b/modules/web/themes/havana/havana-defaults.scss index eaf4bf43a1..2ca7c2e6c5 100644 --- a/modules/web/themes/havana/havana-defaults.scss +++ b/modules/web/themes/havana/havana-defaults.scss @@ -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; diff --git a/modules/web6/themes/havana/components/table/table.scss b/modules/web6/themes/havana/components/table/table.scss index 5ea0291b82..60f7c81000 100644 --- a/modules/web6/themes/havana/components/table/table.scss +++ b/modules/web6/themes/havana/components/table/table.scss @@ -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;