summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJonatan Kronqvist <jonatan.kronqvist@itmill.com>2011-08-19 07:16:01 +0000
committerJonatan Kronqvist <jonatan.kronqvist@itmill.com>2011-08-19 07:16:01 +0000
commit12bb89d64b3ba975701600aefdcec06dc4530086 (patch)
tree8d3c4bb17d440c094de4c50493eb4fe7da42ee47 /src
parent65cf73d3272c0b77dcf21c51b14986db5885a0f1 (diff)
downloadvaadin-framework-12bb89d64b3ba975701600aefdcec06dc4530086.tar.gz
vaadin-framework-12bb89d64b3ba975701600aefdcec06dc4530086.zip
Implemented row generation for Table and TreeTable #6720#
svn changeset:20495/svn branch:6.7
Diffstat (limited to 'src')
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java360
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VTreeTable.java82
-rw-r--r--src/com/vaadin/ui/Table.java224
3 files changed, 503 insertions, 163 deletions
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
index fb51919b10..f0db3e55b2 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VScrollTable.java
@@ -1679,9 +1679,13 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
/**
* Run only once when component is attached and received its initial
- * content. This function : * Syncs headers and bodys "natural widths and
- * saves the values. * Sets proper width and height * Makes deferred request
- * to get some cache rows
+ * content. This function:
+ *
+ * * Syncs headers and bodys "natural widths and saves the values.
+ *
+ * * Sets proper width and height
+ *
+ * * Makes deferred request to get some cache rows
*/
private void sizeInit() {
/*
@@ -3968,22 +3972,16 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
*/
private VScrollTableRow prepareRow(UIDL uidl) {
final VScrollTableRow row = createRow(uidl, aligns);
- final int cells = DOM.getChildCount(row.getElement());
- for (int i = 0; i < cells; i++) {
- final Element cell = DOM.getChild(row.getElement(), i);
- int w = VScrollTable.this.getColWidth(getColKeyByIndex(i));
- if (w < 0) {
- w = 0;
- }
- cell.getFirstChildElement().getStyle()
- .setPropertyPx("width", w);
- cell.getStyle().setPropertyPx("width", w);
- }
+ row.initCellWidths();
return row;
}
protected VScrollTableRow createRow(UIDL uidl, char[] aligns2) {
- return new VScrollTableRow(uidl, aligns);
+ if (uidl.hasAttribute("gen_html")) {
+ // This is a generated row.
+ return new VScrollTableGeneratedRow(uidl, aligns2);
+ }
+ return new VScrollTableRow(uidl, aligns2);
}
private void addRowBeforeFirstRendered(VScrollTableRow row) {
@@ -4187,16 +4185,19 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
*/
public int getColWidth(int columnIndex) {
if (tBodyMeasurementsDone) {
- NodeList<TableRowElement> rows = tBodyElement.getRows();
- if (rows.getLength() == 0) {
+ if (renderedRows.isEmpty()) {
// no rows yet rendered
return 0;
- } else {
- com.google.gwt.dom.client.Element wrapperdiv = rows
- .getItem(0).getCells().getItem(columnIndex)
- .getFirstChildElement();
- return wrapperdiv.getOffsetWidth();
}
+ for (Widget row : renderedRows) {
+ if (!(row instanceof VScrollTableGeneratedRow)) {
+ TableRowElement tr = row.getElement().cast();
+ Element wrapperdiv = tr.getCells().getItem(columnIndex)
+ .getFirstChildElement().cast();
+ return wrapperdiv.getOffsetWidth();
+ }
+ }
+ return 0;
} else {
return 0;
}
@@ -4216,14 +4217,22 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
* @param w
*/
public void setColWidth(int colIndex, int w) {
- NodeList<TableRowElement> rows2 = tBodyElement.getRows();
- final int rows = rows2.getLength();
- for (int i = 0; i < rows; i++) {
- TableRowElement row = rows2.getItem(i);
- TableCellElement cell = row.getCells().getItem(colIndex);
- cell.getFirstChildElement().getStyle()
- .setPropertyPx("width", w);
- cell.getStyle().setPropertyPx("width", w);
+ for (Widget row : renderedRows) {
+ TableRowElement tr = row.getElement().cast();
+ TableCellElement cell = tr.getCells().getItem(colIndex);
+ boolean spanned = false;
+ if (row instanceof VScrollTableGeneratedRow) {
+ spanned = ((VScrollTableGeneratedRow) row).isSpanColumns();
+ }
+ if (!spanned) {
+ cell.getFirstChildElement().getStyle()
+ .setPropertyPx("width", w);
+ cell.getStyle().setPropertyPx("width", w);
+ } else if (colIndex == 0) {
+ cell.getFirstChildElement().getStyle()
+ .clearProperty("width");
+ cell.getStyle().clearProperty("width");
+ }
}
}
@@ -4323,8 +4332,8 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
protected final int rowKey;
private List<UIDL> pendingComponentPaints;
- private String[] actionKeys = null;
- private final TableRowElement rowElement;
+ protected String[] actionKeys = null;
+ protected final TableRowElement rowElement;
private boolean mDown;
private int index;
private Event touchStart;
@@ -4345,6 +4354,120 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
| Event.ONCONTEXTMENU | VTooltip.TOOLTIP_EVENTS);
}
+ public VScrollTableRow(UIDL uidl, char[] aligns) {
+ this(uidl.getIntAttribute("key"));
+
+ /*
+ * Rendering the rows as hidden improves Firefox and Safari
+ * performance drastically.
+ */
+ getElement().getStyle().setProperty("visibility", "hidden");
+
+ String rowStyle = uidl.getStringAttribute("rowstyle");
+ if (rowStyle != null) {
+ addStyleName(CLASSNAME + "-row-" + rowStyle);
+ }
+
+ String rowDescription = uidl.getStringAttribute("rowdescr");
+ if (rowDescription != null && !rowDescription.equals("")) {
+ TooltipInfo info = new TooltipInfo(rowDescription);
+ client.registerTooltip(VScrollTable.this, rowElement, info);
+ } else {
+ // Remove possibly previously set tooltip
+ client.registerTooltip(VScrollTable.this, rowElement, null);
+ }
+
+ tHead.getColumnAlignments();
+ int col = 0;
+ int visibleColumnIndex = -1;
+
+ // row header
+ if (showRowHeaders) {
+ boolean sorted = tHead.getHeaderCell(col).isSorted();
+ addCell(uidl, buildCaptionHtmlSnippet(uidl), aligns[col++],
+ "rowheader", true, sorted);
+ visibleColumnIndex++;
+ }
+
+ if (uidl.hasAttribute("al")) {
+ actionKeys = uidl.getStringArrayAttribute("al");
+ }
+
+ addCellsFromUIDL(uidl, aligns, col, visibleColumnIndex);
+
+ if (uidl.hasAttribute("selected") && !isSelected()) {
+ toggleSelection();
+ }
+ }
+
+ /**
+ * Add a dummy row, used for measurements if Table is empty.
+ */
+ public VScrollTableRow() {
+ this(0);
+ addStyleName(CLASSNAME + "-row");
+ addCell(null, "_", 'b', "", true, false);
+ }
+
+ protected void initCellWidths() {
+ final int cells = DOM.getChildCount(getElement());
+ for (int i = 0; i < cells; i++) {
+ final Element cell = DOM.getChild(getElement(), i);
+ int w = VScrollTable.this.getColWidth(getColKeyByIndex(i));
+ if (w < 0) {
+ w = 0;
+ }
+ cell.getFirstChildElement().getStyle()
+ .setPropertyPx("width", w);
+ cell.getStyle().setPropertyPx("width", w);
+ }
+ }
+
+ protected void addCellsFromUIDL(UIDL uidl, char[] aligns, int col,
+ int visibleColumnIndex) {
+ final Iterator<?> cells = uidl.getChildIterator();
+ while (cells.hasNext()) {
+ final Object cell = cells.next();
+ visibleColumnIndex++;
+
+ String columnId = visibleColOrder[visibleColumnIndex];
+
+ 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(col).isSorted();
+ if (cell instanceof String) {
+ addCell(uidl, cell.toString(), aligns[col++], style,
+ isRenderCellsAsHtml(), sorted, description);
+ } else {
+ final Paintable cellContent = client
+ .getPaintable((UIDL) cell);
+
+ addCell(uidl, (Widget) cellContent, aligns[col++],
+ style, sorted);
+ paintComponent(cellContent, (UIDL) cell);
+ }
+ }
+ }
+
+ /**
+ * Overriding this and returning true causes all text cells to be
+ * rendered as HTML.
+ *
+ * @return always returns false in the default implementation
+ */
+ protected boolean isRenderCellsAsHtml() {
+ return false;
+ }
+
/**
* Detects whether row is visible in tables viewport.
*
@@ -4403,7 +4526,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
return index;
}
- private void paintComponent(Paintable p, UIDL uidl) {
+ protected void paintComponent(Paintable p, UIDL uidl) {
if (isAttached()) {
p.updateFromUIDL(uidl, client);
} else {
@@ -4435,90 +4558,6 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
return String.valueOf(rowKey);
}
- public VScrollTableRow(UIDL uidl, char[] aligns) {
- this(uidl.getIntAttribute("key"));
-
- /*
- * Rendering the rows as hidden improves Firefox and Safari
- * performance drastically.
- */
- getElement().getStyle().setProperty("visibility", "hidden");
-
- String rowStyle = uidl.getStringAttribute("rowstyle");
- if (rowStyle != null) {
- addStyleName(CLASSNAME + "-row-" + rowStyle);
- }
-
- String rowDescription = uidl.getStringAttribute("rowdescr");
- if (rowDescription != null && !rowDescription.equals("")) {
- TooltipInfo info = new TooltipInfo(rowDescription);
- client.registerTooltip(VScrollTable.this, rowElement, info);
- } else {
- // Remove possibly previously set tooltip
- client.registerTooltip(VScrollTable.this, rowElement, null);
- }
-
- tHead.getColumnAlignments();
- int col = 0;
- int visibleColumnIndex = -1;
-
- // row header
- if (showRowHeaders) {
- boolean sorted = tHead.getHeaderCell(col).isSorted();
- addCell(uidl, buildCaptionHtmlSnippet(uidl), aligns[col++],
- "rowheader", true, sorted);
- visibleColumnIndex++;
- }
-
- if (uidl.hasAttribute("al")) {
- actionKeys = uidl.getStringArrayAttribute("al");
- }
-
- final Iterator<?> cells = uidl.getChildIterator();
- while (cells.hasNext()) {
- final Object cell = cells.next();
- visibleColumnIndex++;
-
- String columnId = visibleColOrder[visibleColumnIndex];
-
- 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(col).isSorted();
- if (cell instanceof String) {
- addCell(uidl, cell.toString(), aligns[col++], style,
- false, sorted, description);
- } else {
- final Paintable cellContent = client
- .getPaintable((UIDL) cell);
-
- addCell(uidl, (Widget) cellContent, aligns[col++],
- style, sorted);
- paintComponent(cellContent, (UIDL) cell);
- }
- }
- if (uidl.hasAttribute("selected") && !isSelected()) {
- toggleSelection();
- }
- }
-
- /**
- * Add a dummy row, used for measurements if Table is empty.
- */
- public VScrollTableRow() {
- this(0);
- addStyleName(CLASSNAME + "-row");
- addCell(null, "_", 'b', "", true, false);
- }
-
public void addCell(UIDL rowUidl, String text, char align,
String style, boolean textIsHTML, boolean sorted) {
addCell(rowUidl, text, align, style, textIsHTML, sorted, null);
@@ -4528,7 +4567,14 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
String style, boolean textIsHTML, boolean sorted,
String description) {
// String only content is optimized by not using Label widget
- final Element td = DOM.createTD();
+ final TableCellElement td = DOM.createTD().cast();
+ initCellWithText(text, align, style, textIsHTML, sorted,
+ description, td);
+ }
+
+ protected void initCellWithText(String text, char align,
+ String style, boolean textIsHTML, boolean sorted,
+ String description, final TableCellElement td) {
final Element container = DOM.createDiv();
String className = CLASSNAME + "-cell-content";
if (style != null && !style.equals("")) {
@@ -4570,7 +4616,12 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
public void addCell(UIDL rowUidl, Widget w, char align,
String style, boolean sorted) {
- final Element td = DOM.createTD();
+ final TableCellElement td = DOM.createTD().cast();
+ initCellWithWidget(w, align, style, sorted, td);
+ }
+
+ protected void initCellWithWidget(Widget w, char align,
+ String style, boolean sorted, final TableCellElement td) {
final Element container = DOM.createDiv();
String className = CLASSNAME + "-cell-content";
if (style != null && !style.equals("")) {
@@ -5223,7 +5274,7 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
};
}
- private int getColIndexOf(Widget child) {
+ protected int getColIndexOf(Widget child) {
com.google.gwt.dom.client.Element widgetCell = child
.getElement().getParentElement().getParentElement();
NodeList<TableCellElement> cells = rowElement.getCells();
@@ -5269,6 +5320,75 @@ public class VScrollTable extends FlowPanel implements Table, ScrollHandler,
}
}
+ protected class VScrollTableGeneratedRow extends VScrollTableRow {
+
+ private boolean spanColumns;
+ private boolean renderAsHtml;
+
+ public VScrollTableGeneratedRow(UIDL uidl, char[] aligns) {
+ super(uidl, aligns);
+ addStyleName("v-table-generated-row");
+ }
+
+ @Override
+ protected void initCellWidths() {
+ if (!spanColumns) {
+ super.initCellWidths();
+ }
+ }
+
+ public boolean isSpanColumns() {
+ return spanColumns;
+ }
+
+ @Override
+ protected boolean isRenderCellsAsHtml() {
+ return renderAsHtml;
+ }
+
+ @Override
+ protected void addCellsFromUIDL(UIDL uidl, char[] aligns, int col,
+ int visibleColumnIndex) {
+ renderAsHtml = uidl.getBooleanAttribute("gen_html");
+ spanColumns = uidl.getBooleanAttribute("gen_span");
+
+ final Iterator<?> cells = uidl.getChildIterator();
+ if (spanColumns) {
+ int colCount = uidl.getChildCount();
+ if (cells.hasNext()) {
+ final Object cell = cells.next();
+ if (cell instanceof String) {
+ addSpannedCell(uidl, cell.toString(), aligns[0],
+ "", renderAsHtml, false, null, colCount);
+ } else {
+ addSpannedCell(uidl, (Widget) cell, aligns[0], "",
+ false, colCount);
+ }
+ }
+ } else {
+ super.addCellsFromUIDL(uidl, aligns, col,
+ visibleColumnIndex);
+ }
+ }
+
+ private void addSpannedCell(UIDL rowUidl, Widget w, char align,
+ String style, boolean sorted, int colCount) {
+ TableCellElement td = DOM.createTD().cast();
+ td.setColSpan(colCount);
+ initCellWithWidget(w, align, style, sorted, td);
+ }
+
+ private void addSpannedCell(UIDL rowUidl, String text, char align,
+ String style, boolean textIsHTML, boolean sorted,
+ String description, int colCount) {
+ // String only content is optimized by not using Label widget
+ final TableCellElement td = DOM.createTD().cast();
+ td.setColSpan(colCount);
+ initCellWithText(text, align, style, textIsHTML, sorted,
+ description, td);
+ }
+ }
+
/**
* Ensure the component has a focus.
*
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VTreeTable.java b/src/com/vaadin/terminal/gwt/client/ui/VTreeTable.java
index a3b7008e77..b21a5dfdce 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VTreeTable.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VTreeTable.java
@@ -15,6 +15,7 @@ import com.google.gwt.dom.client.SpanElement;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.dom.client.Style.Visibility;
+import com.google.gwt.dom.client.TableCellElement;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
@@ -122,6 +123,10 @@ public class VTreeTable extends VScrollTable {
@Override
protected VScrollTableRow createRow(UIDL uidl, char[] aligns2) {
+ if (uidl.hasAttribute("gen_html")) {
+ // This is a generated row.
+ return new VTreeTableGeneratedRow(uidl, aligns2);
+ }
return new VTreeTableRow(uidl, aligns2);
}
@@ -133,7 +138,7 @@ public class VTreeTable extends VScrollTable {
private boolean open;
private int depth;
private boolean canHaveChildren;
- private Widget widgetInHierarchyColumn;
+ protected Widget widgetInHierarchyColumn;
public VTreeTableRow(UIDL uidl, char[] aligns2) {
super(uidl, aligns2);
@@ -149,7 +154,7 @@ public class VTreeTable extends VScrollTable {
addTreeSpacer(rowUidl);
}
- private boolean addTreeSpacer(UIDL rowUidl) {
+ protected boolean addTreeSpacer(UIDL rowUidl) {
if (cellShowsTreeHierarchy(getElement().getChildCount() - 1)) {
Element container = (Element) getElement().getLastChild()
.getFirstChild();
@@ -265,6 +270,79 @@ public class VTreeTable extends VScrollTable {
}
+ protected class VTreeTableGeneratedRow extends VTreeTableRow {
+
+ private boolean spanColumns;
+ private boolean renderAsHtml;
+
+ public VTreeTableGeneratedRow(UIDL uidl, char[] aligns) {
+ super(uidl, aligns);
+ addStyleName("v-table-generated-row");
+ }
+
+ @Override
+ protected void initCellWidths() {
+ if (!spanColumns) {
+ super.initCellWidths();
+ }
+ }
+
+ public boolean isSpanColumns() {
+ return spanColumns;
+ }
+
+ @Override
+ protected boolean isRenderCellsAsHtml() {
+ return renderAsHtml;
+ }
+
+ @Override
+ protected void addCellsFromUIDL(UIDL uidl, char[] aligns, int col,
+ int visibleColumnIndex) {
+ renderAsHtml = uidl.getBooleanAttribute("gen_html");
+ spanColumns = uidl.getBooleanAttribute("gen_span");
+
+ final Iterator<?> cells = uidl.getChildIterator();
+ if (spanColumns) {
+ int colCount = uidl.getChildCount();
+ if (cells.hasNext()) {
+ final Object cell = cells.next();
+ if (cell instanceof String) {
+ addSpannedCell(uidl, cell.toString(), aligns[0],
+ "", renderAsHtml, false, null, colCount);
+ } else {
+ addSpannedCell(uidl, (Widget) cell, aligns[0], "",
+ false, colCount);
+ }
+ }
+ } else {
+ super.addCellsFromUIDL(uidl, aligns, col,
+ visibleColumnIndex);
+ }
+ }
+
+ private void addSpannedCell(UIDL rowUidl, Widget w, char align,
+ String style, boolean sorted, int colCount) {
+ TableCellElement td = DOM.createTD().cast();
+ td.setColSpan(colCount);
+ initCellWithWidget(w, align, style, sorted, td);
+ if (addTreeSpacer(rowUidl)) {
+ widgetInHierarchyColumn = w;
+ }
+ }
+
+ private void addSpannedCell(UIDL rowUidl, String text, char align,
+ String style, boolean textIsHTML, boolean sorted,
+ String description, int colCount) {
+ // String only content is optimized by not using Label widget
+ final TableCellElement td = DOM.createTD().cast();
+ td.setColSpan(colCount);
+ initCellWithText(text, align, style, textIsHTML, sorted,
+ description, td);
+ addTreeSpacer(rowUidl);
+ }
+ }
+
private int getIdentWidth() {
return identWidth;
}
diff --git a/src/com/vaadin/ui/Table.java b/src/com/vaadin/ui/Table.java
index 5f0fd07277..09625d88d6 100644
--- a/src/com/vaadin/ui/Table.java
+++ b/src/com/vaadin/ui/Table.java
@@ -109,7 +109,9 @@ public class Table extends AbstractSelect implements Action.Container,
protected static final int CELL_ITEMID = 3;
- protected static final int CELL_FIRSTCOL = 4;
+ protected static final int CELL_GENERATED_ROW = 4;
+
+ protected static final int CELL_FIRSTCOL = 5;
/**
* Left column alignment. <b>This is the default behaviour. </b>
@@ -400,6 +402,8 @@ public class Table extends AbstractSelect implements Action.Container,
private boolean rowCacheInvalidated;
+ private RowGenerator rowGenerator = null;
+
/* Table constructors */
/**
@@ -1533,61 +1537,79 @@ public class Table extends AbstractSelect implements Action.Container,
cells[CELL_ICON][i] = getItemIcon(id);
}
+ GeneratedRow generatedRow = rowGenerator != null ? rowGenerator
+ .generateRow(this, id) : null;
+ cells[CELL_GENERATED_ROW][i] = generatedRow;
+
for (int j = 0; j < cols; j++) {
if (isColumnCollapsed(colids[j])) {
continue;
}
Property p = null;
Object value = "";
- boolean isGenerated = columnGenerators.containsKey(colids[j]);
+ boolean isGeneratedRow = generatedRow != null;
+ boolean isGeneratedColumn = columnGenerators
+ .containsKey(colids[j]);
+ boolean isGenerated = isGeneratedRow || isGeneratedColumn;
if (!isGenerated) {
p = getContainerProperty(id, colids[j]);
}
- // check in current pageBuffer already has row
- int index = firstIndex + i;
- if (p != null || isGenerated) {
- if (index < firstIndexNotInCache
- && index >= pageBufferFirstIndex) {
- // we have data already in our cache,
- // recycle it instead of fetching it via
- // getValue/getPropertyValue
+ if (isGeneratedRow) {
+ if (generatedRow.isSpanColumns() && j > 0) {
+ value = null;
+ } else if (generatedRow.getText().length > j) {
+ value = generatedRow.getText()[j];
+ }
+ } else {
+ // check in current pageBuffer already has row
+ int index = firstIndex + i;
+ if (p != null || isGenerated) {
int indexInOldBuffer = index - pageBufferFirstIndex;
- value = pageBuffer[CELL_FIRSTCOL + j][indexInOldBuffer];
- if (!isGenerated && iscomponent[j]
- || !(value instanceof Component)) {
- listenProperty(p, oldListenedProperties);
- }
- } else {
- if (isGenerated) {
- ColumnGenerator cg = columnGenerators
- .get(colids[j]);
- value = cg.generateCell(this, id, colids[j]);
- if (value != null && !(value instanceof Component)
- && !(value instanceof String)) {
- // Avoid errors if a generator returns something
- // other than a Component or a String
- value = value.toString();
- }
- } else if (iscomponent[j]) {
- value = p.getValue();
- listenProperty(p, oldListenedProperties);
- } else if (p != null) {
- value = getPropertyValue(id, colids[j], p);
- /*
- * If returned value is Component (via fieldfactory
- * or overridden getPropertyValue) we excpect it to
- * listen property value changes. Otherwise if
- * property emits value change events, table will
- * start to listen them and refresh content when
- * needed.
- */
- if (!(value instanceof Component)) {
+ if (index < firstIndexNotInCache
+ && index >= pageBufferFirstIndex
+ && pageBuffer[CELL_GENERATED_ROW][indexInOldBuffer] == null) {
+ // we have data already in our cache,
+ // recycle it instead of fetching it via
+ // getValue/getPropertyValue
+ value = pageBuffer[CELL_FIRSTCOL + j][indexInOldBuffer];
+ if (!isGeneratedColumn && iscomponent[j]
+ || !(value instanceof Component)) {
listenProperty(p, oldListenedProperties);
}
} else {
- value = getPropertyValue(id, colids[j], null);
+ if (isGeneratedColumn) {
+ ColumnGenerator cg = columnGenerators
+ .get(colids[j]);
+ value = cg.generateCell(this, id, colids[j]);
+ if (value != null
+ && !(value instanceof Component)
+ && !(value instanceof String)) {
+ // Avoid errors if a generator returns
+ // something
+ // other than a Component or a String
+ value = value.toString();
+ }
+ } else if (iscomponent[j]) {
+ value = p.getValue();
+ listenProperty(p, oldListenedProperties);
+ } else if (p != null) {
+ value = getPropertyValue(id, colids[j], p);
+ /*
+ * If returned value is Component (via
+ * fieldfactory or overridden getPropertyValue)
+ * we excpect it to listen property value
+ * changes. Otherwise if property emits value
+ * change events, table will start to listen
+ * them and refresh content when needed.
+ */
+ if (!(value instanceof Component)) {
+ listenProperty(p, oldListenedProperties);
+ }
+ } else {
+ value = getPropertyValue(id, colids[j], null);
+ }
}
}
}
@@ -2919,6 +2941,7 @@ public class Table extends AbstractSelect implements Action.Container,
paintRowIcon(target, cells, indexInRowbuffer);
paintRowHeader(target, cells, indexInRowbuffer);
+ paintGeneratedRowInfo(target, cells, indexInRowbuffer);
target.addAttribute("key",
Integer.parseInt(cells[CELL_KEY][indexInRowbuffer].toString()));
@@ -2959,6 +2982,15 @@ public class Table extends AbstractSelect implements Action.Container,
paintRowAttributes(target, itemId);
}
+ private void paintGeneratedRowInfo(PaintTarget target, Object[][] cells,
+ int indexInRowBuffer) throws PaintException {
+ GeneratedRow generatedRow = (GeneratedRow) cells[CELL_GENERATED_ROW][indexInRowBuffer];
+ if (generatedRow != null) {
+ target.addAttribute("gen_html", generatedRow.isRenderAsHtml());
+ target.addAttribute("gen_span", generatedRow.isSpanColumns());
+ }
+ }
+
protected void paintRowHeader(PaintTarget target, Object[][] cells,
int indexInRowbuffer) throws PaintException {
if (rowHeadersAreEnabled()) {
@@ -4604,4 +4636,114 @@ public class Table extends AbstractSelect implements Action.Container,
return itemDescriptionGenerator;
}
+ public interface RowGenerator {
+ /**
+ * Called for every row that is painted in the Table. Returning a
+ * GeneratedRow object will cause the row to be painted based on the
+ * contents of the GeneratedRow. A generated row is by default styled
+ * similarly to a header or footer row.
+ * <p>
+ * The GeneratedRow data object contains the text that should be
+ * rendered in the row. The itemId in the container thus works only as a
+ * placeholder.
+ * <p>
+ * If GeneratedRow.setSpanColumns(true) is used, there will be one
+ * String spanning all columns (use setText("Spanning text")). Otherwise
+ * you can define one String per visible column.
+ * <p>
+ * If GeneratedRow.setRenderAsHtml(true) is used, the strings can
+ * contain HTML markup, otherwise all strings will be rendered as text
+ * (the default).
+ * <p>
+ * A "v-table-generated-row" CSS class is added to all generated rows.
+ * For custom styling of a generated row you can combine a RowGenerator
+ * with a CellStyleGenerator.
+ * <p>
+ *
+ * @param table
+ * The Table that is being painted
+ * @param itemId
+ * The itemId for the row
+ * @return A GeneratedRow describing how the row should be painted or
+ * null to paint the row with the contents from the container
+ */
+ public GeneratedRow generateRow(Table table, Object itemId);
+ }
+
+ public static class GeneratedRow {
+ private boolean renderAsHtml = false;
+ private boolean spanColumns = false;
+ private String[] text = null;
+
+ /**
+ * Creates a new generated row. If only one string is passed in, columns
+ * are automatically spanned.
+ *
+ * @param text
+ */
+ public GeneratedRow(String... text) {
+ setRenderAsHtml(false);
+ setSpanColumns(text.length == 1);
+ setText(text);
+ }
+
+ /**
+ * Pass one String if spanColumns is used, one String for each visible
+ * column otherwise
+ */
+ public void setText(String... text) {
+ this.text = text;
+ }
+
+ protected String[] getText() {
+ return text;
+ }
+
+ protected boolean isRenderAsHtml() {
+ return renderAsHtml;
+ }
+
+ /**
+ * If set to true, all strings passed to {@link #setText(String...)}
+ * will be rendered as HTML.
+ *
+ * @param renderAsHtml
+ */
+ public void setRenderAsHtml(boolean renderAsHtml) {
+ this.renderAsHtml = renderAsHtml;
+ }
+
+ protected boolean isSpanColumns() {
+ return spanColumns;
+ }
+
+ /**
+ * If set to true, only one string will be rendered, spanning the entire
+ * row.
+ *
+ * @param spanColumns
+ */
+ public void setSpanColumns(boolean spanColumns) {
+ this.spanColumns = spanColumns;
+ }
+ }
+
+ /**
+ * Assigns a row generator to the table. The row generator will be able to
+ * replace rows in the table when it is rendered.
+ *
+ * @param generator
+ * the new row generator
+ */
+ public void setRowGenerator(RowGenerator generator) {
+ rowGenerator = generator;
+ refreshRenderedCells();
+ }
+
+ /**
+ * @return the current row generator
+ */
+ public RowGenerator getRowGenerator() {
+ return rowGenerator;
+ }
}