GroupTable Component #PL-1903

This commit is contained in:
Yuriy Artamonov 2013-03-12 13:01:02 +00:00
parent 466b0ee033
commit b3f24dc297
9 changed files with 1192 additions and 57 deletions

View File

@ -62,7 +62,7 @@ def desktopModule = project(':cuba-desktop')
def uiTestModule = project(':cuba-test-ui')
def portalModule = project(':cuba-portal')
def vaadinVersion = '7.0.1.h.M1'
def vaadinVersion = '7.0.2.h.M1'
def servletApi = [group: 'org.apache.tomcat', name: 'servlet-api', version: '6.0.20']
def groovyArtifact = [group: 'org.codehaus.groovy', name: 'groovy', version: '1.7.10']
@ -349,7 +349,7 @@ configure(webToolkitModule) {
dependencyModules = [webModule]
widgetSetClass = 'com.haulmont.cuba.web.toolkit.ui.WidgetSet'
//jvmArgs('-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000')
compilerArgs = ['-style' : 'PRETTY', '-logLevel' : 'INFO', '-localWorkers' : '2']
compilerArgs = ['-style' : 'DETAILED', '-logLevel' : 'INFO', '-localWorkers' : '2', '-draftCompile' : 'true']
}
task webArchive(dependsOn: buildWidgetSet, type: Zip) {

View File

@ -28,7 +28,7 @@
webkit based browsers including Google Chrome.
-->
<!-- vaadin7 -->
<set-property name="user.agent" value="safari, gecko1_8"/>
<set-property name="user.agent" value="safari"/>
<!--
To enable SuperDevMode, uncomment this line.

View File

@ -0,0 +1,148 @@
/*
* Copyright (c) 2008 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
*/
package com.haulmont.cuba.web.toolkit.ui.client;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.haulmont.cuba.web.toolkit.ui.client.sys.ToolsImpl;
import com.vaadin.client.RenderInformation;
/**
* @author gorodnov
* @version $Id$
*/
public class Tools {
private static ToolsImpl impl;
static {
impl = new ToolsImpl();
}
public static int parseSize(String s) {
return impl.parseSize(s);
}
public static String format(String s) {
return impl.format(s);
}
public static void removeChildren(Element e) {
int childCount = DOM.getChildCount(e);
if (childCount > 0) {
for (int i = 0; i < childCount; i++) {
DOM.removeChild(e, DOM.getChild(e, 0));
}
}
}
public static void setInnerHTML(Element elem, String text) {
impl.setInnerHTML(elem, text);
}
public static void setInnerText(Element elem, String text) {
impl.setInnerText(elem, text);
}
public static boolean isRadio(Element elem) {
return impl.isRadio(elem);
}
public static boolean isCheckbox(Element elem) {
return impl.isCheckbox(elem);
}
public static void textSelectionEnable(Element el, boolean b) {
impl.textSelectionEnable(el, b);
}
public static void removeElementWithEvents(Element el) {
impl.removeElementWithEvents(el);
}
public static String setStyleName(Element el, String style) {
if (style == null) throw new RuntimeException("Style cannot be null");
style = style.trim();
DOM.setElementProperty(el, "className", style);
return style;
}
public static String getStyleName(Element el) {
return DOM.getElementProperty(el, "className");
}
public static String addStyleName(Element el, String style) {
if (style == null) throw new RuntimeException("Style cannot be null");
style = style.trim();
el.addClassName(style);
return style;
}
public static void removeStyleName(Element el, String style) {
if (style == null) throw new RuntimeException("Style cannot be null");
style = style.trim();
el.removeClassName(style);
}
public static String setStylePrimaryName(Element el, String style) {
if (style == null) throw new RuntimeException("Style cannot be null");
style = style.trim();
impl.updatePrimaryAndDependentStyleNames(el, style);
return style;
}
public static String getStylePrimaryName(Element el) {
String className = DOM.getElementProperty(el, "className");
int spaceIdx = className.indexOf(' ');
if (spaceIdx >= 0) {
return className.substring(0, spaceIdx);
}
return className;
}
public static String addStyleDependentName(Element el, String styleSuffix) {
String s = getStylePrimaryName(el) + '-' + styleSuffix;
addStyleName(el, s);
return s;
}
public static void removeStyleDependentName(Element el, String styleSuffix) {
removeStyleName(el, getStylePrimaryName(el) + '-' + styleSuffix);
}
public static boolean hasStyleDependentName(Element el, String styleSuffix) {
return hasStyleName(el, getStylePrimaryName(el) + '-' + styleSuffix);
}
public static boolean hasStyleName(Element el, String style) {
if (style == null) throw new RuntimeException("Style cannot be null");
style = style.trim();
return impl.hasStyleName(el, style);
}
public static String[] getStyleNames(Element el) {
return getStyleName(el).split("[\\s+]");
}
public static RenderInformation.Size definePaddingBorders(Element el) {
String w = DOM.getStyleAttribute(el, "width");
String h = DOM.getStyleAttribute(el, "height");
DOM.setStyleAttribute(el, "overflow", "hidden");
DOM.setStyleAttribute(el, "width", "0px");
DOM.setStyleAttribute(el, "height", "0px");
RenderInformation.Size s = new RenderInformation.Size();
s.setWidth(el.getOffsetWidth());
s.setHeight(el.getOffsetHeight());
DOM.setStyleAttribute(el, "width", w);
DOM.setStyleAttribute(el, "height", h);
DOM.setStyleAttribute(el, "overflow", "");
return s;
}
}

View File

@ -0,0 +1,174 @@
/*
* Copyright (c) 2008 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
*/
package com.haulmont.cuba.web.toolkit.ui.client.sys;
import com.google.gwt.dom.client.Element;
/**
* @author gorodnov
* @version $Id$
*/
public class ToolsImpl {
public native int parseSize(String s) /*-{
try {
var result = /^(\d+)(%|px|em|ex|in|cm|mm|pt|pc)$/.exec(s);
return parseInt(result[1]);
} catch (e) {
return -1;
}
}-*/;
public native String format(String message) /*-{
return message.replace(/\[br\]/g, "<br/>")
.replace(/\[b\]/g, "<b>")
.replace(/\[\/b\]/g, "</b>")
.replace(/\[i\]/g, "<i>")
.replace(/\[\/i\]/g, "</i>");
}-*/;
public native void setInnerHTML(Element elem, String text) /*-{
elem.innerHTML = text; //todo gorodnov: support line breaks
}-*/;
public native void setInnerText(Element elem, String text) /*-{
while (elem.firstChild) {
elem.removeChild(elem.firstChild);
}
if (text != null) {
var arr = new Array();
arr = text.replace(/\r/g, "").split("\n");
if (arr.length > 0) {
for (var i = 0; i < arr.length; i++) {
if (arr[i]) {
elem.appendChild($doc.createTextNode(arr[i]));
elem.appendChild($doc.createElement("br"));
}
}
} else {
elem.appendChild($doc.createTextNode(text));
}
}
}-*/;
public native boolean isRadio(Element e) /*-{
return (e && e.tagName.toUpperCase() == "INPUT" && e.type == "radio");
}-*/;
public native boolean isCheckbox(Element e) /*-{
return (e && e.tagName.toUpperCase() == "INPUT" && e.type == "checkbox");
}-*/;
public native void textSelectionEnable(Element el, boolean b) /*-{
// CAUTION Do not use jQuery disable text selection pack, it caches html nodes and we have memory leaks
if (typeof document.falseFunction != "function") {
document.falseFunction = function() {
return false;
};
}
var walkEach = function(element, action) {
if (typeof element != "undefined") {
action(element);
var children = element.childNodes;
if (typeof children != "undefined") {
for (var i = 0; i < children.length; i++)
if (children[i].nodeType == 1)
walkEach(children[i], action);
}
}
};
if (!b) {
// disable
if ($wnd.jQuery.browser.mozilla) {
walkEach(el, function(x) {
if (typeof x.style == "undefined")
x.style = {};
x.style.MozUserSelect = "none";
});
} else if ($wnd.jQuery.browser.msie) {
walkEach(el, function(x) {
x.onselectstart = document.falseFunction;
});
} else if ($wnd.jQuery.browser.webkit) {
walkEach(el, function(x) {
if (typeof x.style == "undefined")
x.style = {};
x.style.webkitUserSelect = "none";
});
} else {
walkEach(el, function(x) {
x.addEventListener("selectstart", document.falseFunction, true);
});
}
} else {
// enable
if ($wnd.jQuery.browser.mozilla) {
walkEach(el, function(x) {
if (typeof x.style == "undefined")
x.style = {};
x.style.MozUserSelect = "";
});
} else if ($wnd.jQuery.browser.msie) {
walkEach(el, function(x) {
x.onselectstart = null;
});
} else if ($wnd.jQuery.browser.webkit) {
walkEach(el, function(x) {
if (typeof x.style == "undefined")
x.style = {};
x.style.webkitUserSelect = "";
});
} else {
walkEach(el, function(x) {
x.removeEventListener("selectstart", document.falseFunction, true);
});
}
}
walkEach = null;
}-*/;
public native void removeElementWithEvents(Element el) /*-{
$wnd.jQuery(el).remove();
}-*/;
public native void updatePrimaryAndDependentStyleNames(Element elem,
String newPrimaryStyle) /*-{
var classes = elem.className.split(/\s+/);
if (!classes) {
return;
}
var oldPrimaryStyle = classes[0];
var oldPrimaryStyleLen = oldPrimaryStyle.length;
classes[0] = newPrimaryStyle;
for (var i = 1, n = classes.length; i < n; i++) {
var name = classes[i];
if (name.length > oldPrimaryStyleLen
&& name.charAt(oldPrimaryStyleLen) == '-'
&& name.indexOf(oldPrimaryStyle) == 0) {
classes[i] = newPrimaryStyle + name.substring(oldPrimaryStyleLen);
}
}
elem.className = classes.join(" ");
}-*/;
public native boolean hasStyleName(Element el, String style) /*-{
var classes = elem.className.split(/\s+/);
if (!classes) {
return false;
}
for (var i = 0; i < classes.length; i++) {
if (classes[i] == style) return true;
}
return false;
}-*/;
}

View File

@ -0,0 +1,42 @@
/*
* Copyright (c) 2013 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
*/
package com.haulmont.cuba.web.toolkit.ui.client.table;
import com.google.gwt.core.client.GWT;
import com.haulmont.cuba.web.toolkit.ui.CubaGroupTable;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.UIDL;
import com.vaadin.client.ui.table.TableConnector;
import com.vaadin.shared.ui.Connect;
/**
* @author artamonov
* @version $Id$
*/
@Connect(CubaGroupTable.class)
public class CubaGroupTableConnector extends TableConnector {
@Override
public CubaGroupTableWidget getWidget() {
return (CubaGroupTableWidget) super.getWidget();
}
@Override
protected CubaGroupTableWidget createWidget() {
return GWT.create(CubaGroupTableWidget.class);
}
@Override
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
if (uidl.hasVariable("groupColumns"))
getWidget().updateGroupColumns(uidl.getStringArrayVariableAsSet("groupColumns"));
else
getWidget().updateGroupColumns(null);
super.updateFromUIDL(uidl, client);
}
}

