package org.simantics.interop.update.model; import java.util.ArrayList; import java.util.Collection; import java.util.List; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Statement; import org.simantics.db.WriteGraph; import org.simantics.db.exception.DatabaseException; import org.simantics.interop.test.GraphChanges; import org.simantics.layer0.Layer0; /** * Base class for update operations (adding and deleting objects) * * @author Marko Luukkainen * */ public abstract class UpdateOp { private GraphChanges changes; private boolean selected = false; private boolean manualSelection = false; protected boolean applied = false; protected boolean visible = true; protected boolean enabled = true; private Collection parentOps = new ArrayList(); private Collection subOps = new ArrayList(); public UpdateOp(GraphChanges changes) { this.changes = changes; } public Collection getParentOps() { return parentOps; } public Collection getParentOpsWithClass(Class cls) { List ops = new ArrayList(parentOps.size()); for (UpdateOp op : parentOps) if (cls.isAssignableFrom(op.getClass())) ops.add((T)op); return ops; } public Collection getSubOps() { return subOps; } public Collection getSubOpsWithClass(Class cls) { List ops = new ArrayList(subOps.size()); for (UpdateOp op : subOps) if (cls.isAssignableFrom(op.getClass())) ops.add((T)op); return ops; } public void addParentOp(UpdateOp op) { assert (!op.equals(this)); if (parentOps.contains(op)) return; parentOps.add(op); } public void addSubOp(UpdateOp op) { assert (!op.equals(this)); if (subOps.contains(op)) return; subOps.add(op); } public void removeParentOp(UpdateOp op) { parentOps.remove(op); } public void removeSubOp(UpdateOp op) { subOps.remove(op); } public GraphChanges getChanges() { return changes; } public abstract boolean isAdd(); public abstract boolean isDelete(); public boolean isChange() { return isAdd() || isDelete(); } /** * Should given operation to be applied before this operation. * @param op * @return */ public boolean requiresOp(UpdateOp op) { return false; } /** * Should selection state to be propagated to given op. * @param op parent or sub op of this. * @param select selection flag. * @return */ public boolean selectOp(UpdateOp op, boolean select) { return requiresOp(op); } public boolean select(boolean select) { if (!enabled) return false; if (!isChange()) return false; boolean b = _select(select); if (b) manualSelection = true; return b; } private boolean _select(boolean select) { if (select == selected) return true; if (applied) return false; if (select) { selected = true; manualSelection = false; for (UpdateOp op : parentOps) { if (selectOp(op,true)) op._select(true); } for (UpdateOp op : subOps) { if (selectOp(op,true)) op._select(true); } return true; } else { selected = false; manualSelection = false; for (UpdateOp op : subOps) { if (selectOp(op, false)) op._select(false); else if (!op.manualSelection) op._select(false); } for (UpdateOp op : parentOps) if (selectOp(op, false)) op._select(false); return true; } } public boolean selected() { if (!isChange()) // Non change operations are not really selected, but the selected flag may be used for selection propagation return false; return selected; } public boolean applied() { return applied; } public boolean isVisible() { return visible; } /** * Is change enabled. Disabled changes do not allow changing selected state. * @return */ public boolean enabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public void apply(WriteGraph g) throws DatabaseException { if (applied) return; _apply(g); applied = true; } /** * Applies the changes into the database. * * @param g * @throws DatabaseException */ protected abstract void _apply(WriteGraph g) throws DatabaseException; /** * Returns resource that this operation is changing. * @return */ public abstract Resource getResource(); /** * Returns resource that this operation is changing. * @return */ public abstract Statement getStatement(); /** * Returns resource that this operation created during apply operation. If operation did not add anything, this returns null. * @return */ public abstract Resource getCreatedResource(); public Resource getParentResource(ReadGraph g) throws DatabaseException { Layer0 l0 = Layer0.getInstance(g); return g.getPossibleObject(getResource(), l0.PartOf); } @Override public String toString() { String s = this.getClass().getSimpleName(); if (selected) s += " selected"; if (enabled) s += " enabled"; if (visible) s += " visible"; if (applied) s += " applied"; return s; } }