RWT: Fix mandatory indicator of checkbox and the various issues related to fields of a sequence box
https://bugs.eclipse.org/bugs/show_bug.cgi?id=432328

Issues fixed related to sequence box:
- Status and mandatory flag of first visible field is not rendered correctly.
  The correct behavior is, that status and mandatory flag of the first visible field is applied to the sequence box, and not displayed on the field anymore.
- Sometimes, the field labels disappear after toggling mandatory or error state. That is for fields that have not an inline label.
- Checkbox labels are rendered to small.

Change-Id: Id8636434bd1447576067ad5bb57f5fabd8059aeb
Reviewed-on: https://git.eclipse.org/r/49035
Tested-by: Hudson CI
Reviewed-by: Daniel Wiehl <daniel.wiehl@bsiag.com>
Reviewed-on: https://git.eclipse.org/r/49039
diff --git a/org.eclipse.scout.rt.ui.rap/src/org/eclipse/scout/rt/ui/rap/ext/ILabelComposite.java b/org.eclipse.scout.rt.ui.rap/src/org/eclipse/scout/rt/ui/rap/ext/ILabelComposite.java
index 6a6b128..9c6d374 100644
--- a/org.eclipse.scout.rt.ui.rap/src/org/eclipse/scout/rt/ui/rap/ext/ILabelComposite.java
+++ b/org.eclipse.scout.rt.ui.rap/src/org/eclipse/scout/rt/ui/rap/ext/ILabelComposite.java
@@ -11,6 +11,7 @@
 package org.eclipse.scout.rt.ui.rap.ext;
 
 import org.eclipse.scout.commons.exception.IProcessingStatus;
+import org.eclipse.scout.rt.client.ui.form.fields.sequencebox.ISequenceBox;
 import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.graphics.Font;
 
@@ -41,6 +42,18 @@
 
   void setVisible(boolean b);
 
+  /**
+   * Changes the visibility of the status label part. Typically, the visibility is set to <code>false</code> for the
+   * first field used in a {@link ISequenceBox}, because rendered as part of the box label.
+   */
+  void setStatusVisible(boolean b);
+
+  /**
+   * Changes the grabbing behavior of this compound label. By default, grabbing is <code>enabled</code>. Typically,
+   * grabbing is disabled for fields used within a {@link ISequenceBox}.
+   */
+  public void setGrabHorizontalEnabled(boolean enabled);
+
   Object getData(String key);
 
   void setData(String key, Object value);
diff --git a/org.eclipse.scout.rt.ui.rap/src/org/eclipse/scout/rt/ui/rap/ext/StatusLabelEx.java b/org.eclipse.scout.rt.ui.rap/src/org/eclipse/scout/rt/ui/rap/ext/StatusLabelEx.java
index 25d75b9..0ffbb0c 100644
--- a/org.eclipse.scout.rt.ui.rap/src/org/eclipse/scout/rt/ui/rap/ext/StatusLabelEx.java
+++ b/org.eclipse.scout.rt.ui.rap/src/org/eclipse/scout/rt/ui/rap/ext/StatusLabelEx.java
@@ -10,6 +10,8 @@
  *******************************************************************************/
 package org.eclipse.scout.rt.ui.rap.ext;
 
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
 import org.eclipse.scout.commons.StringUtility;
 import org.eclipse.scout.commons.exception.IProcessingStatus;
 import org.eclipse.scout.rt.client.ui.form.fields.ScoutFieldStatus;
@@ -26,7 +28,6 @@
 import org.eclipse.swt.graphics.Font;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 import org.eclipse.swt.widgets.Label;
@@ -36,6 +37,12 @@
   private static final String STAR_MARKER = "*";
   private static final String WHITE_SPACE = " ";
 
