Declarative UI with XML

Hi,

I guess that an XML for declaratively describing the UI for vaadin applications is a very good idea.

Things should go like this:

The visual editor directly manipulates the XML file. Working with XML is much more easier for a visual editor than parsing source code. Just take a look at the Swing designer in Netbeans. The visual editor only changes things it created itself. There is no risk that the editor manipulates the written business logic.

For each XML UI file that is written by the visual editor (not manually), there exists an additional Java file that keeps the business logic for the UI. This combination is also used in visual studio.

Developing UIs manually should not be the way to develop applications. A visual editor as it is developed for Vaadin is state of the art. But using XML for the backend that is saving the UI is a good choice.

Just think about this combination of XML and visual editor to devide UI and business logic.

Regards,

Mike

Thans for comments. The current implementation of WYSIWYG editor uses instantiated UI component tree as the model. With this it should be fairly easy to add XML as an alternative view to the edited layout. Unfortunately I have not had time to make any progress with the project lately - so it is still on a “concept prototype” level.

Is there a schema file to go along with the XML so that the Eclipse XML Editor can auto complete things?

It may also be good if event listeners can be defined in XML as well. I like the way ZK does the ZUL files with its good eclipse plugin support to edit the ZUL files.

I think that XML is fundamentally the wrong approach. I went and looked at what Joonas did, and it has a ways to go before its usable. Wiring up listeners is just one of the problems.

However, using the snakeyaml project, it should be possible to bootstrap building the basic structure of a Vaadin UI in under a day, because snakeyaml can already read/write arbitrary Java bean structures.

If some one is interested in trying this, I have some simple code for snakeyaml that avoids writing out default values of java beans (based on the null constructor) that I could hand off to you.

Why Yaml:

     Yaml has a concept of aliasing, so you can setup a value of a java bean as matching something you've already defined. So you can tell the child that its parent is well, the parent. :

