import java.util.ArrayDeque;
import java.util.ArrayList;
-import java.util.Collection;
+import java.util.Collections;
import java.util.Deque;
import java.util.List;
import java.util.Map.Entry;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
import org.simantics.Simantics;
import org.simantics.db.ReadGraph;
import org.simantics.db.Resource;
import org.simantics.db.Session;
import org.simantics.db.Statement;
import org.simantics.db.WriteGraph;
+import org.simantics.db.common.request.ReadRequest;
import org.simantics.db.exception.DatabaseException;
import org.simantics.db.layer0.util.Layer0Utils;
import org.simantics.db.request.Read;
import org.simantics.interop.test.GraphChanges;
+import org.simantics.interop.test.GraphChanges.Modification;
import org.simantics.interop.test.GraphComparator;
-import org.simantics.utils.datastructures.BijectionMap;
import org.simantics.utils.datastructures.Pair;
public abstract class ModelUpdate {
private UpdateTree updateTree3;
private UpdateList updateList3;
+ private UpdateNode3 updateNode3;
+
private List<ChangeFilter> filters = new ArrayList<ChangeFilter>();
- private List<ChangeFilter> userFilters = new ArrayList<ChangeFilter>();
+ private List<ChangeFilter2> userFilters = new ArrayList<ChangeFilter2>();
boolean init = false;
* @throws DatabaseException
*/
public void setInput(Resource oldModel, Resource newModel, Resource originalModel, boolean newDistinct) throws DatabaseException{
+ this.setInput(oldModel, newModel, originalModel, newDistinct, null);
+ }
+ public void setInput(Resource oldModel, Resource newModel, Resource originalModel, boolean newDistinct, IProgressMonitor monitor) throws DatabaseException{
+
this.oldModel = oldModel;
this.newModel = newModel;
this.originalModel = originalModel;
+
+ if (monitor == null)
+ monitor = new NullProgressMonitor();
// addFilters(filters);
if (originalModel != null) {
// tree way comparison
GraphComparator comparator2 = result2.first;
if (result2.second != null)
showWarning(result2.second);
- comparator2.test(getSession());
+ comparator2.test(getSession(), monitor);
changes2 = comparator2.getChanges();
- changes2 = getSession().syncRequest(new FilterChangesRead(changes2, filters));
- updateTree2 = getUpdateTree(changes2);
- updateList2 = getUpdateList(changes2);
+ if (monitor.isCanceled())
+ return;
+ changes2 = getSession().syncRequest(createFilterRead(changes2, filters));
+ Pair<UpdateTree, UpdateList> chg2 = createChangeObjects(changes2, null);
+ updateTree2 = chg2.first;
+ updateList2 = chg2.second;
// compare the original and the new model
Pair<GraphComparator,String> result3 = getChanges(originalModel,newModel);
GraphComparator comparator3 = result3.first;
if (result3.second != null)
showWarning(result3.second);
- comparator3.test(getSession());
+ comparator3.test(getSession(), monitor);
changes3 = comparator3.getChanges();
- changes3 = getSession().syncRequest(new FilterChangesRead(changes3, filters));
+ changes3 = getSession().syncRequest(createFilterRead(changes3, filters));
}
+ if (monitor.isCanceled())
+ return;
Pair<GraphComparator,String> result = getChanges(oldModel,newModel);
GraphComparator comparator = result.first;
}
}
}
- comparator.test(getSession());
+ if (monitor.isCanceled())
+ return;
+ comparator.test(getSession(), monitor);
+ monitor.setTaskName("Processing changes...");
+ monitor.subTask("");
changes = comparator.getChanges();
- changes = getSession().syncRequest(new FilterChangesRead(changes, filters));
- updateTree = getUpdateTree(changes);
- updateList = getUpdateList(changes);
+ changes = getSession().syncRequest(createFilterRead(changes, filters));
+ Pair<UpdateTree, UpdateList> chg = createChangeObjects(changes, monitor);
+ updateTree = chg.first;
+ updateList = chg.second;
if (userFilters.size() != 0) {
refreshUserFilters();
}
if (originalModel != null) {
defaultSelections();
}
-
init = true;
}
}
+ public List<ChangeFilter> getFilters() {
+ return Collections.unmodifiableList(filters);
+ }
+
/**
* Adds an user filter. Use refreshUserFilters() to apply the changes.
* @param filter
*/
- public void addUserFilter(ChangeFilter filter) {
+ public void addUserFilter(ChangeFilter2 filter) {
userFilters.add(filter);
}
* Removes an user filter. Use refreshUserFilters() to apply the changes.
* @param filter
*/
- public void removeUserFilter(ChangeFilter filter) {
+ public void removeUserFilter(ChangeFilter2 filter) {
userFilters.remove(filter);
}
userFilters.clear();
}
+ public List<ChangeFilter2> getUserFilters() {
+ return userFilters;
+ }
+
public void refreshUserFilters() throws DatabaseException{
// use user filters to set visible flags of changes.
// First, set all changes visible.
pc.setVisible(true);
}
if (userFilters.size() > 0) {
- // Create filtered changes
- List<ChangeFilter> combined = new ArrayList<>(filters);
- combined.addAll(userFilters);
- GraphChanges filteredChanges = getSession().syncRequest(new FilterChangesRead(changes, combined));
- UpdateTree updateTreeF = getUpdateTree(filteredChanges);
- UpdateList updateListF = getUpdateList(filteredChanges);
- // hide changes that are not contained within the filtered changes.
- applyVisibleFlags(updateTree.getRootNode(), updateTreeF.getRootNode());
- applyVisibleFlags(updateList.getChanges(), updateListF.getChanges());
+ if (changes2 != null && changes3 != null) {
+ getUpdateTree3();
+ }
+ getSession().syncRequest(new ReadRequest() {
+
+ @Override
+ public void run(ReadGraph graph) throws DatabaseException {
+ for (PropertyChange change : updateList.getChanges()) {
+ boolean visible = true;
+ for (ChangeFilter2 filter : userFilters) {
+ if (!filter.accept(graph, change)) {
+ visible = false;
+ break;
+ }
+ }
+ change.setVisible(visible);
+ }
+ if (updateTree3 != null) {
+ Deque<UpdateNode3> stack = new ArrayDeque<>();
+ stack.add(getUpdateNode3());
+ while (!stack.isEmpty()) {
+ UpdateNode3 n = stack.pop();
+ boolean visible = true;
+ for (ChangeFilter2 filter : userFilters) {
+ if (!filter.accept(graph, n)) {
+ visible = false;
+ break;
+ }
+ }
+ n.setVisible(visible);
+ for (UpdateNode3 c : n.getChildren())
+ stack.push(c);
+ }
+ } else {
+
+ Deque<UpdateNode> stack = new ArrayDeque<>();
+ stack.add(updateTree.getRootNode());
+ while (!stack.isEmpty()) {
+ UpdateNode n = stack.pop();
+ boolean visible = true;
+ for (ChangeFilter2 filter : userFilters) {
+ if (!filter.accept(graph, n)) {
+ visible = false;
+ break;
+ }
+ }
+ n.setVisible(visible);
+ for (UpdateNode c : n.getChildren())
+ stack.push(c);
+ }
+ }
+ }
+ });
}
}
- private void applyVisibleFlags(UpdateNode l, UpdateNode r) {
- BijectionMap<UpdateNode, UpdateNode> comparable = new BijectionMap<>();
- for (UpdateNode lc : l.getChildren()) {
- for (UpdateNode rc : r.getChildren()) {
- if (comparable.containsRight(rc))
- continue;
- if (lc.getResource() != null) {
- if (lc.getResource().equals(rc.getResource())) {
-
- comparable.map(lc, rc);
- break;
- }
- } else if (rc.getResource() == null){
- UpdateOp lop = lc.getOp();
- UpdateOp rop = rc.getOp();
- if (lop.getStatement() != null && lop.getStatement().equals(rop.getStatement())) {
- comparable.map(lc, rc);
- break;
- }
- }
- }
- }
- for (UpdateNode lc : l.getChildren()) {
- if (!comparable.containsLeft(lc))
- lc.setVisible(false);
- }
- for (Entry<UpdateNode, UpdateNode> entry : comparable.getEntries()) {
- applyVisibleFlags(entry.getKey(), entry.getValue());
- }
- }
-
- private void applyVisibleFlags(Collection<PropertyChange> l, Collection<PropertyChange> r) {
- BijectionMap<PropertyChange, PropertyChange> comparable = new BijectionMap<>();
- for (PropertyChange lc : l) {
- for (PropertyChange rc : r) {
- if (comparable.containsRight(rc))
- continue;
- if (lc.getFirst().equals(rc.getFirst())) {
- comparable.map(lc, rc);
- }
- }
- }
- for (PropertyChange lc : l) {
- if (!comparable.containsLeft(lc))
- lc.setVisible(false);
- }
-
+ protected abstract Pair<GraphComparator,String> getChanges(Resource r1, Resource r2) throws DatabaseException;
+
+ protected Pair<UpdateTree, UpdateList> createChangeObjects(GraphChanges changes, IProgressMonitor monitor) throws DatabaseException{
+ if (monitor != null)
+ monitor.subTask("Processing structural changes");
+ UpdateTree updateTree = getUpdateTree(changes);
+ if (monitor != null)
+ monitor.subTask("Processing property changes");
+ UpdateList updateList = getUpdateList(changes);
+ if (monitor != null)
+ monitor.subTask("Postprocessing changes");
+ postProcess(updateTree, updateList);
+ return new Pair<UpdateTree, UpdateList>(updateTree, updateList);
}
- protected abstract Pair<GraphComparator,String> getChanges(Resource r1, Resource r2) throws DatabaseException;
protected abstract UpdateTree getUpdateTree(GraphChanges changes) throws DatabaseException;
protected UpdateList getUpdateList(GraphChanges changes) throws DatabaseException {
return new UpdateList(changes, changes.getModifications());
}
+
+ protected void postProcess(UpdateTree updateTree, UpdateList updateList) throws DatabaseException{
+
+ }
+
public Resource getOldModel() {
return oldModel;
}
}
public UpdateTree getUpdateTree3() throws DatabaseException{
- if (updateTree3 == null && changes3 != null)
- updateTree3 = getUpdateTree(changes3);
+ if (updateTree3 == null && changes3 != null) {
+ Pair<UpdateTree, UpdateList> chg3 = createChangeObjects(changes3, null);
+ updateTree3 = chg3.first;
+ updateList3 = chg3.second;
+ }
return updateTree3;
}
public UpdateList getUpdateList3() throws DatabaseException {
- if (updateList3 == null && changes3 != null)
- updateList3 = getUpdateList(changes3);
+ if (updateList3 == null && changes3 != null) {
+ Pair<UpdateTree, UpdateList> chg3 = createChangeObjects(changes3, null);
+ updateTree3 = chg3.first;
+ updateList3 = chg3.second;
+ }
return updateList3;
}
+
+ public UpdateNode3 getUpdateNode3() throws DatabaseException {
+ if (updateNode3 == null && changes2 != null && changes3 != null) {
+ updateNode3 = UpdateNode3.getCombinedTree(this);
+ }
+ return updateNode3;
+ }
public void applyAll(WriteGraph graph) throws DatabaseException {
public void applySelected(WriteGraph graph) throws DatabaseException {
Layer0Utils.addCommentMetadata(graph, "Apply selected model updates");
graph.markUndoPoint();
+
+ updateTree.getUpdateOps().applySelected(graph);
+
for (PropertyChange mod : updateList.getChanges()) {
if (mod.selected())
mod.apply(graph);
}
-
- updateTree.getUpdateOps().applySelected(graph);
}
return Simantics.getSession();
}
+ public Read<GraphChanges> createFilterRead(GraphChanges changes, List<ChangeFilter> filters) {
+ return new FilterChangesRead(changes, filters);
+ }
+
- private class FilterChangesRead implements Read<GraphChanges> {
+ public static class FilterChangesRead implements Read<GraphChanges> {
private GraphChanges changes;
private List<ChangeFilter> filters;
/**
* Filters changes:
- * 1. Changes that are not essential for model update (changes that can be found when the models are axcatly the same)
+ * 1. Changes that are not essential for model update (changes that can be found when the models are exactly the same)
* 2. Runs custom filters for value changes.
*
* @param g
protected GraphChanges filterChanges(ReadGraph g, GraphChanges changes) throws DatabaseException
{
- List<Pair<Statement,Statement>> modifications = new ArrayList<Pair<Statement,Statement>>();
+ List<Modification> modifications = new ArrayList<Modification>();
- for (Pair<Statement, Statement> mod : changes.getModifications()) {
+ for (Modification mod : changes.getModifications()) {
boolean accept = true;
for (ChangeFilter filter : filters) {
if (accept)
modifications.add(mod);
}
- GraphChanges newChanges = new GraphChanges(changes.getResource1(),changes.getResource2(),changes.getDeletions(), changes.getAdditions(), modifications, changes.getComparable());
+ List<Statement> deletions = new ArrayList<Statement>();
+ for (Statement del : changes.getDeletions()) {
+
+ boolean accept = true;
+ for (ChangeFilter filter : filters) {
+ if (!filter.acceptDeletion(g, del)) {
+ accept = false;
+ break;
+ }
+ }
+ if (accept)
+ deletions.add(del);
+ }
+ List<Statement> additions = new ArrayList<Statement>();
+ for (Statement del : changes.getAdditions()) {
+
+ boolean accept = true;
+ for (ChangeFilter filter : filters) {
+ if (!filter.acceptAddition(g, del)) {
+ accept = false;
+ break;
+ }
+ }
+ if (accept)
+ additions.add(del);
+ }
+
+ GraphChanges newChanges = new GraphChanges(changes.getResource1(),changes.getResource2(),deletions, additions, modifications, changes.getComparable());
return newChanges;
}
}
-
+ /**
+ * Interface for built-in filters that are used for processing raw change data before forming UpdateTree + UpdateList
+ * @author luukkainen
+ *
+ */
public interface ChangeFilter {
- public boolean accept(ReadGraph g, Pair<Statement, Statement> change) throws DatabaseException;
+ public boolean accept(ReadGraph g, Modification change) throws DatabaseException;
+ public boolean acceptAddition(ReadGraph g, Statement addition) throws DatabaseException;
+ public boolean acceptDeletion(ReadGraph g, Statement deletion) throws DatabaseException;
+ }
+
+ /**
+ * Interface for user defined filters.
+ *
+ * This filter only affects visible flags.
+ *
+ * @author luukkainen
+ *
+ */
+ public interface ChangeFilter2 {
+ public boolean accept(ReadGraph g, PropertyChange change) throws DatabaseException;
+ public boolean accept(ReadGraph g, UpdateNode change) throws DatabaseException;
+ public boolean accept(ReadGraph g, UpdateNode3 change) throws DatabaseException;
}
}
@Override
- public boolean accept(ReadGraph g, Pair<Statement, Statement> change) throws DatabaseException {
+ public boolean accept(ReadGraph g, Modification change) throws DatabaseException {
//filter floating point values that have less than 1% difference.
- if (!g.hasValue(change.first.getObject()) || !g.hasValue(change.second.getObject()))
+ if (change.getLeftStm() == null || change.getRightStm() == null)
return true;
- Object v1 = g.getValue(change.first.getObject());
- Object v2 = g.getValue(change.second.getObject());
+ if (!g.hasValue(change.getLeftStm().getObject()) || !g.hasValue(change.getRightStm().getObject()))
+ return true;
+ Object v1 = g.getValue(change.getLeftStm().getObject());
+ Object v2 = g.getValue(change.getRightStm().getObject());
if (v1 instanceof Double && v2 instanceof Double) {
double d1 = (Double)v1;
return true;
}
+
+ @Override
+ public boolean acceptAddition(ReadGraph g, Statement addition) throws DatabaseException {
+ return true;
+ }
+
+ @Override
+ public boolean acceptDeletion(ReadGraph g, Statement deletion) throws DatabaseException {
+ return true;
+ }
}
public void defaultSelections() {
if (pair.getFirst() != null) {
boolean found = false;
for (PropertyChange pair2 : updateList2.getChanges()) {
- if (pair.getFirst().equals(pair2.getSecond())) {
+ if (pair.getFirst() != null && pair.getFirst().equals(pair2.getSecond())) {
found = true;
break;
}
public void removeListener(WarningListener listener) {
warningListeners.remove(listener);
}
+
+ public void dispose() {
+ changes = null;
+ changes2 = null;
+ changes3 = null;
+ filters = null;
+ userFilters = null;
+ updateList = null;
+ updateList2 = null;
+ updateList3 = null;
+ updateTree = null;
+ updateTree2 = null;
+ updateTree3 = null;
+ updateNode3 = null;
+ }
}