How to use GWT's Editor Framework with gwt-platform?

4.2k views Asked by At

I'm using gwt-platform and tried to implement GWT's editor framework. But I don't get it working from within the presenter. There are some answers around the web, that say I have to inject the EditorDriver somehow into the Presenter, but I don't know how to do this...

At the moment I tried this without success:

public class MyPresenter extends Presenter<MyPresenter.MyView, MyPresenter.MyProxy> implements MyUiHandlers {
    public interface MyView extends View, HasUiHandlers<MyUiHandlers>, Editor<MyModel> {}

    @ProxyStandard
    @NameToken(NameTokens.myPage)
    @NoGatekeeper
    public interface MyProxy extends ProxyPlace<MyPresenter> {} 

    interface Driver extends SimpleBeanEditorDriver<MyModel, MyView> {}
    private Driver editorDriver;
    DispatchAsync dispatcher;

    @Inject
    public MyPresenter(EventBus eventBus, MyView view, MyProxy proxy, DispatchAsync dispatcher) {
        super(eventBus, view, proxy);
        getView().setUiHandlers(this);
        this.dispatcher = dispatcher;

        MyModel m = new MyModel();
        m.setId(1L);
        m.setUsername("username");
        m.setPassword("password");

        editorDriver = GWT.create(Driver.class);
        editorDriver.initialize(this.getView());
        editorDriver.edit(m);
    }

    ...
}

It works if I explicitly specify the ViewImplementation, but that's not the way MVP should work:

interface Driver extends SimpleBeanEditorDriver<MyModel, MyViewImpl> {}

...

editorDriver.initialize((MyViewImpl) this.getView());

I would be nice if someone could give me an example how to do it right.

Thanks

3

There are 3 answers

2
Marco Jakob On BEST ANSWER

An approach similar to what was used in an earlier version of the Expenses sample worked for me:

An interface that the view should implement. The wildcard is used so that the presenter does not need to know the concrete view implementation:

import com.google.gwt.editor.client.Editor;
import com.gwtplatform.mvp.client.View;

/**
 * Implemented by views that edit beans.
 *
 * @param <B> the type of the bean
 */
public interface BeanEditView<B> extends View, Editor<B> {

  /**
   * @return a new {@link SimpleBeanEditorDriver} initialized to run
   *         this editor
   */
  SimpleBeanEditorDriver<B, ?> createEditorDriver();
}

Your presenter should look something like this now:

public class MyPresenter extends Presenter<MyPresenter.MyView, MyPresenter.MyProxy> implements MyUiHandlers {
    public interface MyView extends BeanEditView<MyModel>, HasUiHandlers<MyUiHandlers> {}

    @ProxyStandard
    @NameToken(NameTokens.myPage)
    @NoGatekeeper
    public interface MyProxy extends ProxyPlace<MyPresenter> {} 

    private SimpleBeanEditorDriver<MyModel, ?> editorDriver;
    DispatchAsync dispatcher;

    @Inject
    public MyPresenter(EventBus eventBus, MyView view, MyProxy proxy, DispatchAsync dispatcher) {
        super(eventBus, view, proxy);
        getView().setUiHandlers(this);
        this.dispatcher = dispatcher;

        MyModel m = new MyModel();
        m.setId(1L);
        m.setUsername("username");
        m.setPassword("password");

        editorDriver = getView().createEditorDriver();
    }

    ...
}

And the view implmementation:

public class MyViewImpl extends ViewWithUiHandlers<MyUiHandlers> implements
    MyPresenter.MyView {

  public interface Binder extends UiBinder<Widget, MyViewImpl> { }
  private static Binder uiBinder = GWT.create(Binder.class);

  /**
   * The driver to link the proxy bean with the view.
   */
  public interface EditorDriver extends SimpleBeanEditorDriver<MyModel, MyViewImpl> { }

  private final Widget widget;

  public MyViewImpl() {
    widget = uiBinder.createAndBindUi(this);
  }

  @Override
  public SimpleBeanEditorDriver<MyModel, ?> createEditorDriver() {
    EditorDriver driver = GWT.create(EditorDriver.class);
    driver.initialize(this);
    return driver;
  }

  @Override
  public Widget asWidget() {
    return widget;
  }

  ...
}

That's as close as I could get to MVP with GWT's Editor Framework. I couldn't find a way for the view implementation to NOT know the model but I don't think it's really necessary.

If anyone has any improvements on this, I'm glad to hear.


Found some additional comments on GWT Editors. It seems that it might just not be possible to completely separate the model. As Thomas Broyer puts it in his answer to another Editor question:

"MVP is not set in stone (it's not even defined; it was coined by Martin Fowler but he retired the term in favor of two more specific patterns), so you're only violating the rules you gave to yourself. Put differently, the Editor framework as a whole can be seen as violating MVP: each editor know the model, not necessarily the exact instance it's editing (as with ValueAwareEditor or LeafValue), but at least the kind of objects it's an editor of."

0
Benjamin M On

MVP says that you use the presenter to completely seperate the model from the view. In addition I'd say that your approach puts logic inside the view... I hope that there's another solution ;)

0
rcomblen On

The issue is that the Driver.class passed to GWT.create

editorDriver = GWT.create(Driver.class);

must the concrete class that holds all sub-editors, i.e. all the uibinded widgets.

One solution is the following:

The view interface extends the editor interface for the Model object

public interface MyView extends View, ..., Editor<MyModel>

The view implementation MyViewImpl defines a driver type

interface MyDriverImpl extends SimpleBeanEditorDriver<MyModel,MyViewImpl>

The driver is instantiated in MyViewImpl by

SimpleBeanEditorDriver<MyModel,MyView> driver = GWT.create(MyDriverImpl.class);

The parent type

SimpleBeanEditorDriver<MyModel,MyView>

can be used to pass references of the driver to the presenter