/* * Copyright 2003-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jetbrains.mps.openapi.editor.menus.transformation; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.mps.openapi.language.SAbstractConcept; import org.jetbrains.mps.openapi.language.SContainmentLink; import org.jetbrains.mps.openapi.model.SNode; /** * A node location in the tree. Used to specify location for both transformations and substitutions. Usually the same node is transformed and substituted, but * when creating a menu for an empty cell the transformations are collected for the parent while substitutions are collected for the (non-existent) child. */ public interface SNodeLocation { /** * The node to use for transformations. Always non-null. */ @NotNull SNode getContextNode(); /** * Parent node for substitutions. */ @Nullable SNode getParent(); /** * Containment link for substitutions. */ @Nullable SContainmentLink getContainmentLink(); /** * Child node for substitutions. */ @Nullable SNode getChild(); @Nullable default SAbstractConcept getTargetConcept() { return getContainmentLink() != null ? getContainmentLink().getTargetConcept() : null; } /** * A location specified by a parent node and a containment link. The child is assumed to be absent. Transformations act on the parent, substitutions create * a new child node for the link. */ class FromParentAndLink extends SNodeLocationWithTargetConcept { @NotNull private final SNode myParentNode; @NotNull private final SContainmentLink myContainmentLink; public FromParentAndLink(@NotNull SNode parentNode, @NotNull SContainmentLink containmentLink) { myParentNode = parentNode; myContainmentLink = containmentLink; } public FromParentAndLink(@NotNull SNode parentNode, @NotNull SContainmentLink containmentLink, @NotNull SAbstractConcept targetConcept) { super(targetConcept); myParentNode = parentNode; myContainmentLink = containmentLink; } @NotNull @Override public SNode getContextNode() { return myParentNode; } @NotNull @Override public SNode getParent() { return myParentNode; } @NotNull @Override public SContainmentLink getContainmentLink() { return myContainmentLink; } /** * Current child node, always null. */ @Nullable @Override public SNode getChild() { return null; } } /** * A location specified by an existing node. The node is both transformed and substituted. */ class FromNode extends SNodeLocationWithTargetConcept { @NotNull private final SNode myNode; public FromNode(@NotNull SNode node) { myNode = node; } public FromNode(@NotNull SNode node, @NotNull SAbstractConcept targetConcept) { super(targetConcept); myNode = node; } @NotNull @Override public SNode getContextNode() { return myNode; } @Nullable @Override public SNode getParent() { return myNode.getParent(); } @Nullable @Override public SContainmentLink getContainmentLink() { return myNode.getContainmentLink(); } @NotNull @Override public SNode getChild() { return myNode; } } abstract class SNodeLocationWithTargetConcept implements SNodeLocation { @Nullable private SAbstractConcept myTargetConcept; SNodeLocationWithTargetConcept(@NotNull SAbstractConcept targetConcept) { myTargetConcept = targetConcept; } SNodeLocationWithTargetConcept() { } @Nullable @Override public SAbstractConcept getTargetConcept() { return myTargetConcept != null ? myTargetConcept : SNodeLocation.super.getTargetConcept(); } } }