/** * */ package cz.cuni.mff.peckam.java.origamist.modelstate; import cz.cuni.mff.peckam.java.origamist.utils.ChangeNotification; 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.Observer; /** * Represents a fold on the paper. * * @author Martin Pecka */ public class Fold implements Cloneable { /** * The lines this fold consists of. */ protected ObservableList<FoldLine> lines = new ObservableList<FoldLine>(); /** * Id of the step this fold originated in. */ protected Integer originatingStepId = null; /** * */ public Fold() { addObservers(); } /** * @param originatingStepId Id of the step this fold originated in. */ public Fold(Integer originatingStepId) { this(); this.originatingStepId = originatingStepId; } /** * Add all needed observers to this object's fields. */ protected void addObservers() { lines.addObserver(getLinesObserver()); } /** * @return The lines this fold consists of. */ public ObservableList<FoldLine> getLines() { return lines; } /** * @return Id of the step this fold originated in. */ public Integer getOriginatingStepId() { return originatingStepId; } /** The observer of the list of lines that automatically assigns this fold as the parent for all new lines. */ private transient Observer<FoldLine> linesObserver = null; /** * @return The observer of the list of lines that automatically assigns this fold as the parent for all new lines. */ private Observer<FoldLine> getLinesObserver() { if (linesObserver == null) { linesObserver = new Observer<FoldLine>() { @Override public void changePerformed(ChangeNotification<? extends FoldLine> change) { if (change.getChangeType() != ChangeTypes.ADD) { change.getOldItem().setFold(null); } if (change.getChangeType() != ChangeTypes.REMOVE) { change.getItem().setFold(Fold.this); } } }; } return linesObserver; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((lines == null) ? 0 : lines.hashCode()); result = prime * result + ((originatingStepId == null) ? 0 : originatingStepId.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Fold other = (Fold) obj; if (originatingStepId == null) { if (other.originatingStepId != null) return false; } else if (!originatingStepId.equals(other.originatingStepId)) return false; if (lines == null) { if (other.lines != null) return false; } else if (!lines.equals(other.lines)) return false; return true; } @Override public String toString() { return "Fold [originatingStepId=" + originatingStepId + ", lines=" + lines + "]"; } /** * <p> * <b>Cloning this class will not trigger any external observers on the lines field to be triggered, although the * contents of that list are themselves cloned. The observers are, however, copied along with the list (not cloned). * Note that the referenced ModelTriangles in any FoldLines aren't cloned.</b> * </p> * * {@inheritDoc} */ @Override public Fold clone() { try { Fold result = (Fold) super.clone(); result.lines = new ObservableList<FoldLine>(); // create a new linesObserver and add it to the list of lines result.linesObserver = null; result.lines.addObserver(result.getLinesObserver()); for (FoldLine l : this.lines) { // calling add() will trigger the linesObserver which sets the cloned Fold as the parent of the fold // lines result.lines.add(l.clone()); } // add the rest of observers to avoid calling them when cloning the lines list for (Observer<? super FoldLine> o : lines.getObservers()) { if (o != linesObserver) result.lines.addObserver(o); } return result; } catch (CloneNotSupportedException e) { return null; } } }