]> source.dussan.org Git - vaadin-framework.git/commitdiff
Initial commit for #1739, implements Table.addGeneratedColumn()
authorMarc Englund <marc.englund@itmill.com>
Wed, 18 Jun 2008 07:46:45 +0000 (07:46 +0000)
committerMarc Englund <marc.englund@itmill.com>
Wed, 18 Jun 2008 07:46:45 +0000 (07:46 +0000)
svn changeset:4911/svn branch:trunk

src/com/itmill/toolkit/ui/Table.java

index 10ad2238dcf2775e35f78db3ca2d4ed0cd17b649..0e46e74e88d28d694ceabc0bfaf035a0f495af8d 100644 (file)
@@ -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.
      * 
      * <p>
      * The columns are show in the order of their appearance in this array.
      * </p>
      * 
-     * @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.
+     * <p>
+     * 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.
+     * </p>
+     * <p>
+     * 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.
+     * </p>
+     * <p>
+     * Also note that getVisibleColumns() will return the generated columns,
+     * while getContainerPropertyIds() will not.
+     * </p>
+     * 
+     * @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