package jetbrains.mps.vcs.diff.changes; /*Generated by MPS */ import org.jetbrains.mps.openapi.model.SNodeId; import org.jetbrains.mps.openapi.language.SContainmentLink; import java.util.List; import org.jetbrains.annotations.NotNull; import jetbrains.mps.vcs.diff.ChangeSet; import org.jetbrains.mps.openapi.model.SNodeReference; import org.jetbrains.annotations.Nullable; import org.jetbrains.mps.openapi.model.SNode; import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations; import jetbrains.mps.smodel.adapter.structure.MetaAdapterFactory; import jetbrains.mps.lang.smodel.generator.smodelAdapter.AttributeOperations; import jetbrains.mps.lang.smodel.generator.smodelAdapter.IAttributeDescriptor; import jetbrains.mps.smodel.SNodePointer; import jetbrains.mps.util.IterableUtil; import jetbrains.mps.internal.collections.runtime.ListSequence; import java.util.ArrayList; import org.jetbrains.mps.openapi.model.SModel; import jetbrains.mps.internal.collections.runtime.IVisitor; import jetbrains.mps.internal.collections.runtime.IterableUtils; import jetbrains.mps.internal.collections.runtime.ISelector; import jetbrains.mps.util.NameUtil; public class NodeGroupChange extends ModelChange { private final SNodeId myParentNodeId; private final SContainmentLink myRole; private final int myBegin; private final int myEnd; private final int myResultBegin; private final int myResultEnd; private List<SNodeId> myPreparedIdsToDelete = null; private SNodeId myPreparedAnchorId = null; public NodeGroupChange(@NotNull ChangeSet changeSet, @NotNull SNodeId parentNodeId, @NotNull SContainmentLink role, int begin, int end, int resultBegin, int resultEnd) { super(changeSet); myParentNodeId = parentNodeId; myRole = role; myBegin = begin; myEnd = end; myResultBegin = resultBegin; myResultEnd = resultEnd; } @NotNull public SNodeId getParentNodeId() { return myParentNodeId; } @NotNull public SNodeId getParentNodeId(boolean isNewModel) { return myParentNodeId; } @NotNull public String getRole() { return myRole.getRoleName(); } @NotNull public SContainmentLink getRoleLink() { return myRole; } public boolean isAbout(SContainmentLink link) { return myRole.equals(link); } public int getBegin() { return myBegin; } public int getEnd() { return myEnd; } public int getResultEnd() { return myResultEnd; } public int getResultBegin() { return myResultBegin; } private SNodeReference myMergeHint = null; private boolean myMergeHintLoaded = false; @Nullable @Override public SNodeReference getMergeHint() { // get "nonconflicting" attribute in metamodel if (!(myMergeHintLoaded)) { myMergeHintLoaded = true; SNode n = getParent(false); SNode c = SNodeOperations.getConceptDeclaration(n); SNode linkDecl = SNodeOperations.as(myRole.getDeclarationNode(), MetaAdapterFactory.getConcept(0xc72da2b97cce4447L, 0x8389f407dc1158b7L, 0xf979bd086aL, "jetbrains.mps.lang.structure.structure.LinkDeclaration")); SNode hint = AttributeOperations.getAttribute(linkDecl, new IAttributeDescriptor.NodeAttribute(MetaAdapterFactory.getConcept(0x37e03aa1728949bcL, 0x826930de5eceec76L, 0x657f08af7deb331aL, "jetbrains.mps.vcs.mergehints.structure.MergeHint"))); if ((hint == null)) { hint = AttributeOperations.getAttribute(c, new IAttributeDescriptor.NodeAttribute(MetaAdapterFactory.getConcept(0x37e03aa1728949bcL, 0x826930de5eceec76L, 0x657f08af7deb331aL, "jetbrains.mps.vcs.mergehints.structure.MergeHint"))); } if ((hint != null)) { myMergeHint = new SNodePointer(hint); } } return myMergeHint; } private SNode getParent(boolean isNewModel) { return ((isNewModel ? getChangeSet().getNewModel() : getChangeSet().getOldModel())).getNode(getParentNodeId(isNewModel)); } public void prepare() { if (myPreparedIdsToDelete == null) { SNode parent = getParent(false); assert parent != null; List<? extends SNode> children = IterableUtil.asList(parent.getChildren(myRole)); myPreparedIdsToDelete = ListSequence.fromList(new ArrayList<SNodeId>()); for (int i = myBegin; i < myEnd; i++) { ListSequence.fromList(myPreparedIdsToDelete).addElement(children.get(i).getNodeId()); } myPreparedAnchorId = (myBegin == 0 ? null : children.get(myBegin - 1).getNodeId()); } } @Override public void apply(@NotNull final SModel model, @NotNull NodeCopier nodeCopier) { // delete old nodes prepare(); ListSequence.fromList(myPreparedIdsToDelete).visitAll(new IVisitor<SNodeId>() { public void visit(SNodeId id) { model.getNode(id).delete(); } }); myPreparedIdsToDelete = null; // copy nodes to insert List<SNode> nodesToAdd = ListSequence.fromList(new ArrayList<SNode>()); List<? extends SNode> newChildren = IterableUtil.asList(getParent(true).getChildren(myRole)); for (int i = myResultBegin; i < myResultEnd; i++) { ListSequence.fromList(nodesToAdd).addElement(nodeCopier.copyNode(newChildren.get(i))); } // insert new nodes SNode anchor = (myPreparedAnchorId == null ? null : model.getNode(myPreparedAnchorId)); SNode parent = model.getNode(myParentNodeId); if (anchor != null) { // can't use anchor.next-sibling here as it looks for sibling with respect to node's containment role // while there are tests (MergeCoreTest) that expect ordering according overall children list anchor = anchor.getNextSibling(); } else { // MergeCoreTest expects nodes without anchor to go first anchor = parent.getFirstChild(); } for (SNode newNode : ListSequence.fromList(nodesToAdd)) { parent.insertChildBefore(myRole, newNode, anchor); } } @Nullable @Override public SNodeId getRootId() { return SNodeOperations.getContainingRoot(getParent(false)).getNodeId(); } @NotNull @Override public ChangeType getType() { if (myBegin == myEnd) { return ChangeType.ADD; } if (myResultBegin == myResultEnd) { return ChangeType.DELETE; } return ChangeType.CHANGE; } @Override public String toString() { if (myEnd == myBegin) { return String.format("Insert %s into position #%d in role %s of node %s", nodeRange(myResultBegin, myResultEnd), myBegin, myRole, myParentNodeId); } if (myResultEnd == myResultBegin) { return String.format("Delete %s in role %s of node %s", nodeRange(myBegin, myEnd), myRole, myParentNodeId); } return String.format("Replace %s with nodes %s in role %s of node %s", nodeRange(myBegin, myEnd), nodeRange(myResultBegin, myResultEnd), myRole, myParentNodeId); } @Override public String getDescription() { return getDescription(true); } public String getDescription(boolean verbose) { List<SNode> newChildren = null; String newIds = null; if (verbose) { newChildren = IterableUtil.asList(getParent(true).getChildren(myRole)); newIds = IterableUtils.join(ListSequence.fromList(newChildren).page(myResultBegin, myResultEnd).select(new ISelector<SNode, String>() { public String select(SNode n) { return "#" + n.getNodeId(); } }), ", "); } String oldStuff = (myEnd - myBegin == 1 ? getRole() : NameUtil.formatNumericalString(myEnd - myBegin, getRole())); String newStuff = (myResultEnd - myResultBegin == 1 ? getRole() : NameUtil.formatNumericalString(myResultEnd - myResultBegin, getRole())); // FIXME get rid of this dirty magic with role names "pluralization". PLEASE!!! if (eq_yjf6x2_a0a7a82(newStuff, getRole()) && eq_yjf6x2_a0a7a82_0(oldStuff, getRole())) { newStuff = "another"; } else if (myEnd != myBegin) { newStuff = "another " + newStuff; } if (myEnd == myBegin) { if (verbose) { String addedOrInserted = (myResultEnd == ListSequence.fromList(newChildren).count() ? "Added" : "Inserted"); return String.format("%s %s: %s", addedOrInserted, newStuff, newIds); } else { return String.format("Added %s", newStuff); } } if (myResultEnd == myResultBegin) { return String.format("Removed %s", oldStuff); } if (verbose) { return String.format("Replaced %s with %s: %s", oldStuff, newStuff, newIds); } else { return String.format("Replaced %s with %s", oldStuff, newStuff); } } @NotNull @Override protected ModelChange createOppositeChange() { return new NodeGroupChange(getChangeSet().getOppositeChangeSet(), myParentNodeId, myRole, myResultBegin, myResultEnd, myBegin, myEnd); } private static String nodeRange(int begin, int end) { return (begin + 1 == end ? String.format("node #%d", begin) : String.format("nodes #%d-%d", begin, end - 1)); } private static boolean eq_yjf6x2_a0a7a82(Object a, Object b) { return (a != null ? a.equals(b) : a == b); } private static boolean eq_yjf6x2_a0a7a82_0(Object a, Object b) { return (a != null ? a.equals(b) : a == b); } }