Declarative UI with XML

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.

I’ll throw in my opinions, FWIW.

  • This approach has a well-understood and very successful poster-child: Apple’s Interface Builder and XIB files, used in every iPhone app. Nothing like billions of dollars in revenue to prove your point.
  • Definitely use XML, not YAML! There are zillions of tools and libraries for working with XML.
  • It’s also probably a good idea to declare all of your elements in a custom Vaadin XML namespace.
  • Don’t bother trying to hack any Java logic into the language. That’s what programming languages are for.

I like everything about Vaadin, except the layout stuff kills me. I suppose this is because I’m coming from the Java programming world rather than the CSS/web design world… but so does everybody else that I work with. In any case, I spend way too much time trying to figure out layout screwups and trying to understand the interaction of Java, CSS, HTML, etc. which conspire to make things worse than e.g. programming in Java/Swing. Trying to get your layout just right programmatically is (for me, at least) painful and tedious.

If you could provide a layout editor that lets me edit the layout visually, save and commit that as an XML file, and then spend the majority of my time working on the programming, I could be much more productive. I know this because I’ve done a good bit of iPhone programming (with Xcode and Interface Builder) and that’s what happens. The Apple “division of labor” between programming and UI design tools works great.
[b]

Any chance we can get “Load” and “Save” buttons added to the
online web demo
of Visual Designer that would import/export this XML??
[/b]

If you did that, you will have just made Vaadin 100 times easier to use. I think that would be good for your business :slight_smile:

Some continuation of this discussion in
this thread
.

Slightly off topic, but when developing Java Swing apps, I use SWIXML http://www.swixml.org/

What makes it so powerful, is that it just builds swing apps, it doesn’t try to be yet another gui toolkit. What I find myself doing when I use a component I haven’t used before, is I code it using real Java code, and once up and running, I work out how the same can be expressed using XML…

I would love that vaadin has the same type of markup…, just so long as that the XML defines real Vaddin components, and everything that can be done in XML can continue to be done using code. The XML should be an addition to the development process, not a replacement…

On the subject of listeners, further up the thread, Swixml does this by defining an action attribute…

the Xml:

the Java, in the instance variable declarations…

public Action pressAction = new AbstractAction(){
actionPerformed(ActionEvent e){
System.out.println(“Button Pressed”);
}
}

Hi Guys,

I have developed a maven plugin which compiles YAML UI definition files to java classes at pre-compile time.

For example, the source file YAML file:


## Vaadin View
---
package: org.fdmtech.yamlcrunch.demo
name: TestGraph
imports:
  - &vl com.vaadin.ui.VerticalLayout
  - &button com.vaadin.ui.Button
  - &window com.vaadin.ui.Window
object:
  - !comp
    <class>: *window
    <name>: root
    caption: Test window
    <children>:
      - !comp
        <class>: *vl
        <name>: layout
        <children>:
          - !comp
            <class>: *button
            <name>: button
            caption: Click here

Generates the java source:


package org.fdmtech.yamlcrunch.demo;

import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Button;
import com.vaadin.ui.Window;

public class TestGraph {

    public Window root;
    public VerticalLayout layout;
    public Button button;

    protected final void init() {
        // Create components
        root = new Window();
        layout = new VerticalLayout();
        button = new Button();
        // Setup
        root.setCaption("Test window");
        button.setCaption("Click here");
        // Hierarchy
        root.addComponent(layout);
        layout.addComponent(button);
    }

    public TestGraph() {
        init();
    }

}

Then you can use it as:


public class MyApplication extends Application {

    @Override
    public void init() {

        TestGraph view = new TestGraph();
        setMainWindow(view.root);

        view.button.addListener(new Button.ClickListener() {
            @Override
            public void buttonClick(ClickEvent event) {
                event.getButton().setCaption("Clicked!!!");
            }
        });
    }
}

Pros:

  • No runtime dependencies
  • Generated classes can be extended
  • Definition errors are detected at compiletime

What do you think about this approach?

I want to publish the plugin to the community, is anyone interested?

I would like to see this approach as an alternative.