为什么在CellTable中没有使用CompositeCell的正确例子?

时间:2012-02-01 05:51:23

标签: gwt cell composite gwt-celltable

我已经搜索了GoogleCode,GWT ShowCase,GWT Developer Notes和Google Groups,以了解如何获取/设置CompositeCell的值。没有一个明确的例子可以解释如何在CellTable中使用它。

让我们盯着一些代码......首先是抽象类......

public abstract class ToggleableGrid<T> extends CellTable<T> {

private static final String DEFAULT_TABLE_WIDTH = "100%";
private static final DisplayMode DEFAULT_MODE = DisplayMode.VIEW;

protected void setDefaults() {
    setWidth(DEFAULT_TABLE_WIDTH);
    // Set the message to display when the table is empty.
    setEmptyTableWidget(new Label(UiMessages.INSTANCE.no_results()));
    // Add a selection model so we can select cells
    final SelectionModel<T> selectionModel = new MultiSelectionModel<T>();
    setSelectionModel(selectionModel, DefaultSelectionEventManager.<T> createDefaultManager());
}

public void setInput(List<T> content) {
    setInput(content, DEFAULT_MODE);
}

public void setInput(List<T> content, DisplayMode mode) {
    setDefaults();
    resetTableColumns();
    final ListDataProvider<T> dataProvider = new ListDataProvider<T>(content);
    final ListHandler<T> sortHandler = new ListHandler<T>(dataProvider.getList());
    addColumnSortHandler(sortHandler);
    initializeStructure(constructMetadata(), sortHandler, mode);
    dataProvider.addDataDisplay(this);
}

// see http://stackoverflow.com/questions/3772480/remove-all-columns-from-a-celltable
// concrete classes are forced to maintain a handle on all columns added
private void resetTableColumns() {
    for (final Column<T, ?> column: allColumns()) {
        removeColumn(column);
    }
    allColumns().clear();
}

public boolean isInEditMode(DisplayMode currentDisplayMode) {
    boolean result = false;
    if (currentDisplayMode == DisplayMode.EDIT) {
        result = true;
    }
    return result;
}

protected abstract Set<Column<T, ?>> allColumns();

protected abstract TableMetadata constructMetadata();

protected abstract void initializeStructure(TableMetadata metadata, ListHandler<T> sortHandler, DisplayMode mode);

protected void setColumnHorizontalAlignment(Column<T, ?> column, HorizontalAlignmentConstant alignment) {
    column.setHorizontalAlignment(alignment);
}

@Override
public void addColumn(Column<T, ?> column, String columnHeaderName) {
    final StringBuffer sb = new StringBuffer();
    sb.append("<div align=\"right\">").append(columnHeaderName).append("</div>");
    final SafeHtml header = new OnlyToBeUsedInGeneratedCodeStringBlessedAsSafeHtml(sb.toString());
    addColumn(column, header);
    allColumns().add(column);
}

}

然后是具体的实施......