+  private static final boolean GRAB_HORIZONTAL_LABEL = true; // The label must grab horizontal space in order to allow horizontal alignment of the label.
+  private static final boolean GRAB_HORIZONTAL_STATUS = false;
+
+  // Represents the effective visibility status set for this composite.
+  // This flag is required to still visualize error and mandatory status, even if this composite is not visible.
+  private boolean m_visible = true;
   private IProcessingStatus m_status;
   private boolean m_mandatory;
   private boolean m_enabled;
@@ -69,12 +76,7 @@
   }
 
   protected void createLayout() {
-    GridLayout containerLayout = new GridLayout(2, false);
-    containerLayout.horizontalSpacing = 0;
-    containerLayout.marginHeight = 0;
-    containerLayout.marginWidth = 0;
-    containerLayout.verticalSpacing = 0;
-    setLayout(containerLayout);
+    GridLayoutFactory.swtDefaults().numColumns(2).spacing(0, 0).margins(0, 0).applyTo(this);
   }
 
   protected void createContent(Composite parent, int style) {
@@ -84,13 +86,8 @@
     m_statusLabel = new Label(parent, SWT.NONE);
     getUiEnvironment().getFormToolkit().getFormToolkit().adapt(m_statusLabel, false, false);
 
-    //Make sure the label composite fills the cell so that horizontal alignment of the text works well
-    GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
-    m_label.setLayoutData(data);
-
-    data = new GridData(SWT.RIGHT, SWT.CENTER, false, false);
-    data.verticalIndent = 3;
-    m_statusLabel.setLayoutData(data);
+    GridDataFactory.swtDefaults().align(SWT.FILL, SWT.FILL).grab(GRAB_HORIZONTAL_LABEL, true).applyTo(m_label); // do not make the label to grab horizontal space so that scaling in sequence box works properly.
+    GridDataFactory.swtDefaults().align(SWT.RIGHT, SWT.CENTER).grab(GRAB_HORIZONTAL_STATUS, false).indent(SWT.NONE, 3).applyTo(m_statusLabel);
   }
 
   protected IRwtEnvironment getUiEnvironment() {
@@ -315,6 +312,48 @@
     layout(true, true);
   }
 
