code: protected void childStateChanged(PropertyChangeEvent evt) {
  		if (FormModel.DIRTY_PROPERTY.equals(evt.getPropertyName())) {
  			Object source = evt.getSource();
  
  			if (source instanceof FieldMetadata) {
  				FieldMetadata metadata = (FieldMetadata) source;
  				if (metadata.isDirty()) {
  					dirtyValueAndFormModels.add(metadata);
  				}
  				else {
  					dirtyValueAndFormModels.remove(metadata);
  				}
  			}
  			else if (source instanceof FormModel) {
  				FormModel formModel = (FormModel) source;
  				if (formModel.isDirty()) {
  					dirtyValueAndFormModels.add(formModel);
  				}
  				else {
  					dirtyValueAndFormModels.remove(formModel);
  				}
  			}
  			else {
  				DirtyTrackingValueModel valueModel = (DirtyTrackingValueModel) source;
  				if (valueModel.isDirty()) {
  					dirtyValueAndFormModels.add(valueModel);
  				}
  				else {
  					dirtyValueAndFormModels.remove(valueModel);
  				}
  			}
  			dirtyUpdated();
  		}
  		else if (COMMITTABLE_PROPERTY.equals(evt.getPropertyName())) {
  			committableUpdated();
  		}
  	}
docs: Events from the child form model or value models that have side-effects
  on this form model should be handled here. This includes:
  
  <ul>
  <li><em>Dirty state:</em> when a child is dirty, the parent should be
  dirty.</li>
  <li><em>Committable state:</em> when a child is committable, the
  parent might be committable as well. The committable state of the parent
  should be taken into account and revised when a child sends this event.</li>
  </ul>
  
  Note that we include value models and their metadata as being children.
  As these are low level models, they cannot be parents and therefore don't
  show up in
  {@link AbstractFormModel#parentStateChanged(PropertyChangeEvent)}.