component: &parent1 { — the alias for our component is “parent1”
title: “Title”
children: [
parent: *parent1 — setParent(parent1) is going to get called on the child.

In XML, you'll have to go back after the fact in order to wire "parent", and you'll have to do that for each class.You can save/restore arbitrary structures of java bean objects in Yaml, which you can't do in XML. YAML files, if you use the "prettyFlow" stream that's in SnakeYaml 1.7 are also more human readable then XML. 

     Second, snakeyaml allows you to inject your own object resolvers, so you can wire listener methods up inside the layout. When I looked into how people made Vaadin UIs, there are lots and lots of inner classes. Which work great, until you're trying to split up the code from the layout. Snakeyaml would let you set the listener method using some pre-defined constructor:

  !listenerMethod: saveClicked
  !listenerClass: SaveClickerClass

The first would tell the loader to call “saveClicked” on the loading class, the second would know to make a new instance of SaveClickerClass (presumably an inner class).

This would be much better then ZKs approach because the code would be the code, and the layout the layout. That’s one of the things that I think sucks about ZUL.

If you use the Yaml approach, I suspect that someone could have a working declarative UI loader based on Yaml in a week. If someone wants to tackle this, let me know, and I can pass you some code to make things easier.

Yes! Exactly what I’ve wanted for a while now. Working as a theme designer/developer together with UI programmers is sometimes such a pain, when you have to go through all the Java code just to try and add some margin or change some layout to another type.

What would suffice for me, is that the UI programmer would just use CustomLayouts for each and every screen they code, and just provide semantic “slot” names for all the components that they put inside the layout. I could then only edit the CustomLayouts, where I would be allowed to hack as much HTML as I dare, instantiate core layouts with a set of components/slots as parameters, add/remove style names for all contained components and specify their sizes.

I would not want to specify any listeners for the components inside the layout, that’s specifically the job for the UI programmer. The program logic should, in my opinion, stay in the Java code, where it’s easiest to maintain, refactor and keep clean. Layout code is the one that usually ends up messy, not the logic, hence I would very much like to separate the two, and I bet the regular UI programmers would like it as well. So wiring up listeners through templates is a bad idea IMO.

I realize this would require a bit more effort from the UI programmer in the start (creating HTML templates, naming all slots etc.), but the reward would be worth it.

And to not just ramble about my own ideas, I might actually respond to your ideas as well :slight_smile:

I took a very brief glance at the SnakeYAML documentation. Pretty hard for me to say, with such limited info, if it would be useful to use that kind of syntax. My first gut feeling didn’t like it too much, but maybe if I saw a better example I could be persuaded otherwise.

Yeah, I’ve been on the other side of that, being the programmer working with the designer. So I agree, code is code, layout is layout.

As for what Yaml looks like, you’re right, the examples are lame. So this is a complex example in “flow” style, with the “pretty flow” option I added to SnakeYaml. It’s the first half of a file, so there are terminators missing. This is from our actual code.

Yaml has two flavors:
Block: Kind of like Python, indentation/whitespace is important to indicate nesting
Flow: whitespace is irrelvant, instead surround lists and { } surround name-value pairs, and there’s commas to terminate things.

For Pretty Flow, I take the indentation from Block and add {} and . But the indentation doesn’t matter, its just there to make it more readable. You have to make sure that your
and {} match, and you need commas here and there.

Note that # marks comments.

First the code:



# a series of steps
[

  { # begin step
    title : "Step 1 of 1",
    shortHelp : "This is some short help text for step 1",
    popupHelp : "This is longer popup help text for step 1",

    # begin a series of panels
    panels : [
        {   # panel start
            title : "Panel 1",
            shortHelp : "Short help text for panel 1 step 1",
            popupHelp : "Popup help text for panel 1 step 1",
            attributes : [
             {  # attribute start
                name : "emailAddress",
                label : "emailAddress",
              type : "String",      # This is just for reference, we pull this from the model each time
#              class : "BASIC", # This is just for reference, we pull this from the model each time
                    shortHelp: "",
                    popupHelp: "",
              }, #end of an attribute
             {  # attribute start
                name : "uuid",
                label : "uuid",
              type : "String",      # This is just for reference, we pull this from the model each time
#              class : "BASIC", # This is just for reference, we pull this from the model each time
                    shortHelp: "",
                    popupHelp: "",
                     disabled: true,
              }, #end of an attribute
             {  # attribute start
                name : "party?.name",
                label : "Party",
              type : "Party",      # This is just for reference, we pull this from the model each time
#              class : "MANY_TO_ONE", # This is just for reference, we pull this from the model each time
                    shortHelp: "",
                    popupHelp: "",
              }, #end of an attribute
             ], #end of all attributes for panel
            }, # end of a panel

There’s one thing that’s missing from this example, because this example doesn’t need it, and that is specifying any data types. The reason my above sample doesn’t have it is because SnakeYaml can determine from the context that a List has to be filled with objects of type “Foo”, and if you have an object “Bar” that has a parameter “color” of type “Color”, that it needs to build a “Color” object. Simple types like String, Integer, date can be inferred from the format of the data.

That is, if the type of an object can be determined from the context, either from the specification on the collection class or via the type of the object property, it’s not necessary to specify the type.

In the above, When I parse the file, I tell Yaml its parsing a List. Step.panels is set to be a List, and Panel has Panel.attributes = Map<String,Object>. Those are just the regular declarations for my objects, I didn’t add anything to be able to read/write the yaml!

If specifying the type is necessary, it looks like this:



!!com.example.ProductType {
    guid: 3520D0F5-C2F1-49AB-8F43-F5C808F59D1F,
    name: Demo Auth 9
  },

That excerpt above is from a List, so Yaml knows that they’re all SuperType objects, but it doesn’t know which kind, so it has to specify the type.

Do you think you could work with that?

May be use something more “standard”, like
mozilla rhino
?
JavaFx for poor men :wink:

~~concept:

importPackage(com.vaadin.ui);

JavaAdapter(Packages.com.vaadin.Application, {
title: “My Page 1”,//see? very easy and declarative
foo: 999999,
label1 = Label(“Blabla!”),

/** Init is invoked on application load (when a user accesses the application for the first time). */
init: function () {
with (this) {
// Main window is the primary browser window
main = Window(“Hello window”);
mainWindow = main;

// "Hello world" text is added to window as a Label component
main.addComponent(Label("Hello World!"));
main.addComponent(label1);
		
button = Button("Push me");
main.addComponent(button);
    button.addListener({buttonClick: function (event) {
       label1.value = "Button "+button+", this="+this+", event="+event;
       //but this is still programming language, not xml/yaml
       for (i=0; i<10; i++) { label1.value += i; }
     }});
}//with

}//init
});

There has been a lots of interest in this add-on, but unfortunately I have not had time to complete it.

IMO, there are two “blockers” before this could be considered stable for use:[list]

[]
Reviewing XML structure and deciding upon the final structure.
[
]
Adding support for all attributes of all layouts in the Vaadin Framework core package.

[/list]

Any opinions on the first one? My gut feeling is that the current XML structure is adequate, but it would be better if the structure would be flattened by moving layout attributes from c-nodes to child nodes. Maybe some prefixing should be considered to avoid naming conflicts.

So instead of writing:

<?xml version="1.0" ?>

<VerticalLayout height="100%" width="100%" margin="true">
	<c expandRatio="1.0">
		<TabSheet height="100%">
			<c caption="Fields">
				<VerticalLayout spacing="true" margin="true">
					<c>
						<TextField caption="Name" id="name"></TextField>
					</c>
					<c>
						<DateField caption="Age" id="age"></DateField>
					</c>
					<c alignment="c">
						<InlineDateField resolution="4"></InlineDateField>
					</c>
				</VerticalLayout>
			</c>
			<c caption="Misc">
				<VerticalLayout margin="left top">
					<c>
						<Label contentMode="3">&lt;div style="background-color:
							yellow;"&gt;Foo&lt;/div&gt;</Label>
					</c>
				</VerticalLayout>
			</c>
		</TabSheet>
	</c>
	<c alignment="r">
		<Button caption="Save"></Button>
	</c>
</VerticalLayout>

We could write

<?xml version="1.0" ?>

<VerticalLayout height="100%" width="100%" margin="true">
		<TabSheet height="100%" lo-expandRatio="1.0">
				<VerticalLayout spacing="true" margin="true" lo-caption="Fields">
						<TextField caption="Name" id="name"/>
						<DateField caption="Age" id="age"/>
						<InlineDateField resolution="4" lo-alignment="c"/>
				</VerticalLayout>
				<VerticalLayout margin="left top" lo-caption="Misc">
						<Label contentMode="3">&lt;div style="background-color:
							yellow;"&gt;Foo&lt;/div&gt;</Label>
				</VerticalLayout>
		</TabSheet>
		<Button caption="Save" lo-alignment="r"/>
</VerticalLayout>

(see for a live version at XMLUI Editor - just press “Test XML”)

Hello,

XML is fine to describe the GUI of Vaadin; I don’t see issues in use XML to describe the components. So, I believe that the second mode is more readable to users. What about listeners? Can we add a listener in one button, for example?

Rodrigo

How we should do that? If we would write java in XML attributes we would have to introduce some way of getting references and doing imports. Maybe we could add some references by default, like this:

<Button onClick="app.getMainWindow().showNotification(\"foo\");" caption="foo"/>

I am afraid that this would introduce a large set of complex problems: [list]

[]
how to do autocomplete and code validation?
[
]
how to do imports?
[]
how to pass references?
[
]
should we use BeanShell to execute the code?
[*]

[/list]
Any ideas on how to resolve these?

If not, I am in favor of the current “add ids to xml, add listeners in java” approach: Button myButton = (Button) ui.getById("myButton"); myButton.addListener(...)

Actually, for the most common listeners, this could even be reduced to:

ui.addListener("myButton", new Button.ClickListener() {...})

I dislike the idea of trying to shoehorn application logic into the UI description. This will only lead to unreadable code and other problems, some of which Joonas mentioned in the above post. One other problem: how do you debug such code?

IMO it would be best if the XML was for UI structure only, and any logic (listeners etc.) would reside in the java code as usual. OTOH this will lead to new problems, like how to couple the components in the XML to java code.

Personally, I’m not sure if all this is worth the effort and added complexity.

I have just started to have a look at Vaadin and see great potential in the XML UI approach.

As an organisation we have a lot of expertise in XML and this approach looks to me like a short-cut. If I can quickly define a set of screens in XML which I can show to a client in a matter of hours and get buy-in as well as feedback, it would be worth it even if I would have to throw it away and start again when we come to building the real thing.

Now to a more practical question - is there an XSD that will tell me what I can put into the XML file?

Or have I missed something fundamental? I have only started to look at it today…

Not yet. One of the challenges is that XSD depends on set of available components (both in Vaadin as well as add-ons). Maybe XMLUI could somehow generate XSD. Any ideas on a convenient way to get the list of classes implementing com.vaadin.ui.Component interface -?

From inside there is no convenient way. You never know all classes.
From outside I would suggest Eclipse’s Type Hierarchy.

Good idea.

Actually - for the xmlui itself it could be enough to have a method for generating xsd for any given list of classes. The the party using that xsd probably knows the list better than xmlui. For example - Eclipse could use that xsd for editor code completion and validation and knows the available classes best.

Take a look at
MVP and UIBinder for Vaadin add-on
. Did not try it out yet, but documentation looks promising.

What does “XML” stand for? If it just stands for “Extensible Markup Language.” The name emphasizes the key feature of the language as it will be seen by an HTML user - the ability to define your own tags and attributes, which, of course, HTML does not allow. So XML is just HTML on steroids? So what do
PHP XML
, Java XML means?

In this case XML has nothing to do with HTML.