Por que não existem exemplos decentes de CompositeCell em uso em uma CellTabl

Examinei o GoogleCode, o GWT ShowCase, as Notas do desenvolvedor do GWT e os Grupos do Google para saber como obter / definir valores de um CompositeCell. Não há um exemplo definitivo que explique como usá-lo em uma CellTabl

Vamos olhar para algum código ... primeiro uma classe abstrata ...

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);
}

}

E então uma implementação concreta ...

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;
}

}

Tenho uma oferta de energia (EnergyOfferDTO). Possui uma lista de pontos MW / preço (OfferPriceMWPairDTO). Eu quero renderizar uma grade em que por horas do dia eu possa ver até 10 curvas (as curvas são a coleção de pontos MW / Preço do dia). Quero que cada uma dessas colunas da curva contenha um par de campos de entrada (um para preço e outro para valor mw). Eu imagino, ei, crie colunas e células para cada uma delas e as junte em um CompositeCell. Quão difícil isso poderia ser

Decidi estender o CellTable (ou seja, ToggleableGrid) para poder encapsular a configuração, o estilo e o comportamento da placa da caldeira; também para definir um modo de exibição. O modo é consultado à medida que as colunas estão sendo construídas (consulte isInEditMode) para renderizar um TextCell ou um derivado concreto de AbstractInputCell, como TextInputCell. Também criei uma extensão para SelectionCell (ou seja, ReferenceDataBackedSelectionCell) para poder definir o valor de uma opção usando o ReferenceData. Colunas de entrada única funcionam! Eu posso exibi-los como texto ou como campo de entrada ou selecionar lista. É o CompositeCell que está me causando dores de cabeça.

Enquanto esse código renderizará os pares de campos de entrada corretamente, os valores estarão em branco (nulo), em branco ou em branc

Por favor, dê uma olhada no método addPriceMwColumn. Talvez você possa ver algo que eu não vejo

questionAnswers(2)

yourAnswerToTheQuestion