View File

@ -0,0 +1,468 @@
/*
* Copyright (c) 2013 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
*/
package com.haulmont.cuba.web.toolkit.ui.client.table;
import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
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 com.vaadin.shared.ui.table.TableConstants;
import java.util.HashSet;
import java.util.Set;
/**
* @author artamonov
* @version $Id$
*/
public class CubaGroupTableWidget extends VScrollTable {
public static final String CLASSNAME = "cuba-grouptable";
public static final String GROUP_DIVIDER_COLUMN_KEY = "-1";
protected Set<String> groupColumns;
public void updateGroupColumns(Set<String> groupColumns) {
this.groupColumns = groupColumns;
}
private void addGroupColumn(String colKey) {
if (groupColumns == null) {
groupColumns = new HashSet<String>();
}
groupColumns.add(colKey);
}
private void removeGroupColumn(String colKey) {
if (groupColumns != null) {
groupColumns.remove(colKey);
if (groupColumns.size() == 0)
groupColumns = null;
}
}
private boolean isGroupColumn(String cid) {
return groupColumns != null && groupColumns.contains(cid);
}
@Override
protected int getVisibleColsCount(String[] strings) {
return strings.length + 1;
}
@Override
protected void updateHeaderColumns(String[] strings, int colIndex) {
boolean dividerPainted = false;
int i;
for (i = 0; i < strings.length; i++) {
final String cid = strings[i];
if (!isGroupColumn(cid) && !dividerPainted) {
//paint group columns divider
visibleColOrder[colIndex] = GROUP_DIVIDER_COLUMN_KEY;
tHead.enableColumn(GROUP_DIVIDER_COLUMN_KEY, colIndex++);
dividerPainted = true;
}
visibleColOrder[colIndex] = cid;
tHead.enableColumn(cid, colIndex);
colIndex++;
}
if (!dividerPainted) {
visibleColOrder[colIndex] = GROUP_DIVIDER_COLUMN_KEY;
tHead.enableColumn(GROUP_DIVIDER_COLUMN_KEY, colIndex);
}
}
@Override
protected void updateFooterColumns(String[] strings, int colIndex) {
boolean dividerPainted = false;
int i;
for (i = 0; i < strings.length; i++) {
final String cid = strings[i];
if (!isGroupColumn(cid) && !dividerPainted) {
//paint group columns divider
tFoot.enableColumn(GROUP_DIVIDER_COLUMN_KEY, colIndex++);
dividerPainted = true;
}
tFoot.enableColumn(cid, colIndex);
colIndex++;
}
if (!dividerPainted) {
tFoot.enableColumn(GROUP_DIVIDER_COLUMN_KEY, colIndex);
}
}
@Override
protected void reOrderColumn(String columnKey, int newIndex) {
// CAUTION This method copied from VScrollTable
// Added grouping support
final int oldIndex = getColIndexByKey(columnKey);
// Change header order
tHead.moveCell(oldIndex, newIndex);
// Change footer order
tFoot.moveCell(oldIndex, newIndex);
/*
* Build new columnOrder and update it to server Note that columnOrder
* also contains collapsed columns so we cannot directly build it from
* cells vector Loop the old columnOrder and append in order to new
* array unless on moved columnKey. On new index also put the moved key
* i == index on columnOrder, j == index on newOrder
*/
final String oldKeyOnNewIndex = visibleColOrder[newIndex];
if (showRowHeaders) {
newIndex--; // columnOrder don't have rowHeader
}
// Grouping support
final int groupDividerIndex = getColIndexByKey(GROUP_DIVIDER_COLUMN_KEY);
if (isGroupColumn(columnKey)) {
if (newIndex > 0 && newIndex >= groupDividerIndex) {
removeGroupColumn(columnKey);
newIndex--;
}
} else {
if (newIndex <= groupDividerIndex) {
addGroupColumn(columnKey);
}
if (newIndex > 0 && newIndex > groupDividerIndex) {
newIndex--;
}
}
if (!GROUP_DIVIDER_COLUMN_KEY.equals(oldKeyOnNewIndex)) {
for (int i = 0; i < columnOrder.length; i++) {
if (columnOrder[i].equals(oldKeyOnNewIndex)) {
break; // break loop at target
}
if (isCollapsedColumn(columnOrder[i])) {
newIndex++;
}
}
}
// finally we can build the new columnOrder for server
final String[] newOrder = new String[columnOrder.length];
for (int i = 0, j = 0; j < newOrder.length; i++) {
if (j == newIndex) {
newOrder[j] = columnKey;
j++;
}
if (i == columnOrder.length) {
break;
}
if (columnOrder[i].equals(columnKey)) {
continue;
}
newOrder[j] = columnOrder[i];
j++;
}
columnOrder = newOrder;
// also update visibleColumnOrder
int colIndex = showRowHeaders ? 1 : 0;
boolean dividerPainted = false;
for (int j = 0; j < newOrder.length; j++) {
final String cid = newOrder[j];
if (!isGroupColumn(cid) && !dividerPainted) {
//paint group columns divider
visibleColOrder[colIndex++] = GROUP_DIVIDER_COLUMN_KEY;
dividerPainted = true;
}
if (!isCollapsedColumn(cid)) {
visibleColOrder[colIndex++] = cid;
}
}
// Grouping sypport
if (groupColumns != null) {
// collect new grouped columns
final String[] groupedColumns = new String[groupColumns.size()];
for (int i = 0, j = 0; i < columnOrder.length; i++) {
final String colKey = columnOrder[i];
if (isGroupColumn(colKey)) {
groupedColumns[j++] = colKey;
}
if (j == groupedColumns.length) {
break;
}
}
client.updateVariable(paintableId, "groupedcolumns", groupedColumns, false);
}
// CAUTION we use immediate update of column order
client.updateVariable(paintableId, "columnorder", columnOrder, true);
if (client.hasEventListeners(this,
TableConstants.COLUMN_REORDER_EVENT_ID)) {
client.sendPendingVariableChanges();
}
}
@Override
protected VScrollTableBody createScrollBody() {
return new GroupTableBody();
}
@Override
protected TableHead createTableHead() {
return new GroupTableHead();
}
@Override
protected TableFooter createTableFooter() {
return new GroupTableFooter();
}
protected class GroupTableHead extends TableHead {
public GroupTableHead() {
super();
availableCells.put(GROUP_DIVIDER_COLUMN_KEY, new GroupDividerHeaderCell());
}
@Override
public void clear() {
super.clear();
availableCells.put(GROUP_DIVIDER_COLUMN_KEY, new GroupDividerHeaderCell());
}
@Override
protected void fillAdditionalUpdatedCells(HashSet<String> updated) {
updated.add(GROUP_DIVIDER_COLUMN_KEY);
}
}
protected class GroupTableFooter extends TableFooter {
public GroupTableFooter() {
availableCells.put(GROUP_DIVIDER_COLUMN_KEY, new GroupDividerFooterCell());
}
@Override
public void clear() {
super.clear();
availableCells.put(GROUP_DIVIDER_COLUMN_KEY, new GroupDividerFooterCell());
}
@Override
protected void fillAdditionalUpdatedCells(HashSet<String> updated) {
updated.add(GROUP_DIVIDER_COLUMN_KEY);
}
}
protected class GroupTableBody extends VScrollTableBody {
@Override
protected VScrollTableRow createRow(UIDL uidl, char[] aligns2) {
if (uidl.hasAttribute("groupKey")) {
return new GroupTableGroupRow(uidl, aligns2); //creates a group row
}
else
return new GroupTableRow(uidl, aligns2);
}
@Override
protected void addRow(VScrollTableRow row) {
super.addRow(row);
if (row instanceof GroupTableGroupRow
&& ((GroupTableGroupRow) row).isExpanded()) {
row.addStyleName("v-expanded");
}
}
protected class GroupTableRow extends VScrollTableRow {
public GroupTableRow(UIDL uidl, char[] aligns) {
super(uidl, aligns);
}
@Override
protected boolean addSpecificCell(Object columnId, int colIndex) {
if (GROUP_DIVIDER_COLUMN_KEY.equals(columnId)) {
addCell("", aligns[colIndex], "", false, false, null);
return true;
}
return false;
}
}
protected class GroupTableGroupRow extends GroupTableRow {
private String colKey;
private String groupKey;
private boolean expanded;
private int colIndex = -1;
private boolean hasCells = false;
public GroupTableGroupRow(UIDL uidl, char[] aligns) {
super(uidl, aligns);
}
@Override
protected void addCellsFromUIDL(UIDL uidl, char[] aligns, int colIndex, int visibleColumnIndex) {
colKey = uidl.getStringAttribute("colKey");
groupKey = uidl.getStringAttribute("groupKey");
expanded = uidl.hasAttribute("expanded") && uidl.getBooleanAttribute("expanded");
while (colIndex < visibleColOrder.length && !visibleColOrder[colIndex].equals(colKey)) {
//draw empty cells
Element td = DOM.createTD();
final TableCellElement tdCell = td.cast();
initCellWithText("", ALIGN_LEFT, "", false, true, null, tdCell);
td.setClassName(CubaGroupTableWidget.this.getStylePrimaryName() + "-cell-content");
DOM.appendChild(getElement(), td);
colIndex++;
}
if (colIndex >= visibleColOrder.length)
throw new ArrayIndexOutOfBoundsException();
//paint "+" and group caption
this.colIndex = colIndex;
addGroupCell(uidl.getStringAttribute("groupCaption"));
if (uidl.getChildCount() > 0) {
super.addCellsFromUIDL(uidl, aligns, colIndex, visibleColumnIndex);
hasCells = true;
} else {
Element td = DOM.getChild(getElement(), DOM.getChildCount(getElement()) - 1);
DOM.setElementAttribute(td, "colSpan", String.valueOf(visibleColOrder.length - this.colIndex));
hasCells = false;
}
}
protected void addGroupCell(String text) {
// String only content is optimized by not using Label widget
final TableCellElement td = DOM.createTD().cast();
initCellWithText(text, ALIGN_LEFT, "", false, true, null, td);
// Enchance DOM for table cell
Element container = (Element) td.getChild(0);
String containerInnerHTML = container.getInnerHTML();
container.setInnerHTML("");
Element groupDiv = DOM.createDiv();
DOM.setInnerHTML(groupDiv, "&nbsp;");
Tools.setStyleName(groupDiv, CLASSNAME + "-group-cell");
DOM.appendChild(container, groupDiv);
Element contentDiv = DOM.createDiv();
contentDiv.setInnerHTML(containerInnerHTML);
Tools.setStyleName(contentDiv, CLASSNAME + "-float");
DOM.appendChild(container, contentDiv);
}
@Override
public void onBrowserEvent(Event event) {
final Element targetElement = DOM.eventGetTarget(event);
switch (DOM.eventGetType(event)) {
case Event.ONCLICK:
if (BrowserInfo.get().getWebkitVersion() > 0 && DOM.getElementPropertyBoolean(targetElement, "__cell")) {
scrollBodyPanel.setFocus(true);
}
handleRowClick(event);
break;
default:
break;
}
}
protected void handleRowClick(Event event) {
if (isExpanded()) {
client.updateVariable(paintableId, "collapse", getGroupKey(), true);
} else {
client.updateVariable(paintableId, "expand", getGroupKey(), true);
}
DOM.eventCancelBubble(event, true);
}
@Override
protected boolean handleClickEvent(Event event, Element targetTdOrTr,
boolean immediate) {
return false;
}
@Override
public void showContextMenu(Event event) {
//do nothing
}
public String getColKey() {
return colKey;
}
public String getGroupKey() {
return groupKey;
}
public int getColIndex() {
return colIndex;
}
public boolean isExpanded() {
return expanded;
}
public boolean hasCells() {
return hasCells;
}
}
@Override
public void moveCol(int oldIndex, int newIndex) {
//do nothing, columns reordering will be process on the server
}
}
protected class GroupDividerHeaderCell extends HeaderCell {
public GroupDividerHeaderCell() {
super(GROUP_DIVIDER_COLUMN_KEY, null);
setWidth("10px");
DOM.setElementProperty(td, "className", CLASSNAME + "-group-div");
}
@Override
public void onBrowserEvent(Event event) {
//do nothing
}
@Override
protected void handleCaptionEvent(Event event) {
//do nothing
}
}
protected class GroupDividerFooterCell extends FooterCell {
public GroupDividerFooterCell() {
super(GROUP_DIVIDER_COLUMN_KEY, null);
setWidth("10px");
DOM.setElementProperty(td, "className", CLASSNAME + "-group-div");
}
@Override
public void onBrowserEvent(Event event) {
//do nothing
}
@Override
protected void handleCaptionEvent(Event event) {
//do nothing
}
}
}

