I wasn't aware of Felxjson, but Metawidget and similar projects were
certainly an inspiration for the dynamic GUI / object CRUD stuff.

I'm sure many more possibilities will become apparent as the idea is
applied to different problem domains.

On 4 July 2011 11:55, Superstring Media <[email protected]> wrote:
> Some of the applications of your idea seem to be inclusive of functions in 
> other APIs like Flexjson's Transformers or Metawidget's dynamic UIs.
> All really great applications coming from a single enhancement, sounds 
> excellent indeed.
>
> http://flexjson.sourceforge.net
> http://metawidget.org
>
> Thom
>
>
> On 2011-07-02, at 4:36 PM, Chris Bartlett wrote:
>
>> Firstly, my apologies for the length of this email (and if there are
>> lots of typos).  It might be easier to just jump to the example BXML
>> fragments which demonstrate possibilities of the proposed change, and
>> then skip back to the more wordy stuff.
>>
>> I will post some proof of concept code in the morning if there is any
>> interest in this.
>>
>>
>> * Notes
>> The examples are meant to demonstrate ideas, so might seem a little 
>> contrived.
>> Although Transformables are designed to be triggered by
>> BXMLSerializer, they can just as easily be used programmatically.
>> The transform() method could be provided with a specific classloader
>> by BXMLSerializer if required
>>
>>
>> * References
>> http://pivot.apache.org/tutorials/bxml-primer.html
>> Specifically the section titled 'Class Instances'
>>
>> http://svn.apache.org/repos/asf/pivot/trunk/core/src/org/apache/pivot/beans/BXMLSerializer.java
>>
>>
>> * Summary
>> Make a backwardly compatible change to BXMLSerializer to enable
>> support for a simple 'Transformable<T>' interface.
>>
>> public interface Transformable<T> {
>>    public Collection<T> transform();
>> }
>>
>> The interface would have a single method named 'transform()' which
>> would return a java.util.Collection<T>.
>>
>> A bean implementing the interface would be constructed as normal by
>> BXMLSerializer, but would have its 'transform()' method called when
>> the bean would usually be returned (if it was the root element) or
>> added to the parent object somehow (if it had a parent).
>>
>> If the bean is the root element, the Collection would be returned as
>> the result of the BXMLSerializer.readObject(InputStream) method;
>>
>> If the bean is not the root element, BXMLSerializer would the iterate
>> over the items in the returned Collection and process them in exactly
>> the same way as the original bean would have been processed.
>>
>> i.e. If the original bean was going to be added to a Sequence defined
>> by a DefaultProperty, then each of the items in the Collection would
>> be added to the same Sequence instead.
>>
>> i.e. If the original bean was going to be set as the value for a
>> writeable property, each of the items in the Collection would be set
>> as values for the same writeable property, in the order defined by the
>> Collection's iterator)
>>
>>
>> * What difference would that make?
>> This simple change would provide flexibility by allowing a special
>> type of 'Class Instance' (an implementation of Transformable) to
>> decide how many items to return (and of what types) when it is
>> 'created', rather than exactly 1 object as currently happens.
>>
>>
>> * How could that help me?
>> It essentially turns Transformable objects into macros that can
>> perform arbitrary tasks.
>>
>>
>>
>> Example 1 - User defined, simplified API for creating object graphs
>>
>> This is the original problem that lead to the proposed idea.
>> Being able to create simplified APIs for Pivot Components means that
>> designers could be provided with a much smaller and simpler 'toolkit'
>> to work with.  Having a smaller API would also be helpful for people
>> who add in auto-complete functionality into their editor tools.
>> Even just the ability to refer to a Component by a different name can
>> be very useful, especially when there are similarly named widgets in
>> various UI frameworks.
>>
>> <!-- This would create and populate a layout without needing to know
>> how it was being implemented behind the scenes -->
>> <ThreeColumnLayout>
>>  <leftColumn>
>>    ...
>>  </leftColumn>
>>  <middleColumn>
>>    ...
>>  </middleColumn>
>>  <rightColumn>
>>    ...
>>  </rightColumn>
>> </ThreeColumnLayout>
>>
>>
>> Here is a more complete example...
>>
>> TablePaneBuilder implements Transformable<TablePane> and has 'columns'
>> and 'components' properties.  The latter being a Sequence<Component>
>> annotated as the DefaultProperty.  Its 'transform()' method returns a
>> newly created TablePane with the requested number of columns, and
>> sufficient rows to populate the cells using the supplied Components.
>>
>> @DefaultProperty("components")
>> public class TablePaneBuilder implements Transformable<TablePane> {
>>
>>    private final List<Component> components = new ArrayList<Component>();
>>    private int columns = 1;
>>
>>    public Sequence<Component> getComponents() {
>>        return components;
>>    }
>>
>>    public int getColumns() {
>>        return columns;
>>    }
>>    public void setColumns(int columns) {
>>        if (columns < 1) {
>>            throw new IllegalArgumentException();
>>        }
>>        this.columns = columns;
>>    }
>>
>>    @Override
>>    public Collection<TablePane> transform() {
>>        final TablePane tablePane = new TablePane();
>>        for (int i = 0; i < columns; i++) {
>>            tablePane.getColumns().add(new Column());
>>        }
>>        TablePane.Row row = null;
>>        for (Component component : components) {
>>            if (row == null || row.getLength() == columns) {
>>                row = new TablePane.Row();
>>                tablePane.getRows().add(row);
>>            }
>>            row.add(component);
>>        }
>>        return Arrays.asList(tablePane);
>>    }
>> }
>>
>> Usage in BXML
>> <TablePaneBuilder columns="2" >
>>  <!-- Row 1 -->
>>  <wtk:Label text="Label 1" />
>>  <wtk:Label text="Label 2" />
>>
>>  <!-- Row 2 -->
>>  <wtk:PushButton buttonData="PushButton 1" />
>>  <wtk:PushButton buttonData="PushButton 2" />
>>
>>  <!-- Row 3 -->
>>  <wtk:TextInput text="TextInput 1" />
>>  <wtk:TextInput text="TextInput 2" />
>> </TablePaneBuilder>
>>
>>
>>
>> Example 2 - Ability to instantiate classes which do not have a no-arg
>> constructor
>>
>> public final class UnfriendlyPOJO {
>>    public final int mandatory;
>>    public UnfriendlyPOJO(int mandatory) {
>>        this.mandatory = mandatory;
>>    }
>> }
>>
>> public class UnfriendlyPOJOBuilder implements Transformable<UnfriendlyPOJO> {
>>    private int mandatory;
>>    public int getMandatory() {
>>        return mandatory;
>>    }
>>    public void setMandatory(int mandatory) {
>>        this.mandatory = mandatory;
>>    }
>>
>>    @Override
>>    public Collection<UnfriendlyPOJO> transform() {
>>        return Arrays.asList(new UnfriendlyPOJO(mandatory));
>>    }
>> }
>>
>>
>> <UnfriendlyPOJOBuilder mandatory="99" />
>>
>>
>>
>> Example 3 - Can be used to hide attribute ordering restrictions
>>
>> This BXML will work, as the selectedIndex is being set once the
>> ListView has data
>> <wtk:ListView listData="['One', 'Two', 'Three']" selectedIndex="0"/>
>>
>> But this BXML will fail, as the selectedIndex is being set before the
>> ListView has data
>> <wtk:ListView selectedIndex="0" listData="['One', 'Two', 'Three']"/>
>>
>>
>> @DefaultProperty("listView")
>> public class ListViewBuilder implements Transformable<ListView> {
>>    private final ListView listView = new ListView();
>>    private int selectedIndex;
>>    private List<?> listData;
>>
>>    public int getSelectedIndex() {
>>        return selectedIndex;
>>    }
>>    public void setSelectedIndex(int selectedIndex) {
>>        this.selectedIndex = selectedIndex;
>>    }
>>
>>    public void setListData(String listData) {
>>        try {
>>            this.listData = JSONSerializer.parseList(listData);
>>        } catch (SerializationException exception) {
>>            throw new IllegalArgumentException(exception);
>>        }
>>    }
>>
>>    @Override
>>    public Collection<ListView> transform() {
>>        listView.setListData(listData);
>>        // Ensure that the index selection happens after the list population
>>        listView.setSelectedIndex(selectedIndex);
>>        return Arrays.asList(listView);
>>    }
>> }
>>
>> <ListViewBuilder selectedIndex="0" listData="['One', 'Two', 'Three']" />
>>
>>
>>
>> Example 4 - Provide similar functionality to named styles only for properties
>>
>> The same could essentially be achieved by subclassing a Component and
>> hard coding some properties into its constructor.
>> Using a Transformable is another option, and could also be used with
>> final classes.
>>
>> @DefaultProperty("textInput")
>> public class PasswordInput implements Transformable<TextInput> {
>>    private TextInput textInput = null;
>>    public void setTextInput(TextInput textInput) {
>>        this.textInput = textInput;
>>    }
>>
>>    @Override
>>    public Collection<TextInput> transform() {
>>        if (textInput == null) {
>>            textInput = new TextInput();
>>        }
>>        textInput.setPassword(true);
>>        textInput.setPrompt("Enter password");
>>        return Arrays.asList(textInput);
>>    }
>> }
>>
>> <!-- Creates and returns a new TextInput -->
>> <PasswordInput />
>> <!-- Uses the supplied TextInput -->
>> <PasswordInput>
>>  <wtk:TextInput tooltipText="Using supplied TextInput" text="secret" />
>> </PasswordInput>
>>
>>
>> This idea can be taken further by a Transformable that 'clones'
>> specified objects (0..n times).
>> It would create new instances based on the supplied source objects,
>> and then iterate over the source's properties and styles while setting
>> the same values on the newly created 'clone'.  (I knocked up a working
>> example of this in about 20 mins)
>>
>>
>>
>> Example 5 - Transformable that returns an empty Collection
>>
>> This could be used to conditionally include sections of BXML file
>> based on any arbitrary logic.
>> (Result of a webquery, result of a JVM scripting function, JVM
>> version, availability of classes on the classpath, Operating System,
>> user name etc)
>> If the critera is met, the Transformable would return a Collection
>> containing the BXML, otherwise just an empty Collection.
>>
>> <WindowsOS>
>>  <WindowsWidget />
>>  <bxml:reference id="$commonToAllOperatingSystems"/>
>>  ...
>> </WindowsOS>
>> <MacOS>
>>  <MacWidget />
>>  <bxml:reference id="$commonToAllOperatingSystems"/>
>>  ...
>> </MacOS>
>>
>>
>>
>> Example 6 - Enhanced BXML include
>>
>> <!-- Include all files that match the regular expression or wildcard
>> syntax, retrieving them asynchronously -->
>> <Include async="true" regex="/path/to/bxml/files/widget[5-7].bxml" />
>>
>> or even
>>
>> <Async>
>>  <Include regex="/path/to/bxml/files/widget[5-7].bxml" />
>> </Async>
>>
>> The Async would queue a callback to populate the same position with
>> data once it had been retrieved from a potentially slow source.
>> (This is just an example of the sorts of options which are made
>> available by this change - not a proposal to create such a new
>> 'Includer')
>>
>>
>>
>> Example 7 - Dynamic UI creation (think automatic CRUD forms for a POJO/bean)
>>
>> <!-- Show a 'person' bean in a form -->
>> <FormBuilder editable="true" source="$person" fieldOrder="['id',
>> 'title', 'firstName', 'lastName', 'age']" />
>> or
>> <!-- Show a 'person' bean in a name/value TableView where the values
>> are editable -->
>> <TableViewBuilder editable="true" source="$person" fieldOrder="['id',
>> 'title', 'firstName', 'lastName', 'age']" />
>>
>> (These examples are for generic XXXBuilders, but they could obviously
>> have internal knowledge of certain types.)
>>
>>
>>
>> Example 8 - Reuseable and sharable
>>
>> Due to the simplicity of the interface, Transformables can easily be
>> shared among Pivot developers.
>> This could lead to an online repository of reuseable components (even
>> just wiki pages of source).
>>
>> There have been many mailing list questions about how to achieve
>> particular layouts.
>> Common layouts could be implemented as Transformables and mailed to
>> the list for easy reuse.
>>
>> (I suppose Transformables could be considered similar to a JSP tag library)
>>
>>
>> Chris
>
>

Reply via email to