/** * */ package cz.cuni.mff.peckam.java.origamist.common; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Iterator; import java.util.List; import javax.xml.bind.annotation.XmlTransient; import cz.cuni.mff.peckam.java.origamist.utils.Arrays; import cz.cuni.mff.peckam.java.origamist.utils.ChangeNotification; import cz.cuni.mff.peckam.java.origamist.utils.CustomPropertyChangeSupport; import cz.cuni.mff.peckam.java.origamist.utils.HasBoundProperties; import cz.cuni.mff.peckam.java.origamist.utils.HasObservableProperties; import cz.cuni.mff.peckam.java.origamist.utils.ObservableList; import cz.cuni.mff.peckam.java.origamist.utils.ObservableList.ChangeTypes; import cz.cuni.mff.peckam.java.origamist.utils.ObservablePropertiesSupport; import cz.cuni.mff.peckam.java.origamist.utils.ObservablePropertyEvent; import cz.cuni.mff.peckam.java.origamist.utils.ObservablePropertyListener; import cz.cuni.mff.peckam.java.origamist.utils.Observer; import cz.cuni.mff.peckam.java.origamist.utils.PropagatedObservablePropertyEvent; import cz.cuni.mff.peckam.java.origamist.utils.PropagatedPropertyChangeEvent; /** * The base of all JAXB-generated classes. * * @author Martin Pecka */ @XmlTransient public abstract class GeneratedClassBase implements HasBoundProperties, HasObservableProperties { /** The object handling property changes. */ protected transient final CustomPropertyChangeSupport support = new CustomPropertyChangeSupport(this); /** The object handling observable property changes. */ protected transient final ObservablePropertiesSupport observableSupport = new ObservablePropertiesSupport(this); /** * The object this one is attached to by a child monitor. Used mainly to recognize if this object is being monitored * or not at all. */ private transient GeneratedClassBase attachedTo = null; /** The parent object's property this object is attached to. Will be null for elements of list fields. */ private transient String attachedToProperty = null; /** A child monitor listener - re-propagates all events propagated from a child. */ private transient final PropertyChangeListener childListener; /** An observable child monitor listener - re-propagates all events propagated from a child. */ private transient final ObservablePropertyListener<?> observableChildListener; public GeneratedClassBase() { childListener = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (!(evt instanceof PropagatedPropertyChangeEvent)) return; if (evt instanceof PropagatedPropertyChangeEvent && ((PropagatedPropertyChangeEvent) evt).getDeepSource() == GeneratedClassBase.this) return; support.firePropertyChange(new PropagatedPropertyChangeEvent(GeneratedClassBase.this, getAttachedToProperty(), evt)); } }; observableChildListener = new ObservablePropertyListener<Object>() { @Override public void changePerformed(ObservablePropertyEvent<?> evt) { if (evt instanceof PropagatedObservablePropertyEvent && ((PropagatedObservablePropertyEvent<?>) evt).getDeepSource() == GeneratedClassBase.this) return; observableSupport.fireObservablePropertyChange(new PropagatedObservablePropertyEvent<Object>( GeneratedClassBase.this, getAttachedToProperty(), evt)); } }; // monitor all changes in children to manage the child monitor listeners support.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (evt instanceof PropagatedPropertyChangeEvent) { return; } if (evt.getOldValue() != null) { if (evt.getOldValue() instanceof HasBoundProperties) ((HasBoundProperties) evt.getOldValue()).removeAllListeners(childListener); if (evt.getOldValue() instanceof HasObservableProperties) ((HasObservableProperties) evt.getOldValue()) .removeAllObservablePropertyListeners(observableChildListener); if (evt.getOldValue() instanceof GeneratedClassBase && ((GeneratedClassBase) evt.getOldValue()).attachedTo == GeneratedClassBase.this) { ((GeneratedClassBase) evt.getOldValue()).attachedTo = null; ((GeneratedClassBase) evt.getOldValue()).attachedToProperty = null; } } if (evt.getNewValue() != null && (evt.getNewValue() instanceof HasBoundProperties || evt.getNewValue() instanceof HasObservableProperties)) { if (!(evt.getNewValue() instanceof GeneratedClassBase) || (((GeneratedClassBase) evt.getNewValue()).attachedTo == null && !Arrays.contains( getNonChildProperties(), evt.getPropertyName()))) { if (evt.getNewValue() instanceof HasBoundProperties) ((HasBoundProperties) evt.getNewValue()).addPropertyChangeListener(childListener); if (evt.getNewValue() instanceof HasObservableProperties) ((HasObservableProperties) evt.getNewValue()) .addObservablePropertyListener(observableChildListener); if (evt.getNewValue() instanceof GeneratedClassBase) { ((GeneratedClassBase) evt.getNewValue()).attachedTo = GeneratedClassBase.this; ((GeneratedClassBase) evt.getNewValue()).attachedToProperty = evt.getPropertyName(); } } } else if (getAttachedToProperty() != null) { support.firePropertyChange(new PropagatedPropertyChangeEvent(GeneratedClassBase.this, getAttachedToProperty(), evt)); } } }); } /** * Finish the initialization of the generated class after all fields are properly initialized. */ protected void init() { if (getListFields() != null) { assert getListProperties() != null; List<String> properties = java.util.Arrays.asList(getListProperties()); Iterator<String> propertiesIt = properties.iterator(); for (final List<?> list : getListFields()) { assert propertiesIt.hasNext(); final String propertyName = propertiesIt.next(); if (!(list instanceof ObservableList<?>)) continue; ((ObservableList<?>) list).addObserver(new Observer<Object>() { @Override public void changePerformed(ChangeNotification<?> change) { if (change.getChangeType() != ChangeTypes.ADD) { if (change.getOldItem() != null) { if (change.getOldItem() instanceof HasBoundProperties) ((HasBoundProperties) change.getOldItem()).removeAllListeners(childListener); if (change.getOldItem() instanceof HasObservableProperties) ((HasObservableProperties) change.getOldItem()) .removeAllObservablePropertyListeners(observableChildListener); if (change.getOldItem() instanceof GeneratedClassBase && ((GeneratedClassBase) change.getOldItem()).attachedTo == GeneratedClassBase.this) { ((GeneratedClassBase) change.getOldItem()).attachedTo = null; ((GeneratedClassBase) change.getOldItem()).attachedToProperty = null; } } } if (change.getChangeType() != ChangeTypes.REMOVE) { if (change.getItem() != null) { if (!(change.getItem() instanceof GeneratedClassBase) || (((GeneratedClassBase) change.getItem()).attachedTo == null && !Arrays .contains(getNonChildProperties(), propertyName))) { if (change.getItem() instanceof HasBoundProperties) ((HasBoundProperties) change.getItem()) .addPropertyChangeListener(childListener); if (change.getItem() instanceof HasObservableProperties) ((HasObservableProperties) change.getItem()) .addObservablePropertyListener(observableChildListener); if (change.getItem() instanceof GeneratedClassBase) { ((GeneratedClassBase) change.getItem()).attachedTo = GeneratedClassBase.this; ((GeneratedClassBase) change.getItem()).attachedToProperty = propertyName; } } } } observableSupport.fireObservablePropertyChange(new PropagatedObservablePropertyEvent<Object>( GeneratedClassBase.this, getAttachedToProperty(), new ObservablePropertyEvent<Object>( GeneratedClassBase.this, propertyName, change))); } }); } } } /** * @return the attachedTo */ public GeneratedClassBase getAttachedTo() { return attachedTo; } /** * @return the attachedToProperty */ public String getAttachedToProperty() { return attachedToProperty != null ? attachedToProperty : (attachedTo != null ? attachedTo.attachedToProperty : null); } /** * Override this method in all child classes having observable list fields. * * @return All observable list fields of this class (will be used to setup property change listeners on these * fields). */ protected List<?>[] getListFields() { return null; } /** * Override this method in all child classes having observable list fields. * * @return All observable list fields' property names in the same order as getListFields(). */ protected String[] getListProperties() { return null; } /** * @return An array of all properties not referring to the "children" of this object (eg. referring to siblings or * parents). */ protected String[] getNonChildProperties() { return null; } @Override public List<String> removeAllListeners(PropertyChangeListener param0) { return this.support.removeAllListeners(param0); } @Override public void addPropertyChangeListener(PropertyChangeListener param0) { this.support.addPropertyChangeListener(param0); } @Override public void addPropertyChangeListener(String param0, PropertyChangeListener param1) { this.support.addPropertyChangeListener(param0, param1); } @Override public void removePropertyChangeListener(String param0, PropertyChangeListener param1) { this.support.removePropertyChangeListener(param0, param1); } @Override public void removePropertyChangeListener(PropertyChangeListener param0) { this.support.removePropertyChangeListener(param0); } @Override public void addPropertyChangeListener(PropertyChangeListener listener, String... propertyName) { support.addPropertyChangeListener(listener, propertyName); } @Override public void removePropertyChangeListener(PropertyChangeListener listener, String... propertyName) { support.removePropertyChangeListener(listener, propertyName); } @Override public void addPrefixedPropertyChangeListener(PropertyChangeListener listener, String... prefix) { support.addPrefixedPropertyChangeListener(listener, prefix); } @Override public void removePrefixedPropertyChangeListener(PropertyChangeListener listener) { support.removePrefixedPropertyChangeListener(listener); } @Override public void addObservablePropertyListener(ObservablePropertyListener<?> listener) { observableSupport.addObservablePropertyListener(listener); } @Override public void addObservablePropertyListener(String property, ObservablePropertyListener<?> listener) { observableSupport.addObservablePropertyListener(property, listener); } @Override public void removeObservablePropertyListener(String property, ObservablePropertyListener<?> listener) { observableSupport.removeObservablePropertyListener(property, listener); } @Override public void removeObservablePropertyListener(ObservablePropertyListener<?> listener) { observableSupport.removeObservablePropertyListener(listener); } @Override public List<String> removeAllObservablePropertyListeners(ObservablePropertyListener<?> listener) { return observableSupport.removeAllObservablePropertyListeners(listener); } @Override public void addObservablePropertyListener(ObservablePropertyListener<?> listener, String... property) { observableSupport.addObservablePropertyListener(listener, property); } @Override public void removeObservablePropertyListener(ObservablePropertyListener<?> listener, String... property) { observableSupport.removeObservablePropertyListener(listener, property); } @Override public <T> void addPrefixedObservablePropertyListener(ObservablePropertyListener<T> listener, String... prefix) { observableSupport.addPrefixedObservablePropertyListener(listener, prefix); } @Override public <T> void removePrefixedObservablePropertyListener(ObservablePropertyListener<T> listener) { observableSupport.removePrefixedObservablePropertyListener(listener); } }