Integration of a native component into the generic user interface allows using such component in a large number of screens with little effort, just like the basic platform components. Full integration requires the following steps:
-
Create the component interface. Interfaces are usually located in the GUI module, available to both client types – Web and Desktop. If the component should be implemented for one client type only, it can be placed in the Web or Desktop module directly. The example below implements the component for Web Client only.
The component interface should be derived from
com.haulmont.cuba.gui.components.Component
or any of its inheritors, for exampleDatasourceComponent
orField
:package com.company.myproject.gui.components; import com.haulmont.cuba.gui.components.Component; public interface MyComponent extends Component { String NAME = "myComponent"; int getSomeParameter(); void setSomeParameter(int value); }
It is recommended to define the
NAME
constant in the interface. The constant should define the name of the component as a string, used for obtaining the component through theComponentsFactory
. This is also used as the name of the component’s XML element in the XML screen descriptors. -
Create the component implementation class in the web module.
It is recommended to derive the class from
com.haulmont.cuba.web.gui.components.WebAbstractComponent
or one of its inheritors, for exampleWebAbstractField
. A native component instance should be created in the class constructor, and the GUI interface calls should be delegated to it:package com.company.myproject.web.components; import com.company.myproject.gui.components.MyComponent; import com.haulmont.cuba.web.gui.components.WebAbstractComponent; public class WebMyComponent extends WebAbstractComponent<org.vaadin.someaddon.SomeComponent> implements MyComponent { public WebMyComponent() { component = new org.vaadin.someaddon.SomeComponent(); } @Override public int getSomeParameter() { return component.getSomeParameter(); } @Override public void setSomeParameter(boolean value) { component.setSomeParameter(value); } }
-
Create a class implementing the
ComponentPalette
interface and return a map of custom components and their implementation classes from thegetComponents()
method:package com.company.myproject.web; import com.company.myproject.gui.components.MyComponent; import com.company.myproject.web.components.WebMyComponent; import com.haulmont.cuba.gui.ComponentPalette; import com.haulmont.cuba.gui.components.Component; import com.haulmont.cuba.gui.xml.layout.ComponentLoader; import java.util.HashMap; import java.util.Map; public class AppComponentPalette implements ComponentPalette { @Override public Map<String, Class<? extends Component>> getComponents() { Map<String, Class<? extends Component>> components = new HashMap<>(); components.put(MyComponent.NAME, WebMyComponent.class); return components; } @Override public Map<String, Class<? extends ComponentLoader>> getLoaders() { return Collections.emptyMap(); } }
The instance of the component palette must be registered in the application. This can be done in the App class initialization block:
package com.company.myproject.web; import com.haulmont.cuba.web.DefaultApp; import com.haulmont.cuba.web.gui.WebUIPaletteManager; public class App extends DefaultApp { static { WebUIPaletteManager.registerPalettes(new AppComponentPalette()); } }
-
At this point, the new GUI component can be retrieved via the
ComponentsFactory
:@Inject private BoxLayout box; @Inject private ComponentsFactory componentsFactory; @Override public void init(Map<String, Object> params) { MyComponent myComponent = componentsFactory.createComponent(MyComponent.NAME); box.addComponent(myComponent); ... }
-
In order to support component declaration in screen XML-descriptors, create a component loader class, implementing
com.haulmont.cuba.gui.xml.layout.ComponentLoader
. It is recommended to derive the loader class fromcom.haulmont.cuba.gui.xml.layout.loaders.ComponentLoader
or any of its inheritors. The loader operates with the component GUI interface only, so it is common for all client types, and can be located in the gui module. The minimal implementation should call theloadComponent()
method, which creates the component instance and sets its common properties, such as ID or size, taken from XML. Any custom component properties can be initialized afterwards:package com.company.myproject.gui.loaders; import com.company.myproject.gui.components.MyComponent; import com.haulmont.cuba.gui.components.Component; import com.haulmont.cuba.gui.xml.layout.*; import org.dom4j.Element; public class MyComponentLoader extends ComponentLoader { public MyComponentLoader(Context context, LayoutLoaderConfig config, ComponentsFactory factory) { super(context, config, factory); } @Override public Component loadComponent(ComponentsFactory factory, Element element, Component parent) { MyComponent component = (MyComponent) super.loadComponent(factory, element, parent); String someParameter = element.attributeValue("someParameter"); if (someParameter != null) { component.setSomeParameter(Integer.valueOf(someParameter)); } return component; } }
The loader must be registered by the
getLoaders()
method of the previously created component palette:public class AppComponentPalette implements ComponentPalette { ... @Override public Map<String, Class<? extends ComponentLoader>> getLoaders() { Map<String, Class<? extends ComponentLoader>> loaders = new HashMap<>(); loaders.put(MyComponent.NAME, MyComponentLoader.class); return loaders; } }
-
Now the component can be used in XML-descriptors of your project:
<layout> <myComponent id="someId" width="100%" someParameter="10"/> </layout>
In order to enable autocomplete for component name and attributes in IDE, define your own XSD and include it in the screens:
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd" xmlns:app="http://schemas.company.com/app/0.1/app-components.xsd" ...> <layout> <app:myComponent id="someId" width="100%" someParameter="10"/> </layout>
Section 5.8.6.2, “Example of Integrating a Vaadin Component into the Generic UI” covers the process of integrating the IntStepper component, used for changing integer values incrementally.