X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.structural.synchronization.client%2Fsrc%2Forg%2Fsimantics%2Fstructural%2Fsynchronization%2FStructuralChangeFlattener.java;fp=bundles%2Forg.simantics.structural.synchronization.client%2Fsrc%2Forg%2Fsimantics%2Fstructural%2Fsynchronization%2FStructuralChangeFlattener.java;h=7a1fbdc47d3a61a9c3e5a7358fae26c0850bccf1;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.structural.synchronization.client/src/org/simantics/structural/synchronization/StructuralChangeFlattener.java b/bundles/org.simantics.structural.synchronization.client/src/org/simantics/structural/synchronization/StructuralChangeFlattener.java new file mode 100644 index 000000000..7a1fbdc47 --- /dev/null +++ b/bundles/org.simantics.structural.synchronization.client/src/org/simantics/structural/synchronization/StructuralChangeFlattener.java @@ -0,0 +1,128 @@ +package org.simantics.structural.synchronization; + +import gnu.trove.map.hash.THashMap; +import gnu.trove.map.hash.TObjectIntHashMap; + +import java.util.ArrayList; +import java.util.Map; + +import org.simantics.databoard.Bindings; +import org.simantics.db.ReadGraph; +import org.simantics.db.Resource; +import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener; +import org.simantics.db.exception.DatabaseException; +import org.simantics.db.layer0.genericrelation.DependencyChanges; +import org.simantics.db.layer0.request.ModelInstances; +import org.simantics.db.layer0.variable.Variable; +import org.simantics.db.layer0.variable.Variables; +import org.simantics.layer0.Layer0; +import org.simantics.structural.stubs.StructuralResource2; +import org.simantics.structural2.utils.StructuralChangeVisitor; +import org.simantics.structural2.utils.StructuralMetadataUtils; + +/** + * Browses change metadata from the requested revision and + * marks the components in a flat structural configuration + * where changes have been occured. + * + * @author Hannu Niemistö + */ +public class StructuralChangeFlattener { + + private static Variable[] EMPTY_VARIABLE_ARRAY = new Variable[0]; + + public static TObjectIntHashMap getModifiedComponents(ReadGraph graph, + Variable rootVariable, long fromRevision) throws DatabaseException { + Visitor visitor = new Visitor(graph, rootVariable); + StructuralMetadataUtils.visitStructuralChangesFrom(graph, + Variables.getModel(graph, rootVariable), + fromRevision, visitor); + return visitor.modifiedComponents; + } + + public static TObjectIntHashMap getModifiedComponents(ReadGraph graph, + Variable rootVariable, DependencyChanges.Change[] changes) throws DatabaseException { + Visitor visitor = new Visitor(graph, rootVariable); + StructuralMetadataUtils.visitStructuralChangesFrom(graph, + Variables.getModel(graph, rootVariable), + changes, visitor); + return visitor.modifiedComponents; + } + + private static class Visitor implements StructuralChangeVisitor { + + Variable rootVariable; + Resource rootResource; + Resource model; + THashMap visitedVariables = new THashMap(); + Layer0 L0; + StructuralResource2 STR; + TObjectIntHashMap modifiedComponents = new TObjectIntHashMap(); + + public Visitor(ReadGraph graph, Variable rootVariable) throws DatabaseException { + this.rootVariable = rootVariable; + this.rootResource = rootVariable.getRepresents(graph); + this.model = Variables.getModel(graph, rootVariable); + this.L0 = Layer0.getInstance(graph); + this.STR = StructuralResource2.getInstance(graph); + } + + @Override + public void visitComponentChange(ReadGraph graph, Resource component, boolean componentItselfModified) + throws DatabaseException { + Variable[] variables = visitedVariables.get(component); + if(variables == null) { + variables = visitUnseenComponent(graph, component); + visitedVariables.put(component, variables); + } + if(componentItselfModified) + for(Variable variable : variables) + modifiedComponents.put(variable, 2); + else + for(Variable variable : variables) + modifiedComponents.putIfAbsent(variable, 1); + } + + private Variable[] visitUnseenComponent(ReadGraph graph, Resource component) throws DatabaseException { + // Is root? + if(component.equals(rootResource)) + return new Variable[] { rootVariable }; + + // Check if this a component type root + Resource componentType = graph.getPossibleObject(component, STR.Defines); + if(componentType != null) { + ArrayList result = new ArrayList(); + Map instances = graph.syncRequest(new ModelInstances(model, componentType), TransientCacheAsyncListener.>instance()); + for(Resource instance : instances.values()) { + visitComponentChange(graph, instance, false); + for(Variable variable : visitedVariables.get(instance)) + result.add(variable); + } + if(result.isEmpty()) + return EMPTY_VARIABLE_ARRAY; + else + return result.toArray(new Variable[result.size()]); + } + + // Check parent + Resource parent = graph.getPossibleObject(component, L0.PartOf); + String name = graph.getPossibleRelatedValue(component, L0.HasName, Bindings.STRING); + if(parent == null || name == null || !graph.isInstanceOf(component, STR.Component)) + return EMPTY_VARIABLE_ARRAY; + + visitComponentChange(graph, parent, false); + Variable[] parentCorrespondences = visitedVariables.get(parent); + ArrayList result = new ArrayList(parentCorrespondences.length); + for(Variable parentCorrespondence : parentCorrespondences) { + Variable correspondence = parentCorrespondence.getPossibleChild(graph, name); + if(correspondence != null) + result.add(correspondence); + } + if(result.isEmpty()) + return EMPTY_VARIABLE_ARRAY; + else + return result.toArray(new Variable[result.size()]); + } + + } +}