The template mechanism of scout is intended for that case.
You create abstract template boxes that are new field composites that can then be used in the form (and form data). The template fields/boxes can also be re-used in other forms, so you have an optimized modularization of your form model.
With your example use case the files would more or less look as follows:
******************* FORM *******************
package org.medical.client.core.ui.forms;
import org.eclipse.scout.commons.annotations.FormData;
import org.eclipse.scout.commons.annotations.FormData.SdkCommand;
import org.eclipse.scout.commons.annotations.Order;
import org.eclipse.scout.commons.exception.ProcessingException;
import org.eclipse.scout.rt.client.ui.form.AbstractForm;
import org.eclipse.scout.rt.client.ui.form.AbstractFormHandler;
import org.eclipse.scout.rt.client.ui.form.fields.groupbox.AbstractGroupBox;
import org.eclipse.scout.rt.client.ui.form.fields.tabbox.AbstractTabBox;
import org.medical.client.core.ui.forms.PatientForm.MainBox.TabBox;
import org.medical.client.core.ui.forms.fields.AbstractPatientDetailGroupBox;
import org.medical.client.core.ui.forms.fields.AbstractPatientMedicalInfoGroupBox;
import org.medical.shared.core.Texts;
import org.medical.shared.core.services.process.PatientFormData;
@FormData(value = PatientFormData.class, sdkCommand = SdkCommand.CREATE)
public class PatientForm extends AbstractForm {
public PatientForm() throws ProcessingException {
super();
}
@Override
protected String getConfiguredTitle() {
return Texts.get("Patient");
}
public MainBox getMainBox() {
return (MainBox) getRootGroupBox();
}
public TabBox getTabBox() {
return getFieldByClass(TabBox.class);
}
@Order(10)
public class MainBox extends AbstractGroupBox {
@Order(10)
public class TabBox extends AbstractTabBox {
@Order(10)
public class DetailGroupBox extends AbstractPatientDetailGroupBox {
}
@Order(20)
public class MedicalGroupBox extends AbstractPatientMedicalInfoGroupBox {
}
}
}
public class ModifyHandler extends AbstractFormHandler {
@Override
protected void execLoad() throws ProcessingException {
PatientFormData data = new PatientFormData();
exportFormData(data);
//XXX call service: SERVICES.getService(IPatientProcessService.class).load(data);
importFormData(data);
}
@Override
protected void execStore() throws ProcessingException {
PatientFormData data = new PatientFormData();
exportFormData(data);
//XXX call service: SERVICES.getService(IPatientProcessService.class).store(data);
}
}
}
******************* RE-USABLE TEMPLATE FIELD FOR PERSONAL DETAIL *******************
package org.medical.client.core.ui.forms.fields;
import org.eclipse.scout.commons.annotations.FormData;
import org.eclipse.scout.commons.annotations.FormData.DefaultSubtypeSdkCommand;
import org.eclipse.scout.commons.annotations.FormData.SdkCommand;
import org.eclipse.scout.commons.annotations.Order;
import org.eclipse.scout.rt.client.ui.form.fields.groupbox.AbstractGroupBox;
import org.eclipse.scout.rt.client.ui.form.fields.stringfield.AbstractStringField;
import org.medical.shared.core.Texts;
import org.medical.shared.core.services.process.AbstractPatientDetailGroupBoxData;
@FormData(value = AbstractPatientDetailGroupBoxData.class, sdkCommand = SdkCommand.CREATE, defaultSubtypeSdkCommand = DefaultSubtypeSdkCommand.CREATE)
public abstract class AbstractPatientDetailGroupBox extends AbstractGroupBox {
public AbstractPatientDetailGroupBox() {
super();
}
@Override
protected String getConfiguredLabel() {
return Texts.get("PersonalInfo");
}
@Order(10)
public class FirstNameField extends AbstractStringField {
@Override
protected String getConfiguredLabel() {
return Texts.get("FirstName");
}
}
/*
* ....
*/
}
******************* RE-USABLE TEMPLATE FIELD FOR MEDICAL DETAIL *******************
package org.medical.client.core.ui.forms.fields;
import org.eclipse.scout.commons.annotations.FormData;
import org.eclipse.scout.commons.annotations.FormData.DefaultSubtypeSdkCommand;
import org.eclipse.scout.commons.annotations.FormData.SdkCommand;
import org.eclipse.scout.commons.annotations.Order;
import org.eclipse.scout.rt.client.ui.form.fields.groupbox.AbstractGroupBox;
import org.eclipse.scout.rt.client.ui.form.fields.longfield.AbstractLongField;
import org.medical.shared.core.Texts;
import org.medical.shared.core.services.process.AbstractPatientMedicalInfoGroupBoxData;
@FormData(value = AbstractPatientMedicalInfoGroupBoxData.class, sdkCommand = SdkCommand.CREATE, defaultSubtypeSdkCommand = DefaultSubtypeSdkCommand.CREATE)
public abstract class AbstractPatientMedicalInfoGroupBox extends AbstractGroupBox {
public AbstractPatientMedicalInfoGroupBox() {
super();
}
@Override
protected String getConfiguredLabel() {
return Texts.get("MedicalInfo");
}
@Order(10)
public class BloodSampleIdField extends AbstractLongField {
@Override
protected String getConfiguredLabel() {
return Texts.get("BloodSampleId");
}
}
/*
* ....
*/
}
******************* MAIN FORM DATA *******************
package org.medical.shared.core.services.process;
import org.eclipse.scout.rt.shared.data.form.AbstractFormData;
public class PatientFormData extends AbstractFormData {
private static final long serialVersionUID = 1L;
public PatientFormData() {
}
public DetailGroupBox getDetailGroupBox() {
return getFieldByClass(DetailGroupBox.class);
}
public MedicalGroupBox getMedicalGroupBox() {
return getFieldByClass(MedicalGroupBox.class);
}
public class DetailGroupBox extends AbstractPatientDetailGroupBoxData {
private static final long serialVersionUID = 1L;
public DetailGroupBox() {
}
}
public class MedicalGroupBox extends AbstractPatientMedicalInfoGroupBoxData {
private static final long serialVersionUID = 1L;
public MedicalGroupBox() {
}
}
}
******************* RE-USABLE TEMPLATE FIELD DATA *******************
package org.medical.shared.core.services.process;
import org.eclipse.scout.rt.shared.data.form.ValidationRule;
import java.util.Map;
import org.eclipse.scout.rt.shared.data.form.fields.AbstractValueFieldData;
import org.eclipse.scout.rt.shared.data.form.fields.AbstractFormFieldData;
public abstract class AbstractPatientDetailGroupBoxData extends AbstractFormFieldData {
private static final long serialVersionUID = 1L;
public AbstractPatientDetailGroupBoxData() {
}
public FirstName getFirstName() {
return getFieldByClass(FirstName.class);
}
public class FirstName extends AbstractValueFieldData<String> {
private static final long serialVersionUID = 1L;
public FirstName() {
}
/**
* list of derived validation rules.
*/
@Override
protected void initValidationRules(Map<String, Object> ruleMap) {
super.initValidationRules(ruleMap);
ruleMap.put(ValidationRule.MAX_LENGTH, 4000);
}
}
}
******************* RE-USABLE TEMPLATE FIELD DATA *******************
package org.medical.shared.core.services.process;
import org.eclipse.scout.rt.shared.data.form.fields.AbstractValueFieldData;
import org.eclipse.scout.rt.shared.data.form.fields.AbstractFormFieldData;
public abstract class AbstractPatientMedicalInfoGroupBoxData extends AbstractFormFieldData {
private static final long serialVersionUID = 1L;
public AbstractPatientMedicalInfoGroupBoxData() {
}
public BloodSampleId getBloodSampleId() {
return getFieldByClass(BloodSampleId.class);
}
public class BloodSampleId extends AbstractValueFieldData<Long> {
private static final long serialVersionUID = 1L;
public BloodSampleId() {
}
}
}