The fields are just IntegerField but by using a class that extends it to help setting them correctly, please disregard the vertical issues, I guess we will be able to solve that using css.
Here is the code of the custom IntegerField :
public class I18NIntStepper extends IntegerField
{
public I18NIntStepper()
{
}
public I18NIntStepper(final String caption, final Long min, final Long max, final Integer step, final boolean nullable)
{
super(I18NBundle.convert(caption));
init(min, max, nullable);
}
@Override
public void setLabel(String label)
{
super.setLabel(I18NBundle.convert(label));
}
private void init(Long min, final Long max, boolean nullable)
{
setStepButtonsVisible(true);
this.setMin(min.intValue());
this.setMax(max.intValue());
this.setValue(null);
this.setStep(1);
this.setWidth("150px");
}
}
Here is the code for the component :
public class Steppers extends CustomField<Long>
{
private static final Long ONE_YEAR = 365L;
@PropertyId("day")
private I18NIntStepper intSDay;
@PropertyId("hour")
private I18NIntStepper intSHour;
@PropertyId("minute")
private I18NIntStepper intSMin;
@PropertyId("second")
private I18NIntStepper intSSec;
@PropertyId("millisecond")
private I18NIntStepper intSMs;
@PropertyId("negative")
private final I18NCheckBox cbDisabled = new I18NCheckBox("Disabled");
private final List<I18NIntStepper> listFields = new ArrayList<>();
private final HorizontalLayout layout = new HorizontalLayout();
private Binder<Time> binder;
public Steppers()
{
add(v8_initContent());
}
@Override
protected Long generateModelValue()
{
return v8_getValue();
}
@Override
protected void setPresentationValue(Long newPresentationValue)
{
v8_doSetValue(newPresentationValue);
}
public Steppers(final String caption, final Granularity granularity, final Long min, final Long max, final Integer step, final boolean nullable, final boolean enabled)
{
this();
super.setLabel(caption);
initFields(granularity, min, max, step, nullable, enabled);
}
public Steppers(Granularity granularity, long steppersMin, long steppersMax, int step, boolean nullable, boolean enabled)
{
this(null, granularity, steppersMin, steppersMax, step, nullable, enabled);
}
public void initFields(final Granularity granularity, final Long min, final Long max, final Integer step, final boolean nullable, final boolean enabled)
{
switch (granularity)
{
case JHMIN:
intSDay = new I18NIntStepper("Day", 0L, ONE_YEAR, step, nullable);
intSHour = new I18NIntStepper("Hour", 0L, TimeUnit.DAYS.toHours(1) - 1, step, nullable);
intSMin = new I18NIntStepper("Minute", 0L, TimeUnit.HOURS.toMinutes(1) - 1, step, nullable);
addFields(intSDay, intSHour, intSMin);
break;
case MIN:
intSMin = new I18NIntStepper("Minute", 0L, TimeUnit.HOURS.toMinutes(1) - 1, step, nullable);
addFields(intSMin);
break;
case MINSEC:
intSSec = new I18NIntStepper("Second", 0L, TimeUnit.MINUTES.toSeconds(1) - 1, step, nullable);
intSMs = new I18NIntStepper("Millisecond", 0L, TimeUnit.SECONDS.toMillis(1) - 1, step, nullable);
addFields(intSSec, intSMs);
break;
case SEC:
intSSec = new I18NIntStepper("Second", 0L, TimeUnit.MINUTES.toSeconds(1) - 1, step, nullable);
addFields(intSSec);
break;
default:
intSMs = new I18NIntStepper("Millisecond", min, max, step, nullable);
addFields(intSMs);
break;
}
for (final I18NIntStepper field : listFields)
{
layout.add(field);
}
if (enabled)
{
layout.add(cbDisabled);
cbDisabled.addValueChangeListener((ValueChangeEvent<Boolean> event) ->
{
setEnabled(!event.getValue());
super.setEnabled(true);
cbDisabled.setEnabled(true);
});
}
binder = new Binder<>(Time.class);
binder.bindInstanceFields(this);
layout.setMargin(false);
}
public Long v8_getValue()
{
if (binder.getBean() != null)
{
return binder.getBean().getTimeMs();
}
else
{
return null;
}
}
protected Component v8_initContent()
{
return layout;
}
protected void v8_doSetValue(Long value)
{
if (value != null)
{
Time t = new Time(value);
binder.setBean(t);
}
else
{
binder.setBean(null);
}
}
public void setEnabled(boolean enabled)
{
super.setEnabled(enabled);
for (I18NIntStepper field : listFields)
{
field.setEnabled(enabled);
}
cbDisabled.setEnabled(enabled);
}
@Override
public void setLabel(String label)
{
super.setLabel(I18NBundle.convert(label));
}
private void addFields(final I18NIntStepper... fields)
{
Collections.addAll(listFields, fields);
}
}
As for the code that produce the form, it will be quite difficult to share it as it’s a programmatic form generator class that use both bean reflection and a resource file that will tell what do display in the form and how to do it.
Just for a reference, here is how it looks in the vaadin 8 app :
I noticied that the checkbox label is not displayed at the same position, I guess I need to use a theme variant to make it shown on top