GWT嵌套编辑器 - 未正确刷新或检测到周期错误

时间:2016-10-06 20:22:55

标签: gwt uibinder gwt-editors

我正在创建一个与此类似的规则构建器:

enter image description here

可以有两种类型的规则对象:

  • JoinMetadataCondition :这包含联接类型("和"或"或")以及要加入的其他元数据条件列表
  • LeafMetadataCondition :这包含规则定义(变量,运算符,值)

这两个条件都实现了 MetadataCondition 接口。

方法1

我已经使用了三个不同的编辑器来尝试编辑规则,但我得到一个周期检测错误,这在规则是递归时是有意义的。以下是三位编辑。

MetadataConditionEditor

这使用描述为herehere

的AbstractSubTypeEditor

这是规则编辑器的切入点。它将被赋予顶级元数据条件,并从那里附加相关编辑器。

public class MetadataConditionEditor extends Composite implements Editor<MetadataCondition> {
interface Binder extends UiBinder<Widget, MetadataConditionEditor> {}

@Ignore
final JoinMetadataConditionEditor joinMetadataEditor = LibsFactory.injector().getJoinMetadataConditionEditor();

@Path("")
final AbstractSubTypeEditor<MetadataCondition, JoinMetadataCondition, JoinMetadataConditionEditor> joinMetadataEditorWrapper =
    new AbstractSubTypeEditor<MetadataCondition, JoinMetadataCondition, JoinMetadataConditionEditor>( joinMetadataEditor ) {
        @Override
        public void setValue( final MetadataCondition value )
        {
            setValue( value, isJoinMetadataCondition( value ) );
            if( isJoinMetadataCondition( value ) ) {
                container.clear();
                container.add( joinMetadataEditor );
            }
        }
};


@Ignore
final LeafMetadataConditionEditor leafMetadataEditor = LibsFactory.injector().getLeafMetadataConditionEditor();

@Path("")
final AbstractSubTypeEditor<MetadataCondition, LeafMetadataCondition, LeafMetadataConditionEditor> leafMetadataEditorWrapper =
    new AbstractSubTypeEditor<MetadataCondition, LeafMetadataCondition, LeafMetadataConditionEditor>( leafMetadataEditor ) {
        @Override
        public void setValue( final MetadataCondition value )
        {
            setValue( value, !isJoinMetadataCondition( value ) );
            if( !isJoinMetadataCondition( value ) ) {
                container.clear();
                container.add( leafMetadataEditor );
            }
        }
};


@UiField @Ignore SimplePanel container;


public MetadataConditionEditor() {
    initWidget( GWT.<Binder> create(Binder.class).createAndBindUi( this ) );
}


private Boolean isJoinMetadataCondition( MetadataCondition value ) {
    return value instanceof JoinMetadataCondition;
}}

JoinMetadataConditionEditor

用于编辑JoinMetadataCondition对象

public class JoinMetadataConditionEditor extends Composite implements Editor {     界面Binder扩展了UiBinder {}

@UiField @Ignore FlowPanel container;

@UiField
@Path( "type" )
ManualSelectEditor type;

@Path( "conditions" )
ListEditor<MetadataCondition, MetadataConditionEditor> conditions;


public JoinMetadataConditionEditor() {
    initWidget( GWT.<Binder> create(Binder.class).createAndBindUi( this ) );

    conditions = ListEditor.of( new MetadataEditorSource() );
    type.setSelectOptions( EditorConstants.metadataJoins );
}


private class MetadataEditorSource extends EditorSource<MetadataConditionEditor>
{
    @Override
    public MetadataConditionEditor create( int index )
    {
        final MetadataConditionEditor subEditor = new MetadataConditionEditor();

        container.insert( subEditor, index );

        return subEditor;
    }

    public void dispose( MetadataConditionEditor subEditor ) {
        container.remove( subEditor );
    }
}}

LeafMetadataConditionEditor

最后编辑器用于LeafMetadataCondition

public class LeafMetadataConditionEditor extends Composite implements Editor<LeafMetadataCondition> {
    interface Binder extends UiBinder<Widget, LeafMetadataConditionEditor> {}

    @UiField TextBoxEditor name;
    @UiField TextBoxEditor value;
    @UiField ManualSelectEditor operator;


    public LeafMetadataConditionEditor() {
        initWidget(GWT.<Binder> create(Binder.class).createAndBindUi(this));
        operator.setSelectOptions( EditorConstants.metadataOperators );
    }
}

问题