public class EnergyOfferGrid extends ToggleableGrid<EnergyOfferDTO> {

private static final int MAX_NUMBER_OF_MW_PRICE_POINTS = 10;

private Set<Column<EnergyOfferDTO, ?>> columns = new HashSet<Column<EnergyOfferDTO, ?>>();

@Override
protected Set<Column<EnergyOfferDTO, ?>> allColumns() {
    return columns;
}

@Override
protected TableMetadata constructMetadata() {
    final TableMetadata metadata = new TableMetadata();

    // TODO Consider a predefined set of ReferenceData to be held in a common package

    // Use Slope
    metadata.addColumnMetadata(UiMessages.INSTANCE.use_slope(), new String[] {UiMessages.INSTANCE.yes(), UiMessages.INSTANCE.no()}, new String[] {"true", "false"});

    return metadata;
}

@Override
protected void initializeStructure(TableMetadata metadata, ListHandler<EnergyOfferDTO> sortHandler, DisplayMode currentDisplayMode) {
    addHourColumn(sortHandler);
    addUseSlopeColumn(metadata, sortHandler, currentDisplayMode);
    for (int i = 1; i <= MAX_NUMBER_OF_MW_PRICE_POINTS; i++) {
        addPriceMwColumn(i, currentDisplayMode);
    }
}

protected void addHourColumn(ListHandler<EnergyOfferDTO> sortHandler) {
    final Column<EnergyOfferDTO, String> hourColumn = new Column<EnergyOfferDTO, String>(new TextCell()) {

        @Override
        public String getValue(EnergyOfferDTO energyOffer) {
            String result = "";
            final String isoDateTime = energyOffer.getDateTime();
            if (isoDateTime != null && !isoDateTime.isEmpty()) {
                final Date dateTime = TimeUtil.isoToDate(isoDateTime);
                if (dateTime != null) {
                    result = TimeUtil.dateToHour(dateTime);
                }
            }
            return result;
        }

    };
    hourColumn.setSortable(true);
    sortHandler.setComparator(hourColumn, new Comparator<EnergyOfferDTO>() {
        @Override
        public int compare(EnergyOfferDTO eo1, EnergyOfferDTO eo2) {
            return eo1.getDateTime().compareTo(eo2.getDateTime());
        }
    });

    addColumn(hourColumn, UiMessages.INSTANCE.hour());
    setColumnWidth(hourColumn, 10, Unit.PCT);
    setColumnHorizontalAlignment(hourColumn, HasHorizontalAlignment.ALIGN_RIGHT);
}


protected void addUseSlopeColumn(TableMetadata metadata, ListHandler<EnergyOfferDTO> sortHandler, DisplayMode currentDisplayMode) {
    final ReferenceData refData = metadata.allColumnMetadata().get(UiMessages.INSTANCE.use_slope());
    Column<EnergyOfferDTO, String> useSlopeColumn;
    Cell<String> cell;
    if (isInEditMode(currentDisplayMode)) {
        cell = new ReferenceDataBackedSelectionCell(refData);
    } else {
        cell = new TextCell();
    }
    useSlopeColumn = new Column<EnergyOfferDTO, String>(cell) {

        @Override
        public String getValue(EnergyOfferDTO energyOffer) {
            return refData.getDisplayValueForSubmitValue(Boolean.toString(energyOffer.isSlope()));
        }

    };

    useSlopeColumn.setSortable(true);
    sortHandler.setComparator(useSlopeColumn, new Comparator<EnergyOfferDTO>() {
        @Override
        public int compare(EnergyOfferDTO eo1, EnergyOfferDTO eo2) {
            return eo1.getDateTime().compareTo(eo2.getDateTime());
        }
    });

    addColumn(useSlopeColumn, UiMessages.INSTANCE.use_slope());
    setColumnWidth(useSlopeColumn, 10, Unit.PCT);
    setColumnHorizontalAlignment(useSlopeColumn, HasHorizontalAlignment.ALIGN_RIGHT);
}

protected void addPriceMwColumn(final int colIndex, DisplayMode currentDisplayMode) {

    // Construct a composite cell for energy offers that includes a pair of text inputs
    final List<HasCell<EnergyOfferDTO, ?>> hasCells = new ArrayList<
            HasCell<EnergyOfferDTO, ?>>();

    // this DTO is passed along so that price and mw values for new entries are kept together
    final OfferPriceMwPairDTO newOfferPriceMwPairDTO = new OfferPriceMwPairDTO();

    // Price
    final HasCell<EnergyOfferDTO, String> priceCell = generatePriceCell(colIndex, newOfferPriceMwPairDTO, currentDisplayMode);
    hasCells.add(priceCell);

    // MW
    final HasCell<EnergyOfferDTO, String> mwCell = generateMwCell(colIndex, newOfferPriceMwPairDTO, currentDisplayMode);
    hasCells.add(mwCell);

    // Composite
    final CompositeCell<EnergyOfferDTO> priceMwCell = generateCompositeCell(hasCells);

    final Column<EnergyOfferDTO, EnergyOfferDTO> priceMwColumn = new Column<EnergyOfferDTO, EnergyOfferDTO>(priceMwCell) {

        @Override
        public EnergyOfferDTO getValue(EnergyOfferDTO energyOffer) {
            // we do this to satisfy the anonymous type's contract,
            // but know that this column's composite cell delegates to its individual cell impls to get a value
            return null;
        }

    };

    addColumn(priceMwColumn, String.valueOf(colIndex));
    setColumnWidth(priceMwColumn, 8, Unit.PCT);
    setColumnHorizontalAlignment(priceMwColumn, HasHorizontalAlignment.ALIGN_RIGHT);
}

protected HasCell<EnergyOfferDTO, String> generatePriceCell(final int colIndex, final OfferPriceMwPairDTO newOfferPriceMwPair, DisplayMode currentDisplayMode) {
    HasCell<EnergyOfferDTO, String> priceCell;

    if (isInEditMode(currentDisplayMode)) {
        priceCell = new HasCell<EnergyOfferDTO, String>() {

            private TextInputCell cell = new TextInputCell();

            @Override
            public Cell<String> getCell() {
                return cell;
            }

            @Override
            public FieldUpdater<EnergyOfferDTO, String> getFieldUpdater() {
                return new FieldUpdater<EnergyOfferDTO, String>() {
                    @Override
                    public void update(int index, EnergyOfferDTO energyOffer, String value) {
                        if (value != null && !value.isEmpty()) {
                            // number format exceptions should be caught and handled by event bus's handle method
                            final double valueAsDouble = NumberFormat.getDecimalFormat().parse(value);

                            final BigDecimal price = BigDecimal.valueOf(valueAsDouble);
                            final List<OfferPriceMwPairDTO> offerPriceCurve = energyOffer.getOfferPriceCurve();
                            final OfferPriceMwPairDTO offerPriceMwPairDTO = offerPriceCurve.get(colIndex);
                            if (offerPriceMwPairDTO == null) {  // we have a new price value
                                newOfferPriceMwPair.setPrice(price);
                                offerPriceCurve.add(newOfferPriceMwPair);
                            } else {
                                offerPriceMwPairDTO.setPrice(price);
                            }

                        }
                    }
                };
            }

            @Override
            public String getValue(EnergyOfferDTO energyOffer) {
                String result = "";
                if (energyOffer != null) {
                    final List<OfferPriceMwPairDTO> offerPriceCurve = energyOffer.getOfferPriceCurve();
                    final OfferPriceMwPairDTO offerPriceMwPairDTO = offerPriceCurve.get(colIndex);
                    if (offerPriceMwPairDTO != null) {
                        final BigDecimal price = offerPriceMwPairDTO.getPrice();
                        result = String.valueOf(price.doubleValue());
                    }
                }
                return result;
            }
        };
    } else {
        priceCell = new Column<EnergyOfferDTO, String>(new TextCell()) {

            @Override
            public String getValue(EnergyOfferDTO energyOffer) {
                String result = "";
                if (energyOffer != null) {
                    final List<OfferPriceMwPairDTO> offerPriceCurve = energyOffer.getOfferPriceCurve();
                    final OfferPriceMwPairDTO offerPriceMwPairDTO = offerPriceCurve.get(colIndex);
                    if (offerPriceMwPairDTO != null) {
                        final BigDecimal price = offerPriceMwPairDTO.getPrice();
                        result = String.valueOf(price.doubleValue());
                    }
                }
                return result;
            }
        };
    }
    return priceCell;
}

protected HasCell<EnergyOfferDTO, String> generateMwCell(final int colIndex, final OfferPriceMwPairDTO newOfferPriceMwPair, DisplayMode currentDisplayMode) {
    HasCell<EnergyOfferDTO, String> mwCell;

    if (isInEditMode(currentDisplayMode)) {
        mwCell = new HasCell<EnergyOfferDTO, String>() {

            private TextInputCell cell = new TextInputCell();

            @Override
            public Cell<String> getCell() {
                return cell;
            }

            @Override
            public FieldUpdater<EnergyOfferDTO, String> getFieldUpdater() {
                return new FieldUpdater<EnergyOfferDTO, String>() {
                    @Override
                    public void update(int index, EnergyOfferDTO energyOffer, String value) {
                        if (value != null && !value.isEmpty()) {
                            // number format exceptions should be caught and handled by event bus's handle method
                            final double valueAsDouble = NumberFormat.getDecimalFormat().parse(value);

                            final BigDecimal mw = BigDecimal.valueOf(valueAsDouble);
                            final List<OfferPriceMwPairDTO> offerPriceCurve = energyOffer.getOfferPriceCurve();
                            final OfferPriceMwPairDTO offerPriceMwPairDTO = offerPriceCurve.get(colIndex);
                            if (offerPriceMwPairDTO == null) {  // we have a new mw value
                                newOfferPriceMwPair.setMw(mw);
                                offerPriceCurve.add(newOfferPriceMwPair);
                            } else {
                                offerPriceMwPairDTO.setMw(mw);
                            }

                        }
                    }
                };
            }

            @Override
            public String getValue(EnergyOfferDTO energyOffer) {
                String result = "";
                if (energyOffer != null) {
                    final List<OfferPriceMwPairDTO> offerPriceCurve = energyOffer.getOfferPriceCurve();
                    final OfferPriceMwPairDTO offerPriceMwPairDTO = offerPriceCurve.get(colIndex);
                    if (offerPriceMwPairDTO != null) {
                        final BigDecimal mw = offerPriceMwPairDTO.getMw();
                        result = String.valueOf(mw.doubleValue());
                    }
                }
                return result;
            }
        };
    } else {
        mwCell = new Column<EnergyOfferDTO, String>(new TextCell()) {

            @Override
            public String getValue(EnergyOfferDTO energyOffer) {
                String result = "";
                if (energyOffer != null) {
                    final List<OfferPriceMwPairDTO> offerPriceCurve = energyOffer.getOfferPriceCurve();
                    final OfferPriceMwPairDTO offerPriceMwPairDTO = offerPriceCurve.get(colIndex);
                    if (offerPriceMwPairDTO != null) {
                        final BigDecimal mw = offerPriceMwPairDTO.getMw();
                        result = String.valueOf(mw.doubleValue());
                    }
                }
                return result;
            }
        };
    }
    return mwCell;
}

protected CompositeCell<EnergyOfferDTO> generateCompositeCell(final List<HasCell<EnergyOfferDTO, ?>> hasCells) {
    final CompositeCell<EnergyOfferDTO> compositeCell = new CompositeCell<EnergyOfferDTO>(hasCells) {

        @Override
        public void render(Context context, EnergyOfferDTO value, SafeHtmlBuilder sb) {
            sb.appendHtmlConstant("<table><tbody><tr>");
            for (final HasCell<EnergyOfferDTO, ?> hasCell : hasCells) {
                render(context, value, sb, hasCell);
            }
            sb.appendHtmlConstant("</tr></tbody></table>");
        }

        @Override
        protected Element getContainerElement(Element parent) {
            // Return the first TR element in the table.
            return parent.getFirstChildElement().getFirstChildElement().getFirstChildElement();
        }

        @Override
        protected <X> void render(Context context, EnergyOfferDTO value,
                SafeHtmlBuilder sb, HasCell<EnergyOfferDTO, X> hasCell) {
            final Cell<X> cell = hasCell.getCell();
            sb.appendHtmlConstant("<td>");
            cell.render(context, hasCell.getValue(value), sb);
            sb.appendHtmlConstant("</td>");
        }
    };
    return compositeCell;
}

}