+  @Override
+  public void setVisible(boolean visible) {
+    m_visible = visible;
+    super.setVisible(visible);
+  }
+
+  @Override
+  public void setStatusVisible(boolean visible) {
+    // Status
+    boolean statusVisible = visible;
+    Label statusLabel = getStatusLabel();
+    if (statusLabel != null) {
+      GridDataFactory.createFrom((GridData) statusLabel.getLayoutData()).exclude(!statusVisible);
+      statusLabel.setVisible(statusVisible);
+    }
+
+    // Label
+    boolean labelVisible = m_visible && StringUtility.hasText(m_nonMandatoryText);
+    Control label = getLabel();
+    if (label != null) {
+      GridDataFactory.createFrom((GridData) label.getLayoutData()).exclude(!labelVisible);
+      label.setVisible(labelVisible);
+    }
+
+    layout(true, true);
+
+    // Make this compound label visible if status is to be displayed.
+    if (statusVisible) {
+      super.setVisible(true); // super-call to not change the effective 'm_visible' value.
+    }
+    else {
+      super.setVisible(labelVisible); // super-call to not change the effective 'm_visible' value.
+    }
+  }
+
+  @Override
+  public void setGrabHorizontalEnabled(boolean enabled) {
+    // Grabbing should be disabled if being used within a sequence box, so label, mandatory and error flag are displayed as expected.
+    ((GridData) m_label.getLayoutData()).grabExcessHorizontalSpace = (enabled ? GRAB_HORIZONTAL_LABEL : false);
+    ((GridData) m_statusLabel.getLayoutData()).grabExcessHorizontalSpace = (enabled ? GRAB_HORIZONTAL_STATUS : false);
+  }
+
 // delegate methods
   @Override
   public String getText() {
diff --git a/org.eclipse.scout.rt.ui.rap/src/org/eclipse/scout/rt/ui/rap/form/fields/checkbox/IRwtScoutCheckbox.java b/org.eclipse.scout.rt.ui.rap/src/org/eclipse/scout/rt/ui/rap/form/fields/checkbox/IRwtScoutCheckbox.java
index d0ec8d3..e663147 100644
--- a/org.eclipse.scout.rt.ui.rap/src/org/eclipse/scout/rt/ui/rap/form/fields/checkbox/IRwtScoutCheckbox.java
+++ b/org.eclipse.scout.rt.ui.rap/src/org/eclipse/scout/rt/ui/rap/form/fields/checkbox/IRwtScoutCheckbox.java
@@ -11,19 +11,16 @@
 package org.eclipse.scout.rt.ui.rap.form.fields.checkbox;
 
 import org.eclipse.scout.rt.client.ui.form.fields.booleanfield.IBooleanField;
-import org.eclipse.scout.rt.ui.rap.ext.ILabelComposite;
 import org.eclipse.scout.rt.ui.rap.form.fields.IRwtScoutFormField;
 import org.eclipse.swt.widgets.Button;
 
 /**
  * <h3>IRwtScoutCheckbox</h3> ...
- * 
+ *
  * @since 3.7.0 June 2011
  */
 public interface IRwtScoutCheckbox extends IRwtScoutFormField<IBooleanField> {
 
   @Override
   Button getUiField();
-
-  ILabelComposite getPlaceholderLabel();
 }
diff --git a/org.eclipse.scout.rt.ui.rap/src/org/eclipse/scout/rt/ui/rap/form/fields/checkbox/RwtScoutCheckbox.java b/org.eclipse.scout.rt.ui.rap/src/org/eclipse/scout/rt/ui/rap/form/fields/checkbox/RwtScoutCheckbox.java
index 06abab7..e421736 100644
--- a/org.eclipse.scout.rt.ui.rap/src/org/eclipse/scout/rt/ui/rap/form/fields/checkbox/RwtScoutCheckbox.java
+++ b/org.eclipse.scout.rt.ui.rap/src/org/eclipse/scout/rt/ui/rap/form/fields/checkbox/RwtScoutCheckbox.java
@@ -11,7 +11,7 @@
 package org.eclipse.scout.rt.ui.rap.form.fields.checkbox;
 
 import org.eclipse.scout.commons.BooleanUtility;
-import org.eclipse.scout.commons.exception.IProcessingStatus;
+import org.eclipse.scout.commons.StringUtility;
 import org.eclipse.scout.rt.client.ui.form.fields.booleanfield.IBooleanField;
 import org.eclipse.scout.rt.ui.rap.LogicalGridData;
 import org.eclipse.scout.rt.ui.rap.LogicalGridLayout;
@@ -28,31 +28,26 @@
 
   private P_RwtButtonListener m_uiButtonListener;
   private boolean m_mandatoryCached;
-  private StatusLabelEx m_labelPlaceholder;
 
   @Override
   protected void initializeUi(Composite parent) {
     super.initializeUi(parent);
     Composite container = getUiEnvironment().getFormToolkit().createComposite(parent);
-    m_labelPlaceholder = new StatusLabelEx(container, SWT.NONE);
-    getUiEnvironment().getFormToolkit().getFormToolkit().adapt(m_labelPlaceholder, false, false);
-    m_labelPlaceholder.setLayoutData(LogicalGridDataBuilder.createLabel(getScoutObject().getGridData()));
 
+    // The label is used to visualize error and mandatory status.
+    StatusLabelEx label = new StatusLabelEx(container, SWT.NONE);
+    getUiEnvironment().getFormToolkit().getFormToolkit().adapt(label, false, false);
+    label.setLayoutData(LogicalGridDataBuilder.createLabel(getScoutObject().getGridData()));
+
+    // Create the checkbox.
     Button checkbox = getUiEnvironment().getFormToolkit().createButton(container, "", SWT.CHECK | SWT.WRAP);
+    LogicalGridData gd = LogicalGridDataBuilder.createField(getScoutObject().getGridData());
+    gd.useUiWidth = true;
+    gd.weightx = 0;
+    checkbox.setLayoutData(gd);
 
-    LogicalGridData checkboxData = LogicalGridDataBuilder.createField(getScoutObject().getGridData());
-    checkboxData.fillHorizontal = false;
-    checkboxData.useUiWidth = true;
-    checkboxData.weightx = 0;
-    checkbox.setLayoutData(checkboxData);
+    setUiLabel(label);
 
-    // This label is only used to dispatch some properties to the checkbox label (see updateLabel)
-    // So it has to be invisible.
-    StatusLabelEx dispatcherLabel = new StatusLabelEx(container, SWT.NONE);
-    dispatcherLabel.setVisible(false);
-    setUiLabel(dispatcherLabel);
-
-    //
     setUiContainer(container);
     setUiField(checkbox);
 
@@ -69,49 +64,6 @@
     getUiField().addListener(SWT.Selection, m_uiButtonListener);
   }
 
-  /*
-   * (non-Javadoc)
-   * @see org.eclipse.scout.rt.ui.rap.form.fields.RwtScoutValueFieldComposite#setErrorStatusFromScout(org.eclipse.scout.commons.exception.IProcessingStatus)
-   */
-  @Override
-  protected void setErrorStatusFromScout(IProcessingStatus s) {
-    // Update the status of the labelPlaceholder and not the dispatcherLabel
-    m_labelPlaceholder.setStatus(s);
-  }
-
-  /*
-   * (non-Javadoc)
-   * @see org.eclipse.scout.rt.ui.rap.form.fields.RwtScoutFieldComposite#setMandatoryFromScout(boolean)
-   */
-  @Override
-  protected void setMandatoryFromScout(boolean b) {
-    super.setMandatoryFromScout(b);
-//    if (b != m_mandatoryCached) {
-//      m_mandatoryCached = b;
-//      getUiLabel().setMandatory(b); // bsh 2010-10-01: inform the label - some GUIs (e.g. Rayo) might use this information
-//    }
-
-    updateLabel();
-  }
-
-  /**
-   * Updates the label of the checkbox with the properties of the dispatcher label.
-   * This makes sure that the mandatory appearance is reflected correctly.
-   */
-  protected void updateLabel() {
-    if (getUiLabel() instanceof StatusLabelEx) {
-      StatusLabelEx uiLabel = getUiLabel();
-
-      if (uiLabel.getText() != null) {
-        getUiField().setText(uiLabel.getText());
-      }
-
-      getUiField().setFont(uiLabel.getFont());
-      getUiField().setForeground(uiLabel.getForeground());
-      getUiField().setBackground(uiLabel.getBackground());
-    }
-  }
-
   @Override
   protected void detachScout() {
     super.detachScout();
@@ -129,25 +81,8 @@
   }
 
   @Override
-  public StatusLabelEx getPlaceholderLabel() {
-    return m_labelPlaceholder;
-  }
-
-  @Override
-  protected void setLabelVisibleFromScout() {
-    boolean b = getScoutObject().isLabelVisible();
-    if (m_labelPlaceholder != null && b != m_labelPlaceholder.getVisible()) {
-      m_labelPlaceholder.setVisible(b);
-      if (getUiContainer() != null && isCreated()) {
-        getUiContainer().layout(true, true);
-      }
-    }
-  }
-
-  @Override
   protected void setLabelFromScout(String s) {
-    super.setLabelFromScout(s);
-    updateLabel();
+    getUiField().setText(StringUtility.nvl(s, ""));
   }
 
   @Override
diff --git a/org.eclipse.scout.rt.ui.rap/src/org/eclipse/scout/rt/ui/rap/form/fields/sequencebox/RwtScoutSequenceBox.java b/org.eclipse.scout.rt.ui.rap/src/org/eclipse/scout/rt/ui/rap/form/fields/sequencebox/RwtScoutSequenceBox.java
index 53f1798..81854d8 100644
--- a/org.eclipse.scout.rt.ui.rap/src/org/eclipse/scout/rt/ui/rap/form/fields/sequencebox/RwtScoutSequenceBox.java
+++ b/org.eclipse.scout.rt.ui.rap/src/org/eclipse/scout/rt/ui/rap/form/fields/sequencebox/RwtScoutSequenceBox.java
@@ -12,13 +12,11 @@
 
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.eclipse.scout.commons.exception.IProcessingStatus;
-import org.eclipse.scout.rt.client.ui.form.fields.ICompositeField;
 import org.eclipse.scout.rt.client.ui.form.fields.IFormField;
-import org.eclipse.scout.rt.client.ui.form.fields.IValueField;
 import org.eclipse.scout.rt.client.ui.form.fields.booleanfield.IBooleanField;
 import org.eclipse.scout.rt.client.ui.form.fields.sequencebox.ISequenceBox;
 import org.eclipse.scout.rt.ui.rap.LogicalGridData;
@@ -28,13 +26,13 @@
 import org.eclipse.scout.rt.ui.rap.form.fields.IRwtScoutFormField;
 import org.eclipse.scout.rt.ui.rap.form.fields.RwtScoutFieldComposite;
 import org.eclipse.scout.rt.ui.rap.form.fields.RwtScoutFormFieldGridData;
-import org.eclipse.scout.rt.ui.rap.form.fields.checkbox.IRwtScoutCheckbox;
 import org.eclipse.swt.widgets.Composite;
 
 public class RwtScoutSequenceBox extends RwtScoutFieldComposite<ISequenceBox> implements IRwtScoutSequenceBox {
 
-  private PropertyChangeListener m_scoutMandatoryChangeListener;
-  private PropertyChangeListener m_scoutErrorStatusChangeListener;
+  private PropertyChangeListener m_changeListener;
+
+  private Map<IFormField, IRwtScoutFormField> m_fieldMap = new HashMap<IFormField, IRwtScoutFormField>();
 
   @Override
   protected void initializeUi(Composite parent) {
@@ -42,56 +40,32 @@
     StatusLabelEx label = getUiEnvironment().getFormToolkit().createStatusLabel(container, getScoutObject());
 
     Composite fieldContainer = getUiEnvironment().getFormToolkit().createComposite(container);
-    int visibleCount = 0;
     for (IFormField scoutField : getScoutObject().getFields()) {
       IRwtScoutFormField childFormField = getUiEnvironment().createFormField(fieldContainer, scoutField);
+      m_fieldMap.put(scoutField, childFormField);
 
-      ILabelComposite childLabel = null;
-      if (childFormField instanceof IRwtScoutCheckbox) {
-        childLabel = ((IRwtScoutCheckbox) childFormField).getPlaceholderLabel();
+      ILabelComposite childLabel = childFormField.getUiLabel();
+      if (childLabel != null) {
+        childLabel.setGrabHorizontalEnabled(false); // disable grabbing so that mandatory and error status are rendered as expected, and the label is not swallowed.
+        if (childLabel.getLayoutData() instanceof LogicalGridData) {
+          ((LogicalGridData) childLabel.getLayoutData()).widthHint = 0; // Make the label as small as possible
+        }
       }
-      else {
-        childLabel = childFormField.getUiLabel();
-      }
-      if (childLabel != null && childLabel.getLayoutData() instanceof LogicalGridData) {
-        //Make the label as small as possible
-        ((LogicalGridData) childLabel.getLayoutData()).widthHint = 0;
 
-        //Remove the label completely if the formField doesn't actually have a label on the left side
-        if (removeLabelCompletely(childFormField)) {
-          childLabel.setVisible(false);
-        }
-        // <bsh 2010-10-01>
-        // Force an empty, but visible label for all but the first visible fields
-        // within an SequenceBox. This empty status label is necessary to show the
-        // "mandatory" indicator.
-        if (childFormField.getScoutObject() instanceof IFormField) {
-          IFormField childScoutField = ((IFormField) childFormField.getScoutObject());
-          if (childScoutField.isVisible()) {
-            visibleCount++;
-          }
-          if (visibleCount > 1) {
-            if (!childLabel.getVisible()) {
-              // make the label visible, but clear any text
-              childLabel.setVisible(true);
-              childLabel.setText("");
-            }
-          }
-        }
-        // <bsh>
-      }
       // create layout constraints
+      final boolean checkbox = scoutField instanceof IBooleanField;
       RwtScoutFormFieldGridData data = new RwtScoutFormFieldGridData(scoutField) {
         @Override
         public void validate() {
           super.validate();
-          useUiWidth = !getScoutObject().isEqualColumnWidths();
+          useUiWidth = !getScoutObject().isEqualColumnWidths() || checkbox;
           useUiHeight = true;
+          weightx = (checkbox ? 0 : weightx); // to enforce the checkbox to be rendered completely (with its label)
         }
       };
       childFormField.getUiContainer().setLayoutData(data);
-
     }
+
     //
     setUiContainer(container);
     setUiLabel(label);
@@ -100,7 +74,8 @@
     // layout
     fieldContainer.setLayout(new LogicalGridLayout(getGridColumnGapInPixel(), 0));
     container.setLayout(new LogicalGridLayout(1, 0));
-    setChildMandatoryFromScout();
+
+    applyInheritedDecoration();
   }
 
   protected int getGridColumnGapInPixel() {
@@ -134,44 +109,37 @@
     return super.getScoutObject();
   }
 
-  protected void setChildMandatoryFromScout() {
+  /**
+   * Applies the mandatory and error status of the first visible field to the sequence box.
+   */
+  public void applyInheritedDecoration() {
+    // Make the status label part visible for all fields.
+    for (IFormField field : getScoutObject().getFields()) {
+      ILabelComposite label = m_fieldMap.get(field).getUiLabel();
+      if (label != null) {
+        m_fieldMap.get(field).getUiLabel().setStatusVisible(field.isMandatory() || field.getErrorStatus() != null);
+      }
+    }
+
+    // Apply 'mandatory' or 'error' status of the first visible field to the sequence box.
     boolean inheritedMandatory = false;
-    List<IValueField<?>> visibleFields = findVisibleValueFields(getScoutObject());
-    for (IValueField<?> field : visibleFields) {
-      if (field.isMandatory()) {
-        inheritedMandatory = true;
+    IProcessingStatus inheritedErrorStatus = null;
+
+    for (IFormField candidate : getScoutObject().getFields()) {
+      if (candidate.isVisible() && m_fieldMap.get(candidate).getUiLabel() != null) {
+        // This is the first visible field of the sequence box. Hide the status label.
+        m_fieldMap.get(candidate).getUiLabel().setStatusVisible(false);
+
+        inheritedMandatory = candidate.isMandatory();
+        inheritedErrorStatus = candidate.getErrorStatus();
         break;
       }
     }
+
     setMandatoryFromScout(inheritedMandatory);
-  }
-
-  protected void setChildErrorStatusFromScout() {
-    IProcessingStatus inheritedErrorStatus = null;
-    List<IValueField<?>> visibleFields = findVisibleValueFields(getScoutObject());
-    if (visibleFields.size() > 0) {
-      // bsh 2010-10-01: don't inherit error status from other fields than the first visible field
-      inheritedErrorStatus = visibleFields.get(0).getErrorStatus();
-    }
     setErrorStatusFromScout(inheritedErrorStatus);
   }
 
-  protected List<IValueField<?>> findVisibleValueFields(ICompositeField parent) {
-    List<IValueField<?>> valueFields = new LinkedList<IValueField<?>>();
-    for (IFormField field : parent.getFields()) {
-      if (!field.isVisible()) {
-        continue;
-      }
-      if (field instanceof IValueField) {
-        valueFields.add((IValueField<?>) field);
-      }
-      else if (field instanceof ICompositeField) {
-        valueFields.addAll(findVisibleValueFields((ICompositeField) field));
-      }
-    }
-    return valueFields;
-  }
-
   @Override
   protected void setEnabledFromScout(boolean b) {
     // Only change color for the label, the field container should not reflect enabled / disabled state. The child fields handle the state independently.
@@ -186,58 +154,39 @@
   protected void attachScout() {
     super.attachScout();
     // add mandatory change listener on children to decorate my label same as any mandatory child
-    m_scoutMandatoryChangeListener = new PropertyChangeListener() {
+    m_changeListener = new PropertyChangeListener() {
       @Override
       public void propertyChange(PropertyChangeEvent e) {
         Runnable j = new Runnable() {
           @Override
           public void run() {
-            if (getUiContainer() != null && !getUiContainer().isDisposed()) {
-              setChildMandatoryFromScout();
-            }
+            applyInheritedDecoration();
           }
         };
         getUiEnvironment().invokeUiLater(j);
       }
     };
     for (IFormField f : getScoutObject().getFields()) {
-      f.addPropertyChangeListener(IFormField.PROP_MANDATORY, m_scoutMandatoryChangeListener);
-    }
-
-    // add error status change listener on children to decorate my label same as any child with an error status
-    m_scoutErrorStatusChangeListener = new PropertyChangeListener() {
-      @Override
-      public void propertyChange(PropertyChangeEvent e) {
-        Runnable j = new Runnable() {
-          @Override
-          public void run() {
-            setChildErrorStatusFromScout();
-          }
-        };
-        getUiEnvironment().invokeUiLater(j);
-      }
-    };
-    for (IFormField f : getScoutObject().getFields()) {
-      f.addPropertyChangeListener(IFormField.PROP_ERROR_STATUS, m_scoutErrorStatusChangeListener);
+      f.addPropertyChangeListener(IFormField.PROP_VISIBLE, m_changeListener);
+      f.addPropertyChangeListener(IFormField.PROP_LABEL_VISIBLE, m_changeListener);
+      f.addPropertyChangeListener(IFormField.PROP_LABEL, m_changeListener);
+      f.addPropertyChangeListener(IFormField.PROP_MANDATORY, m_changeListener);
+      f.addPropertyChangeListener(IFormField.PROP_ERROR_STATUS, m_changeListener);
     }
   }
 
   @Override
   protected void detachScout() {
-    if (m_scoutMandatoryChangeListener != null) {
+    if (m_changeListener != null) {
       for (IFormField f : getScoutObject().getFields()) {
-        f.removePropertyChangeListener(IFormField.PROP_MANDATORY, m_scoutMandatoryChangeListener);
+        f.addPropertyChangeListener(IFormField.PROP_VISIBLE, m_changeListener);
+        f.addPropertyChangeListener(IFormField.PROP_LABEL_VISIBLE, m_changeListener);
+        f.addPropertyChangeListener(IFormField.PROP_LABEL, m_changeListener);
+        f.addPropertyChangeListener(IFormField.PROP_MANDATORY, m_changeListener);
+        f.addPropertyChangeListener(IFormField.PROP_ERROR_STATUS, m_changeListener);
       }
-      m_scoutMandatoryChangeListener = null;
+      m_changeListener = null;
     }
-
-    if (m_scoutErrorStatusChangeListener != null) {
-      for (IFormField f : getScoutObject().getFields()) {
-        f.removePropertyChangeListener(IFormField.PROP_ERROR_STATUS, m_scoutErrorStatusChangeListener);
-      }
-      m_scoutErrorStatusChangeListener = null;
-    }
-
     super.detachScout();
   }