X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=org.simantics.interop.update%2Fsrc%2Forg%2Fsimantics%2Finterop%2Fupdate%2Fmodel%2FModelUpdate.java;h=4e1cc4fed37efb8decac9616d92662fd2aad1cd7;hb=b7493f55002eb0e11f3d38b578adfe0292cd2c98;hp=553396b48750f5d72f26e077c1dfc5d87779b827;hpb=51ca3975e1d4137e189e5e0beedc4efd137af142;p=simantics%2Finterop.git diff --git a/org.simantics.interop.update/src/org/simantics/interop/update/model/ModelUpdate.java b/org.simantics.interop.update/src/org/simantics/interop/update/model/ModelUpdate.java index 553396b..4e1cc4f 100644 --- a/org.simantics.interop.update/src/org/simantics/interop/update/model/ModelUpdate.java +++ b/org.simantics.interop.update/src/org/simantics/interop/update/model/ModelUpdate.java @@ -1,47 +1,81 @@ package org.simantics.interop.update.model; +import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.HashSet; +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.VirtualGraph; import org.simantics.db.WriteGraph; +import org.simantics.db.common.request.ReadRequest; +import org.simantics.db.common.request.WriteRequest; 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.Pair; public abstract class ModelUpdate { - private GraphChanges changes; + private Resource oldModel; // old model that is going to be updated (User modified model) + private Resource newModel; // new model that contains the updates (New design model) + private Resource originalModel; // original model (optional) that is used for detecting and retaining user made changes (Old design model) + + private GraphChanges changes; // changes between old /new private UpdateTree updateTree; private UpdateList updateList; - private GraphChanges changes2; + private GraphChanges changes2; // changes between original / old private UpdateTree updateTree2; private UpdateList updateList2; - private GraphChanges changes3; + private GraphChanges changes3; // changes between original / new private UpdateTree updateTree3; private UpdateList updateList3; + private UpdateNode3 updateNode3; + private List filters = new ArrayList(); + private List userFilters = new ArrayList(); boolean init = false; + private int chunkSize = -1; public void setInput(Resource oldModel, Resource newModel) throws DatabaseException { setInput(oldModel, newModel, null, false); } + /** + * Initialises the ModelUpdate with given input + * @param oldModel the model that is going to be updated (User modified model) + * @param newModel the model containing updates (New design model) + * @param originalModel the model that is used for detecting and retaining user made changes (Old design model). Parameter can be null. + * @param newDistinct when originalModel is given, additions to the old and the new model (when compared to the original model) are forced to be distinct. + * @throws DatabaseException + */ public void setInput(Resource oldModel, Resource newModel, Resource originalModel, boolean newDistinct) throws DatabaseException{ - addFilters(filters); + 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 // compare the original and the old model @@ -49,20 +83,31 @@ public abstract class ModelUpdate { 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)); - updateTree2 = getUpdateTree(changes2); - updateList2 = getUpdateList(changes2); + comparator2.dispose(); + if (monitor.isCanceled()) { + dispose(); + return; + } + changes2 = getSession().syncRequest(createFilterRead(changes2, filters)); + Pair chg2 = createChangeObjects(changes2, null); + updateTree2 = chg2.first; + updateList2 = chg2.second; // compare the original and the new model Pair 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)); + comparator2.dispose(); + changes3 = getSession().syncRequest(createFilterRead(changes3, filters)); + } + if (monitor.isCanceled()) { + dispose(); + return; } Pair result = getChanges(oldModel,newModel); @@ -102,30 +147,218 @@ public abstract class ModelUpdate { } } } - comparator.test(getSession()); + if (monitor.isCanceled()) { + dispose(); + return; + } + comparator.test(getSession(), monitor); + monitor.setTaskName("Processing changes..."); + monitor.subTask(""); changes = comparator.getChanges(); - changes = getSession().syncRequest(new FilterChangesRead(changes)); - updateTree = getUpdateTree(changes); - updateList = getUpdateList(changes); + comparator.dispose(); + changes = getSession().syncRequest(createFilterRead(changes, filters)); + Pair chg = createChangeObjects(changes, monitor); + if (chg == null) { + dispose(); + return; + } + updateTree = chg.first; + updateList = chg.second; + if (userFilters.size() != 0) { + refreshUserFilters(); + } if (originalModel != null) { - createDefaultSelections(); + defaultSelections(); } + init = true; + } + + public void setInput(Resource oldModel, Resource newModel, GraphChanges changes, IProgressMonitor monitor) throws DatabaseException{ + if (!oldModel.equals(changes.getResource1()) || + !newModel.equals(changes.getResource2())) { + throw new DatabaseException("GraphChanges does not match input models"); + } + this.changes = getSession().syncRequest(createFilterRead(changes, filters)); + Pair chg = createChangeObjects(changes, monitor); + if (chg == null) { + dispose(); + return; + } + updateTree = chg.first; + updateList = chg.second; + if (userFilters.size() != 0) { + refreshUserFilters(); + } + + if (originalModel != null) { + defaultSelections(); + } init = true; } + public void addFilter(ChangeFilter filter) { + if (init) + throw new IllegalStateException("ModelUpdate has been initialized, adjusting filters is no longer possible."); + filters.add(filter); + + } + + public List getFilters() { + return Collections.unmodifiableList(filters); + } + + /** + * Adds an user filter. Use refreshUserFilters() to apply the changes. + * @param filter + */ + public void addUserFilter(ChangeFilter2 filter) { + userFilters.add(filter); + } + + /** + * Removes an user filter. Use refreshUserFilters() to apply the changes. + * @param filter + */ + public void removeUserFilter(ChangeFilter2 filter) { + userFilters.remove(filter); + } + + /** + * Clears user filters. Use refreshUserFilters() to apply the changes. + */ + public void clearUserFilters() { + userFilters.clear(); + } + + public List getUserFilters() { + return userFilters; + } + + public int getChunkSize() { + return chunkSize; + } + public void setChunkSize(int chunkSize) { + this.chunkSize = chunkSize; + } + + public void refreshUserFilters() throws DatabaseException{ + // use user filters to set visible flags of changes. + // First, set all changes visible. + Deque stack = new ArrayDeque<>(); + stack.push(updateTree.getRootNode()); + while (!stack.isEmpty()) { + UpdateNode n = stack.pop(); + n.setVisible(true); + stack.addAll(n.getChildren()); + } + for (PropertyChange pc : updateList.getChanges()) { + pc.setVisible(true); + } + if (userFilters.size() > 0) { + 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 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 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); + } + } + } + }); + } + } protected abstract Pair 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.getModifications()); + + protected Pair createChangeObjects(GraphChanges changes, IProgressMonitor monitor) throws DatabaseException{ + if (monitor != null) { + if (monitor.isCanceled()) + return null; + monitor.subTask("Processing structural changes"); + } + UpdateTree updateTree = getUpdateTree(changes, monitor); + if (monitor != null) { + if (monitor.isCanceled()) + return null; + monitor.subTask("Processing property changes"); + } + UpdateList updateList = getUpdateList(changes, monitor); + if (monitor != null) { + if (monitor.isCanceled()) + return null; + monitor.subTask("Postprocessing changes"); + } + postProcess(updateTree, updateList); + return new Pair(updateTree, updateList); } - protected void addFilters(List filters) { - + protected abstract UpdateTree getUpdateTree(GraphChanges changes, IProgressMonitor monitor) throws DatabaseException; + protected UpdateList getUpdateList(GraphChanges changes, IProgressMonitor monitor) throws DatabaseException { + return new UpdateList(changes, changes.getModifications()); + } + + + protected void postProcess(UpdateTree updateTree, UpdateList updateList) throws DatabaseException{ + + } + + public Resource getOldModel() { + return oldModel; + } + + public Resource getNewModel() { + return newModel; + } + + public Resource getOriginalModel() { + return originalModel; } public boolean isInit() { @@ -157,52 +390,112 @@ public abstract class ModelUpdate { } public UpdateTree getUpdateTree3() throws DatabaseException{ - if (updateTree3 == null && changes3 != null) - updateTree3 = getUpdateTree(changes3); + if (updateTree3 == null && changes3 != null) { + Pair 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 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 { - Layer0Utils.addCommentMetadata(graph, "Apply all model updates"); - graph.markUndoPoint(); - for (Pair mod : updateList.getChanges()) { - applyLiteralChange(graph, mod); - } - updateList.clear(); + List list = updateList.getChanges(); + apply(graph, list, "Apply all model updates"); updateTree.getUpdateOps().applyAll(graph); } public void applySelected(WriteGraph graph) throws DatabaseException { - Layer0Utils.addCommentMetadata(graph, "Apply selected model updates"); - graph.markUndoPoint(); - HashSet> changes = new HashSet<>(updateList.getSelected()); - for (Pair mod : changes) { - updateList.removeChange(mod); - applyLiteralChange(graph, mod); + List list = new ArrayList(); + for (PropertyChange mod : updateList.getChanges()) { + if (mod.selected()) + list.add(mod); } + apply(graph, list, "Apply selected model updates"); updateTree.getUpdateOps().applySelected(graph); } - protected void applyLiteralChange(WriteGraph graph, Pair mod) throws DatabaseException { - if (mod.second == null) { - graph.deny(mod.first); - return; - } - Resource s = changes.getComparable().getLeft(mod.second.getSubject()); - Resource pred = mod.second.getPredicate(); - if (graph.hasValue(mod.second.getObject())) { - Object value = graph.getValue(mod.second.getObject()); - graph.claimLiteral(s, pred, value); + public void applyAll(Session session, VirtualGraph vg) throws DatabaseException { + List list = updateList.getChanges(); + apply(session, list, "Apply all model updates", vg); + + updateTree.getUpdateOps().applyAll(session, vg); + } + + public void applySelected(Session session, VirtualGraph vg) throws DatabaseException { + List list = new ArrayList(); + for (PropertyChange mod : updateList.getChanges()) { + if (mod.selected()) + list.add(mod); + } + apply(session, list, "Apply selected model updates", vg); + + updateTree.getUpdateOps().applySelected(session, vg); + + } + + protected void apply(WriteGraph graph, List list, String message) throws DatabaseException { + Layer0Utils.addCommentMetadata(graph, message); + graph.markUndoPoint(); + for (PropertyChange mod : list) { + mod.apply(graph); + } + } + + protected void apply(Session session, List list, String message, VirtualGraph vg) throws DatabaseException { + if (getChunkSize() > 0) { + for (int s = 0; s < list.size(); ) { + int e = s + getChunkSize(); + if (e > list.size()) + e = list.size(); + List subList = list.subList(s, e); + if (s == 0) { + session.syncRequest(new WriteRequest(vg) { + public void perform(WriteGraph graph) throws DatabaseException { + Layer0Utils.addCommentMetadata(graph, message); + graph.markUndoPoint(); + } + }); + } + session.syncRequest(new WriteRequest(vg) { + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + for (PropertyChange mod : subList) { + mod.apply(graph); + } + } + }); + s = e; + } } else { - graph.deny(s,pred); + session.syncRequest(new WriteRequest(vg) { + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + Layer0Utils.addCommentMetadata(graph, message); + graph.markUndoPoint(); + for (PropertyChange mod : list) { + mod.apply(graph); + } + } + }); } } @@ -211,53 +504,108 @@ public abstract class ModelUpdate { return Simantics.getSession(); } + public Read createFilterRead(GraphChanges changes, List filters) { + return new FilterChangesRead(changes, filters); + } + - private class FilterChangesRead implements Read { + public static class FilterChangesRead implements Read { private GraphChanges changes; - public FilterChangesRead(GraphChanges changes) { + private List filters; + + public FilterChangesRead(GraphChanges changes, List filters) { this.changes = changes; + this.filters = filters; } @Override public GraphChanges perform(ReadGraph graph) throws DatabaseException { return filterChanges(graph, changes); } + + /** + * Filters changes: + * 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 + * @param changes + * @return + * @throws DatabaseException + */ + protected GraphChanges filterChanges(ReadGraph g, GraphChanges changes) throws DatabaseException + { + + List modifications = new ArrayList(); + + for (Modification mod : changes.getModifications()) { + + boolean accept = true; + for (ChangeFilter filter : filters) { + if (!filter.accept(g, mod)) { + accept = false; + break; + } + } + if (accept) + modifications.add(mod); + } + List deletions = new ArrayList(); + 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 additions = new ArrayList(); + 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, Modification change) throws DatabaseException; + public boolean acceptAddition(ReadGraph g, Statement addition) throws DatabaseException; + public boolean acceptDeletion(ReadGraph g, Statement deletion) throws DatabaseException; } /** - * Filters changes: - * 1. Changes that are not essential for model update (changes that can be found when the models are axcatly the same) - * 2. Runs custom filters for value changes. + * Interface for user defined filters. * - * @param g - * @param changes - * @return - * @throws DatabaseException + * This filter only affects visible flags. + * + * @author luukkainen + * */ - protected GraphChanges filterChanges(ReadGraph g, GraphChanges changes) throws DatabaseException - { - - List> modifications = new ArrayList>(); - - for (Pair mod : changes.getModifications()) { - - boolean accept = true; - for (ChangeFilter filter : filters) { - if (!filter.accept(g, mod)) { - accept = false; - break; - } - } - if (accept) - modifications.add(mod); - } - GraphChanges newChanges = new GraphChanges(changes.getResource1(),changes.getResource2(),changes.getDeletions(), changes.getAdditions(), modifications, changes.getComparable()); - return newChanges; - } - - public interface ChangeFilter { - public boolean accept(ReadGraph g, Pair change) throws DatabaseException; + 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; } @@ -281,12 +629,14 @@ public abstract class ModelUpdate { } @Override - public boolean accept(ReadGraph g, Pair 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; @@ -302,17 +652,30 @@ public abstract class ModelUpdate { 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; + } } - protected void createDefaultSelections() { + public void defaultSelections() { + if (changes3 == null) { + return; + } // select all changes for (Entry op : updateTree.getUpdateOps().getResourceMap().entrySet()) { op.getValue().select(true); } - for (Pair pair : updateList.getChanges()) { - updateList.addSelected(pair); + for (PropertyChange pair : updateList.getChanges()) { + pair.select(true); } // preserve user-made changes (by removing selections) @@ -328,17 +691,17 @@ public abstract class ModelUpdate { } } - for (Pair pair : updateList.getChanges()) { - if (pair.first != null) { + for (PropertyChange pair : updateList.getChanges()) { + if (pair.getFirst() != null) { boolean found = false; - for (Pair pair2 : updateList2.getChanges()) { - if (pair.first.equals(pair2.second)) { + for (PropertyChange pair2 : updateList2.getChanges()) { + if (pair.getFirst() != null && pair.getFirst().equals(pair2.getSecond())) { found = true; break; } } if (found) { - updateList.removeSelected(pair); + pair.select(false); } } } @@ -363,4 +726,20 @@ public abstract class ModelUpdate { 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; + init = false; + } }