我有能量供应(EnergyOfferDTO)。它有一个MW /价格点列表(OfferPriceMWPairDTO)。我想渲染一个网格,在那里我可以看到最多10条曲线(曲线是当天的MW /价格点的集合)。我希望每个曲线列都包含一对输入字段(一个用于价格,一个用于mw值)。我想,嘿,为每个创建列和单元格,然后在CompositeCell中将它们组合在一起。这有多难?

我决定扩展CellTable(即ToggleableGrid),以便我可以封装样板设置,样式和行为;以及设置显示模式。在构建列时(参见isInDditMode),可以查询模式以呈现TextInell或AbstractInputCell的具体派生,如TextInputCell。我还为SelectionCell创建了一个扩展(即ReferenceDataBackedSelectionCell),以便我可以使用ReferenceData设置选项的值。单输入列工作!我可以将它们显示为文本或输入字段或选择列表。这就是复合细胞,这让我感到头痛。

虽然此代码将正确呈现输入字段对,但值均为空(空),空白文本或空白输入字段对。

请注意addPriceMwColumn方法。也许你可以看到我没有的东西?

1 个答案:

答案 0 :(得分:2)

是否可以像在列中EnergyOfferDTO而不是null返回一样简单? (您可能希望使用IdentityColumn

您在代码中的注释中说复合单元格将委托给其单元格,但是列的责任是首先将值赋予复合单元格,然后复合单元格将调用每个{{ 1}}从传递给复合单元格的值中提取内部单元格的值。

作为旁注,您的复合单元格的HasCell方法不应该遍历render列表,它应该只调用hasCells(当然还是装饰它与您的super.render(context, value, sb)电话)将完成这项工作。