问题是:如何避免循环检测到的错误或以有效的方式构建此递归?

注意:我愿意接受新方法。我已经尝试了一些其他路线,例如为每个子编辑器初始化驱动程序并使它们都成为CompositeEditor。这是编译和加载的,但是当需要刷新驱动程序时,尽管似乎调用了flush()方法但是父编辑器没有使用这些值,因此子编辑器值没有被正确构造。

方法2

第二种方法涉及使用CompositeEditor并让子编辑器创建自己的驱动程序,然后刷新以创建最终结果。

MetadataConditionEditor

public class MetadataConditionEditor extends Composite implements
                            CompositeEditor<MetadataCondition, MetadataCondition, SimpleDriverEditor<MetadataCondition>>,
                            LeafValueEditor<MetadataCondition>
{
    interface Binder extends UiBinder<Widget, MetadataConditionEditor> {}

//    private SimpleBeanEditorDriver<MetadataCondition, ? extends Editor<MetadataCondition>> subDriver;
    private EditorChain<MetadataCondition, SimpleDriverEditor<MetadataCondition>> chain;
    private SimpleDriverEditor<MetadataCondition> subEditor;
    private EditorDelegate<MetadataCondition> delegate;
    private MetadataCondition value;

    @UiField @Ignore SimplePanel container;


    public MetadataConditionEditor() {
        initWidget( GWT.<Binder> create(Binder.class).createAndBindUi( this ) );
    }


    @Override
    public void flush()
    {
        if( Utils.isNull( subEditor ) )
            return;

        GWT.log( "----- flush-pre - " + System.identityHashCode(this) + " - " + value );// TODO

        value = subEditor.flush();

        GWT.log( "----- flush-post-1 - " + System.identityHashCode(this) + " - " + value.toJson() );// TODO

    }

    @Override
    public void onPropertyChange(String... paths) {}

    @Override
    @SuppressWarnings("unchecked")
    public void setValue( MetadataCondition value )
    {
        this.value = value;
//        subDriver = null;

        if( Utils.isNull( value ) )
            return;

        GWT.log( "----- setValue - " + value );// TODO

        if( value instanceof JoinMetadataCondition ) {
            SimpleDriverEditor<JoinMetadataCondition> newSubEditor = LibsFactory.injector().getJoinMetadataConditionEditor();
            SimpleDriverEditor<? extends MetadataCondition> newSubEditor1 = newSubEditor;
            subEditor = (SimpleDriverEditor<MetadataCondition>) newSubEditor1;

            newSubEditor.edit( (JoinMetadataCondition) value );
        }

        container.clear();
        container.add( subEditor );
    }

    @Override
    public void setDelegate( EditorDelegate<MetadataCondition> delegate ) {
        GWT.log( "----- setDelegate - " + delegate );// TODO
        this.delegate = delegate;
    }

    @Override
    public MetadataCondition getValue() {
        GWT.log( "----- getValue - " + System.identityHashCode(this) + " - " + value );// TODO
        return value;
    }

    @Override
    public SimpleDriverEditor<MetadataCondition> createEditorForTraversal() {
        GWT.log( "----- createEditorForTraversal - " + subEditor );// TODO
        return subEditor;
    }

    @Override
    public String getPathElement( SimpleDriverEditor<MetadataCondition> subEditor ) {
        GWT.log( "----- getPathElement - " + delegate.getPath() );// TODO
        return delegate.getPath();
    }

    @Override
    public void setEditorChain( EditorChain<MetadataCondition, SimpleDriverEditor<MetadataCondition>> chain ) {
        GWT.log( "----- setEditorChain - " + chain );// TODO
        this.chain = chain;
    }
}

JoinMetadataConditionEditor

public class JoinMetadataConditionEditor extends Composite implements SimpleDriverEditor<JoinMetadataCondition>
{
    interface Binder extends UiBinder<Widget, JoinMetadataConditionEditor> {}
    interface Driver extends SimpleBeanEditorDriver<JoinMetadataCondition, JoinMetadataConditionEditor> {}

    private Driver driver = GWT.create(Driver.class);

    @Inject
    ModelFactory factory;

    @UiField @Ignore HTML label;
    @UiField @Ignore FlowPanel container;
    @UiField @Ignore Button deleteMetadata;

    @UiField
    @Path( "type" )
    ManualSelectEditor type;

    @Path( "conditions" )
    ListEditor<MetadataCondition, MetadataConditionEditor> conditions = ListEditor.of( new MetadataEditorSource() );


