У меня есть тип значения Commission
, который является частью более крупного графа редактора:
public class Commission implements Serializable
{
private CommissionType commissionType; // enum
private Money value; // custom type, backed by BigDecimal
private Integer multiplier;
private Integer contractMonths;
// ...
}
Чего я хочу добиться, так это сначала показать раскрывающийся список только для перечисления commissionType
, а затем выбрать соответствующий вспомогательный редактор для редактирования остальных полей на основе выбранного значения:
Ранее я реализовал несколько редакторов подтипов (см. вопрос здесь) с использованием AbstractSubTypeEditor
, но этот случай немного отличается, поскольку я не редактирую подклассы, все они редактируют один и тот же базовый тип Commission
, и по какой-то причине один и тот же метод не работает с несколькими редакторами, которые редактируют один и тот же конкретный тип. .
В настоящее время у меня есть два подредактора (оба реализуют Editor<Commission>
и IsWidget
через настраиваемый интерфейс IsCommissionEditorWidget
), но сами они имеют разные подредакторы, так как Money
может быть в пенсах или фунтах, а множитель может представлять дни или месяцы, помимо прочего. изменения.
КомиссияРедактор
Я рассмотрел аналогичную проблему в этом вопросе и попытался создать CompositeEditor<Commission, Commission, Editor<Commission>>
.
Это то, что у меня есть до сих пор (обратите внимание, что закомментированные части — это взломанный способ получения желаемой функциональности путем реализации LeafValueEditor<Commission>
и ручного вызова setValue()
и getValue()
для amount
, multiplier
и contractMonths
):
public class CommissionEditor extends Composite implements CompositeEditor<Commission, Commission, Editor<Commission>>, //LeafValueEditor<Commission>
{
interface Binder extends UiBinder<HTMLPanel, CommissionEditor>
{
}
private static Binder uiBinder = GWT.create(Binder.class);
@UiField
CommissionTypeEditor commissionType;
@UiField
Panel subEditorPanel;
private EditorChain<Commission, Editor<Commission>> chain;
private IsCommissionEditorWidget subEditor = null;
private Commission value = new Commission();
public CommissionEditor()
{
initWidget(uiBinder.createAndBindUi(this));
commissionType.box.addValueChangeHandler(event -> setValue(new Commission(event.getValue())));
}
@Override
public void setValue(Commission value)
{
Log.warn("CommissionEditor -> setValue(): value is " + value);
chain.detach(subEditor);
commissionType.setValue(value.getCommissionType());
if(value.getCommissionType() != null)
{
switch(value.getCommissionType())
{
case UNIT_RATE:
Log.info("UNIT_RATE");
subEditor = new UnitRateCommissionEditor();
break;
case STANDING_CHARGE:
Log.info("STANDING_CHARGE");
subEditor = new StandingChargeCommissionEditor();
break;
case PER_MWH:
Log.info("PER_MWH");
// TODO
break;
case SINGLE_PAYMENT:
Log.info("SINGLE_PAYMENT");
// TODO
break;
}
this.value = value;
subEditorPanel.clear();
// subEditor.setValue(value);
subEditorPanel.add(subEditor);
chain.attach(value, subEditor);
}
}
// @Override
// public Commission getValue()
// {
// if(subEditor != null)
// {
// return subEditor.getValue();
// }
// else
// {
// return value;
// }
// }
@Override
public void flush()
{
this.value = chain.getValue(subEditor);
}
@Override
public void setEditorChain(EditorChain<Commission, Editor<Commission>> chain)
{
this.chain = chain;
}
@Override
public Editor<Commission> createEditorForTraversal()
{
return subEditor;
}
@Override
public String getPathElement(Editor<Commission> commissionEditor)
{
return "";
}
@Override
public void onPropertyChange(String... strings)
{
}
@Override
public void setDelegate(EditorDelegate<Commission> editorDelegate)
{
}
}
Это интерфейс IsCommissionEditorWidget
, который определяет контракт каждого субредактора, который также может быть добавлен на панель:
public interface IsCommissionEditorWidget extends Editor<Commission>, IsWidget
{
}
UnitRateCommissionEditor
Когда пользователь выбирает CommissionType.UNIT_RATE
, я хочу добавить это в цепочку редактора, чтобы применить к 3 оставшимся полям:
public class UnitRateCommissionEditor extends Composite implements IsCommissionEditorWidget
{
interface Binder extends UiBinder<Widget, UnitRateCommissionEditor>
{
}
private static Binder uiBinder = GWT.create(Binder.class);
@UiField
MoneyPenceBox amount;
@UiField
IntegerBox multiplier;
@UiField
IntegerBox contractMonths;
public UnitRateCommissionEditor()
{
initWidget(uiBinder.createAndBindUi(this));
}
// @Override
// public void setValue(Commission commission)
// {
// amount.setValue(commission.getAmount());
// multiplier.setValue(commission.getMultiplier());
// contractMonths.setValue(commission.getContractMonths());
// }
//
// @Override
// public Commission getValue()
// {
// return new Commission(CommissionType.UNIT_RATE, amount.getValue(), multiplier.getValue(), contractMonths.getValue());
// }
}
Постоянная комиссияРедактор
Когда выбрано CommissionType.STANDING_CHARGE
, я хочу это (UiBinders также немного отличаются, но основное отличие заключается в MoneyPoundsBox
вместо MoneyPenceBox
):
public class StandingChargeCommissionEditor extends Composite implements IsCommissionEditorWidget
{
interface Binder extends UiBinder<Widget, StandingChargeCommissionEditor>
{
}
private static Binder uiBinder = GWT.create(Binder.class);
@UiField
MoneyPoundsBox amount;
@UiField
IntegerBox multiplier;
@UiField
IntegerBox contractMonths;
public StandingChargeCommissionEditor()
{
initWidget(uiBinder.createAndBindUi(this));
}
// @Override
// public void setValue(Commission commission)
// {
// amount.setValue(commission.getAmount());
// multiplier.setValue(commission.getMultiplier());
// contractMonths.setValue(commission.getContractMonths());
// }
//
// @Override
// public Commission getValue()
// {
// return new Commission(CommissionType.STANDING_CHARGE, amount.getValue(), multiplier.getValue(), contractMonths.getValue());
// }
}
В настоящее время flush()
родительского типа (редактируемый тип, содержащий Commission
) возвращает комиссию с неопределенными amount
, multiplier
и contractMonths
. Единственный способ, которым я могу получить эти значения для передачи и вывода, — это вручную закодировать их (закомментированный код).
- Правильно ли мой помощник прикреплен к
EditorChain
?
Редактировать 1: Предлагаемое решение
Я решил создать новый промежуточный класс, который будет обертывать каждую комиссию подтипа отдельно, -type/13358890#13358890">используя AbstractSubTypeEditor
как в этом вопросе.
КомиссияРедактор
По-прежнему CompositeEditor
, но у него всегда есть только один или ноль субредакторов, которые всегда будут только CommissionSubtypeEditor
:
public class CommissionEditor extends Composite implements CompositeEditor<Commission, Commission, CommissionSubtypeEditor>, LeafValueEditor<Commission>
{
interface Binder extends UiBinder<HTMLPanel, CommissionEditor>
{
}
private static Binder uiBinder = GWT.create(Binder.class);
@UiField
@Ignore
CommissionTypeEditor commissionType;
@UiField
Panel subEditorPanel;
private EditorChain<Commission, CommissionSubtypeEditor> chain;
@Ignore
@Path("")
CommissionSubtypeEditor subEditor = new CommissionSubtypeEditor();
private Commission value;
public CommissionEditor()
{
initWidget(uiBinder.createAndBindUi(this));
commissionType.box.addValueChangeHandler(event -> setValue(new Commission(event.getValue())));
}
@Override
public void setValue(Commission value)
{
Log.warn("CommissionEditor -> setValue(): value is " + value);
commissionType.setValue(value.getCommissionType());
if(value.getCommissionType() != null)
{
this.value = value;
subEditorPanel.clear();
subEditorPanel.add(subEditor);
chain.attach(value, subEditor);
}
}
@Override
public Commission getValue()
{
Log.info("CommissionEditor -> getValue: " + value);
return value;
}
@Override
public void flush()
{
chain.getValue(subEditor);
}
@Override
public void setEditorChain(EditorChain<Commission, CommissionSubtypeEditor> chain)
{
this.chain = chain;
}
@Override
public CommissionSubtypeEditor createEditorForTraversal()
{
return subEditor;
}
@Override
public String getPathElement(CommissionSubtypeEditor commissionEditor)
{
return "";
}
@Override
public void onPropertyChange(String... strings)
{
}
@Override
public void setDelegate(EditorDelegate<Commission> editorDelegate)
{
}
}
АннотацияSubTypeEditor
Кредит принадлежит Florent Bayle для этого класса. Я не думал, что смогу использовать его без полиморфных подтипов, но, похоже, он отлично работает. По сути, позволяет обертывать подредакторы, как будет показано в CommissionSubtypeEditor
далее.
public abstract class AbstractSubTypeEditor<T, C extends T, E extends Editor<C>> implements CompositeEditor<T, C, E>, LeafValueEditor<T>
{
private EditorChain<C, E> chain;
private T currentValue;
private final E subEditor;
public AbstractSubTypeEditor(E subEditor)
{
this.subEditor = subEditor;
}
@Override
public E createEditorForTraversal()
{
return subEditor;
}
@Override
public void flush()
{
currentValue = chain.getValue(subEditor);
}
@Override
public String getPathElement(E subEditor)
{
return "";
}
@Override
public T getValue()
{
return currentValue;
}
@Override
public void onPropertyChange(String... paths)
{
}
@Override
public void setDelegate(EditorDelegate<T> delegate)
{
}
@Override
public void setEditorChain(EditorChain<C, E> chain)
{
this.chain = chain;
}
public void setValue(T value, boolean instanceOf)
{
if(currentValue != null && value == null)
{
chain.detach(subEditor);
}
currentValue = value;
if(value != null && instanceOf)
{
chain.attach((C) value, subEditor);
}
}
}
КомиссияПодтипРедактор
public class CommissionSubtypeEditor extends Composite implements Editor<Commission>
{
interface Binder extends UiBinder<HTMLPanel, CommissionSubtypeEditor>
{
}
private static Binder uiBinder = GWT.create(Binder.class);
@UiField
Panel subEditorPanel;
@Ignore
final UnitRateCommissionEditor unitRateCommissionEditor = new UnitRateCommissionEditor();
@Path("")
final AbstractSubTypeEditor<Commission, Commission, UnitRateCommissionEditor> unitRateWrapper = new AbstractSubTypeEditor<Commission, Commission,
UnitRateCommissionEditor>(unitRateCommissionEditor)
{
@Override
public void setValue(Commission value)
{
if(value.getCommissionType() == CommissionType.UNIT_RATE)
{
Log.info("unitRateWrapper setValue");
setValue(value, true);
subEditorPanel.clear();
subEditorPanel.add(unitRateCommissionEditor);
}
}
};
@Ignore
final StandingChargeCommissionEditor standingChargeCommissionEditor = new StandingChargeCommissionEditor();
@Path("")
final AbstractSubTypeEditor<Commission, Commission, StandingChargeCommissionEditor> standingChargeWrapper = new AbstractSubTypeEditor<Commission,
Commission, StandingChargeCommissionEditor>(standingChargeCommissionEditor)
{
@Override
public void setValue(Commission value)
{
if(value.getCommissionType() == CommissionType.STANDING_CHARGE)
{
Log.info("standingChargeWrapper setValue");
setValue(value, true);
subEditorPanel.clear();
subEditorPanel.add(standingChargeCommissionEditor);
}
}
};
public CommissionSubtypeEditor()
{
initWidget(uiBinder.createAndBindUi(this));
}
}
UnitRateCommissionEditor и StandingChargeCommissionEditor
И просто, и реализуемо Editor<Commission>
:
public class UnitRateCommissionEditor extends Composite implements Editor<Commission>
{
interface Binder extends UiBinder<Widget, UnitRateCommissionEditor>
{
}
private static Binder uiBinder = GWT.create(Binder.class);
@UiField
MoneyPenceBox amount;
@UiField
IntegerBox multiplier;
@UiField
IntegerBox contractMonths;
public UnitRateCommissionEditor()
{
initWidget(uiBinder.createAndBindUi(this));
}
}
почти готово...
public class StandingChargeCommissionEditor extends Composite implements Editor<Commission>
{
interface Binder extends UiBinder<Widget, StandingChargeCommissionEditor>
{
}
private static Binder uiBinder = GWT.create(Binder.class);
@UiField
MoneyPoundsBox amount;
@UiField
IntegerBox multiplier;
@UiField
IntegerBox contractMonths;
public StandingChargeCommissionEditor()
{
initWidget(uiBinder.createAndBindUi(this));
}
}
Это действительно работает и похоже на то, что я пробовал очень рано, когда у меня были AbstractSubtypeEditor
в самом CompositeEditor
. Я считаю, что проблема заключалась в том, что редактор не мог вызвать setValue()
сам по себе. Я прав?