ListEditor with inheritance

121 views
Skip to first unread message

chris

unread,
Dec 22, 2011, 10:30:52 AM12/22/11
to Google Web Toolkit
There are a few posts asking about Editor's discussing inheritance
this but no responses as of yet. Please keep in mind that I have
search google.com/codesearch, GWT issue tracker and google groups
looking for some kind of solution to using Editor's with inheritance.



// This is my base data provider class that all other implementations
will inherit from.
@ProxyFor(value = DataProvider.class, locator =
DatastoreObjectLocator.class)
public interface DataProviderProxy extends ValueProxy {

public enum DataProviderType {
SQL, R_Command
}

public String getVariableName();

public void setVariableName(String variableName);
}


// This is a simple example that inherits from DataProvider and adds a
single sql statement.
@ProxyFor(value = SqlDataProvider.class, locator =
DatastoreObjectLocator.class)
public interface SqlDataProviderProxy extends DataProviderProxy {


public String getSqlStatement();

public void setSqlStatement(String sqlStatement);
}


// This is the class that I am editing.
@ProxyFor(value = Report.class, locator =
DatastoreObjectLocator.class)
public interface ReportProxy extends DatastoreObjectProxy {
...
/**
* List of all data providers for this report.
* @return
*/
public List<DataProviderProxy> getDataProviders();

/**
* Setter for all data providers.
* @param dataProviders
*/
public void setDataProviders(List<DataProviderProxy>
dataProviders);
...
}



// My report editor that is editing my List of DataProvider objects.
public class ReportBuilderViewImpl extends ViewImpl implements
ReportBuilderView, Editor<ReportProxy> {

...
/**
* Editor for the data provider object contained in the {@link
ReportProxy}.
*/
@UiField
@Path("dataProviders")
DataProviderListEditor dataProviderEditor;

...
}


