From 380791902357c99196f4160bc39fccedf0fe0d2d Mon Sep 17 00:00:00 2001 From: Marc Englund Date: Wed, 18 Jun 2008 07:46:45 +0000 Subject: [PATCH] Initial commit for #1739, implements Table.addGeneratedColumn() svn changeset:4911/svn branch:trunk --- src/com/itmill/toolkit/ui/Table.java | 175 +++++++++++++++++++++++---- 1 file changed, 151 insertions(+), 24 deletions(-) diff --git a/src/com/itmill/toolkit/ui/Table.java b/src/com/itmill/toolkit/ui/Table.java index 10ad2238dc..0e46e74e88 100644 --- a/src/com/itmill/toolkit/ui/Table.java +++ b/src/com/itmill/toolkit/ui/Table.java @@ -179,6 +179,11 @@ public class Table extends AbstractSelect implements Action.Container, */ private final HashMap columnWidths = new HashMap(); + /** + * Holds column generators + */ + private final HashMap columnGenerators = new HashMap(); + /** * Holds value of property pageLength. 0 disables paging. */ @@ -319,13 +324,14 @@ public class Table extends AbstractSelect implements Action.Container, /* Table functionality ************************************************** */ /** - * Gets the array of visible column property id:s. + * Gets the array of visible column id:s, including generated columns. * *

* The columns are show in the order of their appearance in this array. *