View File

@ -24,8 +24,6 @@ import com.haulmont.cuba.web.toolkit.data.AggregationContainer;
import com.haulmont.cuba.web.toolkit.data.GroupTableContainer;
import com.haulmont.cuba.web.toolkit.ui.CubaGroupTable;
import com.vaadin.data.Item;
import com.vaadin.server.PaintException;
import com.vaadin.server.PaintTarget;
import com.vaadin.server.Resource;
import org.apache.commons.lang.StringUtils;
import org.dom4j.Element;
@ -66,22 +64,22 @@ public class WebGroupTable extends WebAbstractTable<CubaGroupTable>
// return b;
// }
@Override
public void paintContent(PaintTarget target) throws PaintException {
super.paintContent(target);
paintSpecificContent(target);
}
// vaadin7
// @Override
// public void groupBy(Object[] properties) {
// groupBy(properties, rerender);
// public void paintContent(PaintTarget target) throws PaintException {
// super.paintContent(target);
// paintSpecificContent(target);
// }
@Override
public void groupBy(Object[] properties) {
groupBy(properties, rerender);
}
};
initComponent(component);
// vaadin7
// component.setGroupPropertyValueFormatter(new AggregatableGroupPropertyValueFormatter());
component.setGroupPropertyValueFormatter(new AggregatableGroupPropertyValueFormatter());
}
@Override
@ -95,12 +93,11 @@ public class WebGroupTable extends WebAbstractTable<CubaGroupTable>
groupPropertiesElement = element.addElement("groupProperties");
// vaadin7
// final Collection<?> groupProperties = component.getGroupProperties();
// for (Object groupProperty : groupProperties) {
// final Element groupPropertyElement = groupPropertiesElement.addElement("property");
// groupPropertyElement.addAttribute("id", groupProperty.toString());
// }
final Collection<?> groupProperties = component.getGroupProperties();
for (Object groupProperty : groupProperties) {
final Element groupPropertyElement = groupPropertiesElement.addElement("property");
groupPropertyElement.addAttribute("id", groupProperty.toString());
}
return true;
}
@ -112,10 +109,9 @@ public class WebGroupTable extends WebAbstractTable<CubaGroupTable>
final Element groupPropertiesElement = element.element("groupProperties");
if (groupPropertiesElement != null) {
final List elements = groupPropertiesElement.elements("property");
final List<MetaPropertyPath> properties = new ArrayList<MetaPropertyPath>(elements.size());
final List<MetaPropertyPath> properties = new ArrayList<>(elements.size());
for (final Object o : elements) {
final MetaPropertyPath property = datasource.getMetaClass().getPropertyEx(
((Element) o).attributeValue("id")
final MetaPropertyPath property = datasource.getMetaClass().getPropertyPath(((Element) o).attributeValue("id")
);
properties.add(property);
}
@ -162,39 +158,32 @@ public class WebGroupTable extends WebAbstractTable<CubaGroupTable>
@Override
public void groupBy(Object[] properties) {
// vaadin7
// component.groupBy(properties);
component.groupBy(properties);
}
@Override
public void expandAll() {
// vaadin7
// component.expandAll();
component.expandAll();
}
@Override
public void expand(GroupInfo groupId) {
// vaadin7
// component.expand(groupId);
component.expand(groupId);
}
@Override
public void collapseAll() {
// vaadin7
// component.collapseAll();
component.collapseAll();
}
@Override
public void collapse(GroupInfo groupId) {
// vaadin7
// component.collapse(groupId);
component.collapse(groupId);
}
@Override
public boolean isExpanded(GroupInfo groupId) {
// vaadin7
// return component.isExpanded(groupId);
return false;
return component.isExpanded(groupId);
}
protected class GroupTableDsWrapper extends SortableCollectionDsWrapper
@ -428,6 +417,7 @@ public class WebGroupTable extends WebAbstractTable<CubaGroupTable>
@Override
public void collapse(Object id) {
if (isGroup(id)) {
//noinspection RedundantCast
expanded.remove((GroupInfo)id);
resetCachedItems();
}
@ -435,6 +425,7 @@ public class WebGroupTable extends WebAbstractTable<CubaGroupTable>
@Override
public boolean isExpanded(Object id) {
//noinspection RedundantCast
return isGroup(id) && expanded.contains((GroupInfo)id);
}
@ -617,18 +608,16 @@ public class WebGroupTable extends WebAbstractTable<CubaGroupTable>
@Override
public void stateChanged(Datasource<Entity> ds, Datasource.State prevState, Datasource.State state) {
rerender = false;
// vaadin7
// Collection groupProperties = component.getGroupProperties();
// component.groupBy(groupProperties.toArray());
Collection groupProperties = component.getGroupProperties();
component.groupBy(groupProperties.toArray());
super.stateChanged(ds, prevState, state);
rerender = true;
}
@Override
public void collectionChanged(CollectionDatasource ds, Operation operation, List<Entity> items) {
// vaadin7
// Collection groupProperties = component.getGroupProperties();
// component.groupBy(groupProperties.toArray());
Collection groupProperties = component.getGroupProperties();
component.groupBy(groupProperties.toArray());
super.collectionChanged(ds, operation, items);
}
}
@ -639,15 +628,12 @@ public class WebGroupTable extends WebAbstractTable<CubaGroupTable>
@Override
public String format(Object groupId, Object value) {
String formattedValue = super.format(groupId, value);
// vaadin7
// int count = WebGroupTable.this.component.getGroupItemsCount(groupId);
// return String.format("%s (%d)", formattedValue == null ? "" : formattedValue, count);
return formattedValue;
int count = WebGroupTable.this.component.getGroupItemsCount(groupId);
return String.format("%s (%d)", formattedValue == null ? "" : formattedValue, count);
}
}
protected class DefaultGroupPropertyValueFormatter
implements com.haulmont.cuba.web.toolkit.ui.GroupTable.GroupPropertyValueFormatter {
protected class DefaultGroupPropertyValueFormatter implements CubaGroupTable.GroupPropertyValueFormatter {
@Override
public String format(Object groupId, Object value) {

View File

@ -2,11 +2,6 @@
* Copyright (c) 2008 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
* Author: Nikolay Gorodnov
* Created: 10.11.2009 18:00:23
*
* $Id$
*/
package com.haulmont.cuba.web.toolkit.data;
@ -14,6 +9,10 @@ import com.vaadin.data.Container;
import java.util.Collection;
/**
* @author gorodnov
* @version $Id$
*/
public interface GroupTableContainer extends Container.Sortable {
void groupBy(Object[] properties);
@ -44,4 +43,4 @@ public interface GroupTableContainer extends Container.Sortable {
void collapse(Object id);
boolean isExpanded(Object id);
}
}

View File

@ -1,19 +1,42 @@
/*
* Copyright (c) 2013 Haulmont Technology Ltd. All Rights Reserved.
* Copyright (c) 2008 Haulmont Technology Ltd. All Rights Reserved.
* Haulmont Technology proprietary and confidential.
* Use is subject to license terms.
*/
package com.haulmont.cuba.web.toolkit.ui;
import com.haulmont.cuba.gui.data.GroupInfo;
import com.haulmont.cuba.web.gui.data.PropertyValueStringify;
import com.haulmont.cuba.web.toolkit.data.GroupTableContainer;
import com.haulmont.cuba.web.toolkit.data.util.GroupTableContainerWrapper;
import com.vaadin.data.Container;
import com.vaadin.data.Property;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.server.KeyMapper;
import com.vaadin.server.PaintException;
import com.vaadin.server.PaintTarget;
import java.util.*;
/**
* @author artamonov
* @author gorodnov
* @version $Id$
*/
public class CubaGroupTable extends com.vaadin.ui.Table {
public class CubaGroupTable extends com.vaadin.ui.Table implements GroupTableContainer {
private KeyMapper groupIdMap = new KeyMapper();
private GroupPropertyValueFormatter groupPropertyValueFormatter;
@Override
public void setContainerDataSource(Container newDataSource) {
if (newDataSource == null) {
newDataSource = new IndexedContainer();
}
super.setContainerDataSource(new GroupTableContainerWrapper(newDataSource));
}
@Override
protected String formatPropertyValue(Object rowId, Object colId, Property<?> property) {
@ -22,4 +45,299 @@ public class CubaGroupTable extends com.vaadin.ui.Table {
return super.formatPropertyValue(rowId, colId, property);
}
@Override
public void paintContent(PaintTarget target) throws PaintException {
super.paintContent(target);
if (hasGroups()) {
final Collection groupProperties = getGroupProperties();
final String[] groupColumns = new String[groupProperties.size()];
int index = 0;
for (final Object groupColumnId : groupProperties) {
groupColumns[index++] = columnIdMap.key(groupColumnId);
}
target.addVariable(this, "groupColumns", groupColumns);
}
}
@Override
protected boolean changeVariables(Map<String, Object> variables) {
boolean clientNeedsContentRefresh = super.changeVariables(variables);
boolean needsResetPageBuffer = false;
Object[] newGroupProperties = null;
if (variables.containsKey("columnorder") && !variables.containsKey("groupedcolumns")) {
newGroupProperties = new Object[0];
} else if (variables.containsKey("groupedcolumns")) {
final Object[] ids = (Object[]) variables.get("groupedcolumns");
final Object[] groupProperties = new Object[ids.length];
for (int i = 0; i < ids.length; i++) {
groupProperties[i] = columnIdMap.get(ids[i].toString());
}
newGroupProperties = groupProperties;
// Deny group by generated columns
if (!columnGenerators.isEmpty()) {
List<Object> notGeneratedProperties = new ArrayList<>();
for (Object id : newGroupProperties) {
if (!columnGenerators.containsKey(id))
notGeneratedProperties.add(id);
}
newGroupProperties = notGeneratedProperties.toArray();
}
}
if (variables.containsKey("collapsedcolumns")) {
boolean needToRegroup = false;
final List<Object> groupProperties = new ArrayList<>(getGroupProperties());
for (int index = 0; index < groupProperties.size(); index++) {
final Object propertyId = groupProperties.get(index);
if (isColumnCollapsed(propertyId)) {
groupProperties.subList(index, groupProperties.size())
.clear();
needToRegroup = true;
break;
}
}
if (needToRegroup) {
newGroupProperties = groupProperties.toArray();
}
}
if (variables.containsKey("expand")) {
Object groupId = groupIdMap.get((String) variables.get("expand"));
expand(groupId, false);
clientNeedsContentRefresh = true;
needsResetPageBuffer = true;
}
if (variables.containsKey("collapse")) {
Object groupId = groupIdMap.get((String) variables.get("collapse"));
collapse(groupId, false);
clientNeedsContentRefresh = true;
needsResetPageBuffer = true;
}
if (newGroupProperties != null) {
groupBy(newGroupProperties, false);
}
if (needsResetPageBuffer) {
resetPageBuffer();
}
return clientNeedsContentRefresh;
}
@Override
protected void paintRowAttributes(PaintTarget target, Object itemId) throws PaintException {
super.paintRowAttributes(target, itemId);
boolean hasGroups = hasGroups();
if (hasGroups) {
if (isGroup(itemId)) {
target.addAttribute("colKey", columnIdMap.key(getGroupProperty(itemId)));
target.addAttribute("groupKey", groupIdMap.key(itemId));
if (isExpanded(itemId))
target.addAttribute("expanded", true);
final Object propertyValue = getGroupPropertyValue(itemId);
target.addAttribute("groupCaption", formatGroupPropertyValue(itemId, propertyValue));
// todo aggregation
}
}
}
@Override
protected LinkedHashSet<Object> getItemIdsInRange(Object startItemId, final int length) {
Set<Object> rootIds = super.getItemIdsInRange(startItemId, length);
LinkedHashSet<Object> ids = new LinkedHashSet<>();
for (Object itemId: rootIds) {
if (itemId instanceof GroupInfo) {
if (!isExpanded(itemId)) {
Collection<?> itemIds = getGroupItemIds(itemId);
ids.addAll(itemIds);
expand(itemId, true);
}
List<GroupInfo> children = (List<GroupInfo>) getChildren(itemId);
for (GroupInfo groupInfo : children) {
if (!isExpanded(groupInfo)) {
expand(groupInfo, true);
}
}
} else {
ids.add(itemId);
}
}
return ids;
}
@Override
protected boolean isColumnNeedsToRefreshRendered(Object colId) {
final GroupTableContainer items = (GroupTableContainer) this.items;
final boolean groupped = items.hasGroups();
return !groupped || !getGroupProperties().contains(colId);
}
@Override
protected boolean isItemNeedsToRefreshRendered(Object itemId) {
final GroupTableContainer items = (GroupTableContainer) this.items;
final boolean groupped = items.hasGroups();
return !groupped || !items.isGroup(itemId);
}
protected String formatGroupPropertyValue(Object groupId, Object groupValue) {
return groupPropertyValueFormatter != null
? groupPropertyValueFormatter.format(groupId, groupValue)
: (groupValue == null ? "" : groupValue.toString());
}
protected void expand(Object id, boolean rerender) {
final int pageIndex = getCurrentPageFirstItemIndex();
((GroupTableContainer) items).expand(id);
setCurrentPageFirstItemIndex(pageIndex, false);
if (rerender) {
resetPageBuffer();
refreshRenderedCells();
markAsDirty();
}
}
protected void collapse(Object id, boolean rerender) {
final int pageIndex = getCurrentPageFirstItemIndex();
((GroupTableContainer) items).collapse(id);
setCurrentPageFirstItemIndex(pageIndex, false);
if (rerender) {
resetPageBuffer();
refreshRenderedCells();
markAsDirty();
}
}
protected void groupBy(Object[] properties, boolean rerender) {
((GroupTableContainer) items).groupBy(properties);
if (rerender) {
resetPageBuffer();
refreshRenderedCells();
markAsDirty();
}
}
@Override
public Collection<?> getGroupProperties() {
Collection<?> groupProperties = ((GroupTableContainer) items).getGroupProperties();
// Deny group by generated columns
if (!columnGenerators.isEmpty()) {
List<Object> notGeneratedGroupProps = new ArrayList<>();
for (Object id : groupProperties) {
if (!columnGenerators.containsKey(id))
notGeneratedGroupProps.add(id);
}
return notGeneratedGroupProps;
} else
return groupProperties;
}
@Override
public void expandAll() {
final int pageIndex = getCurrentPageFirstItemIndex();
((GroupTableContainer) items).expandAll();
setCurrentPageFirstItemIndex(pageIndex, false);
resetPageBuffer();
refreshRenderedCells();
markAsDirty();
}
@Override
public void expand(Object id) {
expand(id, true);
}
@Override
public void collapseAll() {
final int pageIndex = getCurrentPageFirstItemIndex();
((GroupTableContainer) items).collapseAll();
setCurrentPageFirstItemIndex(pageIndex, false);
resetPageBuffer();
refreshRenderedCells();
markAsDirty();
}
@Override
public void collapse(Object id) {
collapse(id, true);
}
@Override
public boolean hasGroups() {
return ((GroupTableContainer) items).hasGroups();
}
@Override
public void groupBy(Object[] properties) {
groupBy(properties, true);
}
@Override
public boolean isGroup(Object itemId) {
return ((GroupTableContainer) items).isGroup(itemId);
}
@Override
public Collection<?> rootGroups() {
return ((GroupTableContainer) items).rootGroups();
}
@Override
public boolean hasChildren(Object id) {
return ((GroupTableContainer) items).hasChildren(id);
}
@Override
public Collection<?> getChildren(Object id) {
return ((GroupTableContainer) items).getChildren(id);
}
@Override
public Object getGroupProperty(Object itemId) {
return ((GroupTableContainer) items).getGroupProperty(itemId);
}
@Override
public Object getGroupPropertyValue(Object itemId) {
return ((GroupTableContainer) items).getGroupPropertyValue(itemId);
}
@Override
public Collection<?> getGroupItemIds(Object itemId) {
return ((GroupTableContainer) items).getGroupItemIds(itemId);
}
@Override
public int getGroupItemsCount(Object itemId) {
return ((GroupTableContainer) items).getGroupItemsCount(itemId);
}
@Override
public boolean isExpanded(Object id) {
return ((GroupTableContainer) items).isExpanded(id);
}
public GroupPropertyValueFormatter getGroupPropertyValueFormatter() {
return groupPropertyValueFormatter;
}
public void setGroupPropertyValueFormatter(GroupPropertyValueFormatter groupPropertyValueFormatter) {
this.groupPropertyValueFormatter = groupPropertyValueFormatter;
}
public interface GroupPropertyValueFormatter {
String format(Object groupId, Object value);
}
}