// This class is a work in progress but essentially what I am trying
to do is to Edit a list of DataProviderProxy
// objects, but when I get to an object of type SqlDataProvider I want
to show the user the optional TextArea that
// they can past their sql statement. In the same editor if the
DataProvider is an instanceof RDataProvider ( not // shown above) I
would want to give the user the option of editing an R command and not
the sqlStatement. I
// have tried adding Generics but ran into compilation issues when
Editor validation was running.

Is there any kind of elegant solution to the problem I am trying to
solve?

public class DataProviderListEditor extends Composite implements
IsEditor<ListEditor<DataProviderProxy, DataProviderEditor>> {

private class DataProviderSource extends
EditorSource<DataProviderEditor> {

@Override
public DataProviderEditor create(int index) {
DataProviderEditor editor = new DataProviderEditor();
container.insert(editor, index);
return editor;
}

/**
* Call this to remove an editor from the view.
*/
@Override
public void dispose(DataProviderEditor editor) {
editor.removeFromParent();
}

@Override
public void setIndex(DataProviderEditor editor, int index) {
container.insert(editor, index);
}
}

/**
* This is the default view for our widgets.
*
* @author chinshaw
*
*/
@UiTemplate("DataProviderEditor.ui.xml")
public interface Binder extends UiBinder<Widget,
DataProviderEditor> {
}

/**
* This is the actual widget that edits our data provider proxy.
It will
* handle flushing and so forth.
*
* @author chinshaw
*
*/
public static class DataProviderEditor extends Composite
implements ValueAwareEditor<DataProviderProxy> {

private DataProviderProxy value = null;

@UiField
TextBox variableName;

@UiField
TextArea sqlStatement;

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

@Override
public void setDelegate(EditorDelegate<DataProviderProxy>
delegate) {
// TODO Auto-generated method stub

}

/**
* Indicates that the Editor cycle is finished. This method
will be
* called in a depth-first order by the EditorDriver, so
Editors do not
* generally need to flush their sub-editors.
*/
@Override
public void flush() {

}

/**
* Notifies the Editor that one or more value properties have
changed.
* Not all backing services support property-based
notifications.
*
* @param paths
* a list of String paths
*/
@Override
public void onPropertyChange(String... paths) {

}

/**
* Called by the EditorDriver to set the object the Editor is
peered
* with
* <p>
* ValueAwareEditors should preferentially use sub-editors to
alter the
* properties of the object being edited.
*
* @param value
* a value of type T
*/
@Override
public void setValue(DataProviderProxy value) {
this.value = value;
}
}

/**
* This is the parent container panel that contains all other
editors
*/
private final FlowPanel container = new FlowPanel();
private final ListEditor<DataProviderProxy, DataProviderEditor>
editor = ListEditor.of(new DataProviderSource());

/**
* Default constructor takes an index of the Editor objects
location. The
* index is used to delete this object.
*
* @param index
*/
public DataProviderListEditor(Resources resources) {
initWidget(container);
}

@Override
public ListEditor<DataProviderProxy, DataProviderEditor>
asEditor() {
return editor;
}
}








Thomas Broyer

unread,
Dec 22, 2011, 11:56:35 AM12/22/11
to google-we...@googlegroups.com
First, have you seen http://code.google.com/p/google-web-toolkit/issues/detail?id=6719 ?

In your case, I think you could do it quite easily by:
  1. not having the TextArea as a sub-editor
  2. implementing ValueAwareEditor to push to the TextArea and make it visible when the value is a SqlDataProvider in setValue, and pull from it and push to the value in flush(); and similar things for other kinds of values.
That unfortunately won't scale very well as you add other DataProvider subclasses.

FWIW, in a similar scenario, we chose to not use the Editor framework and handle everything "by hand" instead (but we had another challenge: some structures are recursive; i.e. we could have a DataProvider that would contain other DataProvider).

Stefan Ollinger

unread,
Dec 22, 2011, 2:31:12 PM12/22/11
to google-we...@googlegroups.com
I submitted a post to the gwt contributors mailing list with a similar issue:
https://groups.google.com/d/msg/google-web-toolkit-contributors/gUFkDIQ2TSE/Atjg5PZ6G4kJ

This is basically what is proposed in the Issue 6791.
Is there any progress on that issue yet, or are there any problems which prevent this solution?

Regards,
Stefan
--
You received this message because you are subscribed to the Google Groups "Google Web Toolkit" group.
To view this discussion on the web visit https://groups.google.com/d/msg/google-web-toolkit/-/EsCldOjAMBgJ.
To post to this group, send email to google-we...@googlegroups.com.
To unsubscribe from this group, send email to google-web-tool...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/google-web-toolkit?hl=en.

chris

unread,
Dec 22, 2011, 2:55:55 PM12/22/11
to Google Web Toolkit
Thomas,

Thank you for your quick response. I do have a semi working
solution that does support inheritance, still has some bugs that are
probably caused by my lack of generics in the EditorSource. I did see
BobV's response on stackoverflow but wasn't exactly sure it would fix
my problem. Going forward I am going to implement your solution using
ValueAwareEditor, use instanceof to construct subeditors and manually
flush the changes to the corresponding object. Thank you again for
all your work helping the GWT community.

I am attaching a partial solution that is adding a SqlDataProvider
entity but is not persisting the values. In the solution I could use
the EditorSource to construct a sub editor of a specific type based on
the instanceof DataProvider in the asEditor().getList() of my
DataProviderEditor. I imagine that there is a problem persisting my
values because the EditorSource does not know what kind of
Editor<Entity> it is editing so this will probably never work
correctly. Please let me know if you agree.

I have implemented the SqlDataProviderEditor as a ValueAwareEditor
instead of Editor as a way to do debugging.


// NOTE THIS CODE SAMPLE DOES NOT WORK CORRECTLY.
public class DataProviderListEditor extends Composite implements
IsEditor<ListEditor<DataProviderProxy, Editor<DataProviderProxy>>> {

private static final Logger logger =
Logger.getLogger(DataProviderListEditor.class.getName());

private class DataProviderSource extends EditorSource<Editor> {

@Override
public Editor create(int index) {

SqlDataProviderEditor editor = new
SqlDataProviderEditor();
container.insert(editor, index);
// Editor<DataProviderProxy> retEditor =
(Editor<DataProviderProxy>)
// editor;

return editor;
}

/**
* Call this to remove an editor from the view.
*
* @Override public void dispose(Editor<DataProviderProxy>
editor) {
* editor.removeFromParent(); }
* @Override public void setIndex(Editor<DataProviderProxy>,
int index)
* { container.insert(editor, index); }
*/
}

public static class SqlDataProviderEditor extends Composite
implements ValueAwareEditor<SqlDataProviderProxy> {

private SqlDataProviderProxy value = null;

@UiField
TextBox variableName;

@UiField
TextArea sqlStatement;

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

@Override
public void setDelegate(EditorDelegate<SqlDataProviderProxy>
delegate) {
// TODO Auto-generated method stub
}

@Override
public void flush() {
logger.info("calling flush on my value editor");
value.setSqlStatement(sqlStatement.getValue());
logger.info("Setting variable name to be " +
variableName.getValue());
value.setVariableName(variableName.getValue());
}

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

}

@Override
public void setValue(SqlDataProviderProxy value) {
logger.info("Value of object is " + value);
this.value = value;
logger.info("Value being assigned is " +
value.getVariableName());
}
}

/**
* This is the default view for our widgets.
*
* @author chinshaw
*
*/
@UiTemplate("DataProviderEditor.ui.xml")
public interface Binder extends UiBinder<Widget,
SqlDataProviderEditor> {
}

/**
* This is the parent container panel that contains all other
editors
*/
private final FlowPanel container = new FlowPanel();
private final ListEditor<DataProviderProxy,
Editor<DataProviderProxy>> editor = ListEditor.of(new
DataProviderSource());

/**
* Default constructor takes an index of the Editor objects
location. The
* index is used to delete this object.
*
* @param index
*/
public DataProviderListEditor(Resources resources) {
initWidget(container);
}

@Override
public ListEditor<DataProviderProxy, Editor<DataProviderProxy>>
asEditor() {
return editor;
}
}


On Dec 22, 10:56 am, Thomas Broyer <t.bro...@gmail.com> wrote:
> First, have you seenhttp://code.google.com/p/google-web-toolkit/issues/detail?id=6719?
>
> In your case, I think you could do it quite easily by:
>
>    1. not having the TextArea as a sub-editor
>    2. implementing ValueAwareEditor to push to the TextArea and make it
Reply all
Reply to author
Forward
0 new messages