To create a custom form component, you need to do the following:
In the vaadin project, create a class for your event:
The constructor must have as its second parameter the relevant data type.
The parameter can be based on the record related to the component record.
getEventProperties()
method so it returns a hashmap of the custom event properties.package com.whitestein.colorpicker.vaadin.util; import java.util.HashMap; import java.util.Map; import com.vaadin.shared.ui.colorpicker.Color; import com.whitestein.lsps.lang.Decimal; import com.whitestein.lsps.lang.exec.RecordHolder; import com.whitestein.lsps.vaadin.ui.components.UIComponent; import com.whitestein.lsps.vaadin.ui.events.UIEvent; public class UIColorPickEvent extends UIEvent { private final Color newColor; public UIColorPickEvent(UIComponent component, Color newColor) { super(component, colorpicker::ColorPickEvent); this.newColor = newColor; } private static RecordHolder toColor(UIComponent context, Color color) { final RecordHolder c = context.getComponentData().getScreen().getScreenContext().getNamespace().createRecord("colorpicker::Color"); c.setProperty("r", new Decimal(color.getRed())); c.setProperty("g", new Decimal(color.getGreen())); c.setProperty("b", new Decimal(color.getBlue())); c.setProperty("a", new Decimal(color.getAlpha())); return c; } @Override //creates java hashmap -> fieldname to value; then creates the uicolorpickevent recordholder; protected Map<String, ?> getEventProperties(UIComponent component) { final Map<String, Object> result = new HashMap<String, Object>(super.getEventProperties(component)); result.put("color", toColor(component, newColor)); return result; } }
To create an example custom component, create a class implementing your component:
It must define a constructor with UIComponentData as its input argument.
Make sure the UIComponentData is defined as a class variable, so you can use it in the getComponentData method.
Create the custom listener
The listener should override the method that creates the event on the component, in the example colorChanged(ColorChangeEvent e), so the event is transformed into our custom event and then fired and enters the event queue when UIComponents.fireAndProcess() method is called.
public UIColorPicker(UIComponentData data) { this.data = data; ColorChangeListener listener = new ColorChangeListener() {   @Override public void colorChanged(ColorChangeEvent event) { final Color newColor = event.getColor(); UIComponents.fireAndProcess(new UIColorPickEvent(UIColorPicker.this, newColor)); }   }; //registered to vaadin's color picker addColorChangeListener(listener); UIComponents.afterCreate(this);
Defines the refresh() method for the component.
The method is called when the component is refreshed.
@Override public void refresh() { Variant.RecordVariant color = Variant.definitionOf(this).getPropertyValue("color").closure() .inScope(this).call().record(); color.checkType("colorpicker::Color").checkPresent(); setColor(toColor(color)); }   private static Color toColor(Variant.RecordVariant color) { return new Color(color.getPropertyValue("r").decimal().get().intValue(), color.getPropertyValue("g").decimal().get().intValue(), color.getPropertyValue("b").decimal().get().intValue(), color.getPropertyValue("a").decimal().or(new Decimal(255)).intValue()); }
package com.whitestein.colorpicker.vaadin.util;   import com.vaadin.shared.ui.colorpicker.Color; import com.vaadin.ui.ColorPicker; import com.vaadin.ui.components.colorpicker.ColorChangeEvent; import com.vaadin.ui.components.colorpicker.ColorChangeListener; import com.whitestein.lsps.lang.Decimal; import com.whitestein.lsps.vaadin.ui.UIComponentData; import com.whitestein.lsps.vaadin.ui.components.UIComponent; import com.whitestein.lsps.vaadin.ui.events.UIEvent; import com.whitestein.lsps.vaadin.util.UIComponents; import com.whitestein.lsps.vaadin.util.Variant;   public class UIColorPicker extends ColorPicker implements UIComponent {   private final UIComponentData data;   public UIColorPicker(UIComponentData data) { this.data = data; ColorChangeListener listener = new ColorChangeListener() {   @Override public void colorChanged(ColorChangeEvent event) { final Color newColor = event.getColor(); UIComponents.fireAndProcess(new UIColorPickEvent(UIColorPicker.this, newColor)); }   }; //registered to vaadin's color picker addColorChangeListener(listener); UIComponents.afterCreate(this); }   @Override public void refresh() { Variant.RecordVariant color = Variant.definitionOf(this).getPropertyValue("color").closure() .inScope(this).call().record(); color.checkType("colorpicker::Color").checkPresent(); setColor(toColor(color)); }   private static Color toColor(Variant.RecordVariant color) { return new Color(color.getPropertyValue("r").decimal().get().intValue(), color.getPropertyValue("g").decimal().get().intValue(), color.getPropertyValue("b").decimal().get().intValue(), color.getPropertyValue("a").decimal().or(new Decimal(255)).intValue()); }   @Override public UIComponentData getComponentData() { return data; } }
Modify the LspsAppComponentFactory
class: uncomment the createComponent
method and add the constructor call for your component that is called when the respective Record is requested.
package org.eko.ekoapp.vaadin.util;   import org.eko.ekoapp.vaadin.components.UIText;   import com.whitestein.lsps.vaadin.LspsAppConnector; import com.whitestein.lsps.vaadin.ui.UIComponentData; import com.whitestein.lsps.vaadin.ui.UIComponentFactoryImpl; import com.whitestein.lsps.vaadin.ui.components.UIComponent;   public class MyComponentFactory extends UIComponentFactoryImpl {
public MyComponentFactory(LspsAppConnector connector) throws NullPointerException { super(connector); }   @Override protected UIComponent createComponent(UIComponentData componentData) { String type = componentData.getComponentDefinition().getType() .getFullName(); if (type.equals("customComponentModule::TextComponentRecord")) { return new UIText(componentData); } return super.createComponent(componentData); } }
To create a support for your component in PDS, do the following:
Create a data type model that reflects the components, events, and any related data types defined in your application: make sure their are located in the module and have the name defined in their implementation (in the example, the color picker, color, and color-change listener).
Note that a data type must have the correct super types:
source
that holds the component that produced the event and a field with the data the implementation requires.new colorpicker::ColorPickListener( refresh -> {a->{PICKER}}, handle -> {e:ColorPickEvent-> color:=e.color; debugLog({->"Color was picked. " + e})} )