    public JoinMetadataConditionEditor() {
        initWidget( GWT.<Binder> create(Binder.class).createAndBindUi( this ) );
        type.setSelectOptions( EditorConstants.metadataJoins );
    }


    public SimpleBeanEditorDriver<JoinMetadataCondition, JoinMetadataConditionEditor> createDriver() {
        driver.initialize( this );
        return driver;
    }


    @Override
    public JoinMetadataCondition flush()
    {
        GWT.log( "---------- flush-pre - " + System.identityHashCode(this) + " - " + type.getValue() );// TODO
        GWT.log( "---------- flush-pre - " + System.identityHashCode(this) + " - " + conditions.getList() );// TODO
        JoinMetadataCondition value = driver.flush();
        GWT.log( "---------- flush-post - " + System.identityHashCode(this) + " - " + value.toJson() );// TODO
        return value;
    }


    @Override
    public void edit( JoinMetadataCondition object ) {
        createDriver();
        driver.edit( object );
        label.setText( getLabel( object ) );
    }


    private String getLabel( JoinMetadataCondition value ) {
        if( StringUtils.equals( value.getType(), JoinMetadataTypes.AND.value() ) )
            return LibsFactory.lang().allConditionsAreTrue();
        return LibsFactory.lang().anyConditionsAreTrue();
    }


    @Override
    public HandlerRegistration addDeleteHandler( MetadataDeletedHandler handler ) {
        return addHandler( handler, MetadataDeletedEvent.TYPE );
    }


    @UiHandler("deleteMetadata")
    protected void onDeleteMetadata( ClickEvent event ) {
        fireEvent( new MetadataDeletedEvent( (Event) event.getNativeEvent() ) );
    }


    @UiHandler("addAllMetadata")
    protected void onAddAllMetadata(ClickEvent event) {
        add( factory.newJoinMetadataCondition( JoinMetadataTypes.AND ) );
    }


    @UiHandler("addOrMetadata")
    protected void onAddOrMetadata(ClickEvent event) {
        add( factory.newJoinMetadataCondition( JoinMetadataTypes.OR ) );
    }

    @UiHandler("addLeafMetadata")
    protected void onAddLeafMetadata(ClickEvent event) {
        add( factory.newLeafMetadataCondition() );
    }


    private void add( MetadataCondition metadata ) {
        try {
            GWT.log("--------------------------------- add() - pre");// TODO
            conditions.getList().add( metadata );
            clearErrors();
        } catch (Exception e) {
            GWT.log("--------------------------------- add() - " + e.getMessage()); // TODO
        }
    }


    public void clearErrors() {
        type.getErrorHandler().clearErrors();
    }


    private class MetadataEditorSource extends EditorSource<MetadataConditionEditor>
    {
        @Override
        public MetadataConditionEditor create( int index )
        {
            final MetadataConditionEditor subEditor = new MetadataConditionEditor();
            container.insert( subEditor, index );
            return subEditor;
        }

        public void dispose( MetadataConditionEditor subEditor ) {
            container.remove( subEditor );
        }
    }
}

问题

这第二种方法似乎几乎可行。问题是,当我刷新驱动程序时,子驱动程序也会被刷新,但由于某些原因,父编辑实际上并未包含子编辑的值。

当我有一个嵌套的Join条件时,上面的日志语句会生成以下输出:

----- flush-pre - 111 - JoinMetadataCondition@2d1
---------- flush-pre - 761 - null
---------- flush-pre - 761 - [JoinMetadataCondition@379]
----- flush-pre - 886 - JoinMetadataCondition@379
---------- flush-pre - 929 - and
---------- flush-pre - 929 - []
---------- flush-post - 929 - {"type":"and", "conditions":[]}
----- flush-post-1 - 886 - {"type":"and", "conditions":[]}
----- getValue - 886 - JoinMetadataCondition@379
---------- flush-post - 761 - {"type":"and", "conditions":[]}
----- flush-post-1 - 111 - {"type":"and", "conditions":[]}
----- getValue - 111 - JoinMetadataCondition@2d1
{"type":"and", "conditions":[]}

正如您所看到的,主编辑器(111)实际上并未包含其子编辑器的内容。任何想法为什么会这样?

1 个答案:

答案 0 :(得分:0)

不幸的是,我无法使用结构化编辑器方法来实现这一点。

最终的解决方案是创建一个LeafValueEditor,并根据setValue()提供的数据输入“手动”构建表单。我还实现了HasEditorErrors以正确处理错误。