* - * @return the Value of property availableColumns. + * @return an array of currently visible propertyIds and generated column + * ids. */ public Object[] getVisibleColumns() { if (visibleColumns == null) { @@ -357,15 +363,16 @@ public class Table extends AbstractSelect implements Action.Container, final Collection properties = getContainerPropertyIds(); for (int i = 0; i < visibleColumns.length; i++) { if (visibleColumns[i] == null) { - throw new NullPointerException("Properties must be non-nulls"); - } else if (!properties.contains(visibleColumns[i])) { + throw new NullPointerException("Ids must be non-nulls"); + } else if (!properties.contains(visibleColumns[i]) + && !columnGenerators.containsKey(visibleColumns[i])) { throw new IllegalArgumentException( - "Properties must exist in the Container, missing property: " + "Ids must exist in the Container or as a generated column , missing id: " + visibleColumns[i]); } } - // If this is called befor the constructor is finished, it might be + // If this is called before the constructor is finished, it might be // uninitialized final LinkedList newVC = new LinkedList(); for (int i = 0; i < visibleColumns.length; i++) { @@ -374,13 +381,19 @@ public class Table extends AbstractSelect implements Action.Container, // Removes alignments, icons and headers from hidden columns if (this.visibleColumns != null) { - for (final Iterator i = this.visibleColumns.iterator(); i.hasNext();) { - final Object col = i.next(); - if (!newVC.contains(col)) { - setColumnHeader(col, null); - setColumnAlignment(col, null); - setColumnIcon(col, null); + disableContentRefreshing(); + try { + for (final Iterator i = this.visibleColumns.iterator(); i + .hasNext();) { + final Object col = i.next(); + if (!newVC.contains(col)) { + setColumnHeader(col, null); + setColumnAlignment(col, null); + setColumnIcon(col, null); + } } + } finally { + enableContentRefreshing(false); } } @@ -1199,8 +1212,8 @@ public class Table extends AbstractSelect implements Action.Container, final int headmode = getRowHeaderMode(); final boolean[] iscomponent = new boolean[cols]; for (int i = 0; i < cols; i++) { - iscomponent[i] = Component.class - .isAssignableFrom(getType(colids[i])); + iscomponent[i] = columnGenerators.containsKey(colids[i]) + || Component.class.isAssignableFrom(getType(colids[i])); } int firstIndexNotInCache; if (pageBuffer != null && pageBuffer[CELL_ITEMID].length > 0) { @@ -1229,11 +1242,18 @@ public class Table extends AbstractSelect implements Action.Container, if (cols > 0) { for (int j = 0; j < cols; j++) { - final Property p = getContainerProperty(id, colids[j]); - Object value = null; + Property p = null; + Object value = ""; + boolean isGenerated = columnGenerators + .containsKey(colids[j]); + + if (!isGenerated) { + p = getContainerProperty(id, colids[j]); + } + // check in current pageBuffer already has row int index = firstIndex + i; - if (p != null) { + if (p != null || isGenerated) { if (p instanceof Property.ValueChangeNotifier) { if (oldListenedProperties == null || !oldListenedProperties.contains(p)) { @@ -1251,8 +1271,13 @@ public class Table extends AbstractSelect implements Action.Container, - pageBufferFirstIndex; value = pageBuffer[CELL_FIRSTCOL + j][indexInOldBuffer]; } else { + if (isGenerated) { + ColumnGenerator cg = (ColumnGenerator) columnGenerators + .get(colids[j]); + value = cg + .generateCell(this, id, colids[j]); - if (iscomponent[j]) { + } else if (iscomponent[j]) { value = p.getValue(); } else if (p != null) { value = getPropertyValue(id, colids[j], p); @@ -1261,8 +1286,6 @@ public class Table extends AbstractSelect implements Action.Container, null); } } - } else { - value = ""; } if (value instanceof Component) { @@ -1470,13 +1493,28 @@ public class Table extends AbstractSelect implements Action.Container, if (collapsedColumns != null) { collapsedColumns.clear(); } - setVisibleColumns(getContainerPropertyIds().toArray()); + + // columnGenerators 'override' properties, don't add the same id twice + Collection col = new LinkedList(); + for (Iterator it = getContainerPropertyIds().iterator(); it.hasNext();) { + Object id = it.next(); + if (columnGenerators == null || !columnGenerators.containsKey(id)) { + col.add(id); + } + } + // generators added last + if (columnGenerators != null && columnGenerators.size() > 0) { + col.addAll(columnGenerators.keySet()); + } + + setVisibleColumns(col.toArray()); // null value as we may not be sure that currently selected identifier // exits in new ds setValue(null); // Assure visual refresh + resetPageBuffer(); refreshRenderedCells(); } @@ -1739,9 +1777,13 @@ public class Table extends AbstractSelect implements Action.Container, for (final Iterator it = visibleColumns.iterator(); it.hasNext() && iscomponentIndex < iscomponent.length;) { final Object columnId = it.next(); - final Class colType = getType(columnId); - iscomponent[iscomponentIndex++] = colType != null - && Component.class.isAssignableFrom(colType); + if (columnGenerators.containsKey(columnId)) { + iscomponent[iscomponentIndex++] = true; + } else { + final Class colType = getType(columnId); + iscomponent[iscomponentIndex++] = colType != null + && Component.class.isAssignableFrom(colType); + } } target.startTag("rows"); // cells array contains all that are supposed to be visible on client, @@ -2234,6 +2276,66 @@ public class Table extends AbstractSelect implements Action.Container, return true; } + /** + * Adds a generated column to the Table. + *

+ * A generated column is a column that exists only in the Table, not as a + * property in the underlying Container. It shows up just as a regular + * column. + *

+ *

+ * A generated column will override a property with the same id, so that the + * generated column is shown instead of the column representing the + * property. Note that getContainerProperty() will still get the real + * property. + *

+ *

+ * Also note that getVisibleColumns() will return the generated columns, + * while getContainerPropertyIds() will not. + *

+ * + * @param id + * the id of the column to be added + * @param generatedColumn + * the {@link ColumnGenerator} to use for this column + */ + public void addGeneratedColumn(Object id, ColumnGenerator generatedColumn) { + if (generatedColumn == null) { + throw new IllegalArgumentException( + "Can not add null as a GeneratedColumn"); + } + if (columnGenerators.containsKey(id)) { + throw new IllegalArgumentException( + "Can not add the same GeneratedColumn twice, id:" + id); + } else { + columnGenerators.put(id, generatedColumn); + visibleColumns.add(id); + resetPageBuffer(); + refreshRenderedCells(); + } + } + + /** + * Removes a generated column previously added with addGeneratedColumn. + * + * @param id + * id of the generated column to remove + * @return true if the column could be removed (existed in the Table) + */ + public boolean removeGeneratedColumn(Object id) { + if (columnGenerators.containsKey(id)) { + columnGenerators.remove(id); + if (!items.containsId(id)) { + visibleColumns.remove(id); + } + resetPageBuffer(); + refreshRenderedCells(); + return true; + } else { + return false; + } + } + /** * Returns the list of items on the current page * @@ -2652,4 +2754,29 @@ public class Table extends AbstractSelect implements Action.Container, + super.toString(); } + /** + * Used to create "generated columns"; columns that exist only in the Table, + * not in the underlying Container. Implement this interface and pass it to + * Table.addGeneratedColumn along with an id for the column to be generated. + * + */ + public interface ColumnGenerator { + + /** + * Called by Table when a cell in a generated column needs to be + * generated. + * + * @param source + * the source Table + * @param itemId + * the itemId (aka rowId) for the of the cell to be + * generated + * @param columnId + * the id for the generated column (as specified in + * addGeneratedColumn) + * @return + */ + public abstract Component generateCell(Table source, Object itemId, + Object columnId); + } } \ No newline at end of file -- 2.39.5