/*
* 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.nodeEditor.menus.substitute;
import jetbrains.mps.lang.editor.menus.substitute.DefaultSubstituteMenuLookup;
import jetbrains.mps.lang.editor.menus.transformation.InUsedLanguagesPredicate;
import jetbrains.mps.nodeEditor.menus.CachingPredicate;
import jetbrains.mps.nodeEditor.menus.CanBeChildPredicate;
import jetbrains.mps.nodeEditor.menus.CanBeParentPredicate;
import jetbrains.mps.nodeEditor.menus.IsSubconceptOfPredicate;
import jetbrains.mps.nodeEditor.menus.MenuItemFactory;
import jetbrains.mps.nodeEditor.menus.MenuUtil;
import jetbrains.mps.nodeEditor.menus.RecursionSafeMenuItemFactory;
import jetbrains.mps.openapi.editor.EditorContext;
import jetbrains.mps.openapi.editor.menus.substitute.SubstituteMenuContext;
import jetbrains.mps.openapi.editor.menus.substitute.SubstituteMenuItem;
import jetbrains.mps.openapi.editor.menus.substitute.SubstituteMenuLookup;
import jetbrains.mps.smodel.language.LanguageRegistry;
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.SModel;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.module.SRepository;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
/**
* @author simon
*/
public class DefaultSubstituteMenuContext implements SubstituteMenuContext {
private EditorContext myEditorContext;
private SContainmentLink myContainmentLink;
private SNode myParentNode;
private SNode myCurrentChild;
private MenuItemFactory<SubstituteMenuItem, SubstituteMenuContext, SubstituteMenuLookup> myMenuItemFactory;
private Predicate<SAbstractConcept> mySuitableForConstraintsPredicate;
private SAbstractConcept myTargetConcept;
private DefaultSubstituteMenuContext(MenuItemFactory<SubstituteMenuItem, SubstituteMenuContext, SubstituteMenuLookup> menuItemFactory,
SContainmentLink containmentLink, SAbstractConcept targetConcept, SNode parentNode,
SNode currentChild, EditorContext editorContext) {
myMenuItemFactory = menuItemFactory;
myContainmentLink = containmentLink;
myTargetConcept = targetConcept;
myParentNode = parentNode;
myCurrentChild = currentChild;
myEditorContext = editorContext;
}
private DefaultSubstituteMenuContext(MenuItemFactory<SubstituteMenuItem, SubstituteMenuContext, SubstituteMenuLookup> menuItemFactory,
SContainmentLink containmentLink, SNode parentNode,
SNode currentChild, EditorContext editorContext) {
this(menuItemFactory, containmentLink, null, parentNode, currentChild, editorContext);
}
@NotNull
private Predicate<SAbstractConcept> createSuitableForConstraintsPredicate(SNode parentNode, SContainmentLink containmentLink, SRepository repository) {
Predicate<SAbstractConcept> predicate = new CanBeChildPredicate(parentNode, containmentLink).
and(new CanBeParentPredicate(parentNode, containmentLink, repository));
if (myContainmentLink != null) {
predicate = predicate.and(new IsSubconceptOfPredicate(getTargetConcept()));
}
predicate = predicate.and(new InUsedLanguagesPredicate(getModel()));
return predicate;
}
@NotNull
@Override
public EditorContext getEditorContext() {
return myEditorContext;
}
@NotNull
@Override
public SNode getParentNode() {
return myParentNode;
}
@Override
public SModel getModel() {
return myParentNode.getModel();
}
@Override
@Nullable
public SContainmentLink getLink() {
return myContainmentLink;
}
@Nullable
@Override
public SAbstractConcept getTargetConcept() {
if (myTargetConcept != null) {
return myTargetConcept;
}
return SubstituteMenuContext.super.getTargetConcept();
}
@Override
@Nullable
public SNode getCurrentTargetNode() {
return myCurrentChild;
}
@NotNull
@Override
public List<SubstituteMenuItem> createItems(@Nullable SubstituteMenuLookup menuLookup) {
if (menuLookup == null) {
if (myContainmentLink == null) {
return Collections.emptyList();
}
assert getTargetConcept() != null;
menuLookup = new DefaultSubstituteMenuLookup(LanguageRegistry.getInstance(myEditorContext.getRepository()), getTargetConcept());
}
return myMenuItemFactory.createItems(this, menuLookup);
}
@Override
public SubstituteMenuContext withLink(SContainmentLink link) {
return new DefaultSubstituteMenuContext(myMenuItemFactory, link, myParentNode, myCurrentChild, myEditorContext);
}
@Override
public Predicate<SAbstractConcept> getConstraintsCheckingPredicate() {
if (mySuitableForConstraintsPredicate == null) {
mySuitableForConstraintsPredicate = new CachingPredicate<>(createSuitableForConstraintsPredicate(myParentNode, myContainmentLink, myEditorContext.getRepository()));
}
return mySuitableForConstraintsPredicate;
}
@NotNull
public static DefaultSubstituteMenuContext createInitialContextForNode(SContainmentLink containmentLink, SNode parentNode,
SNode currentChild, EditorContext editorContext) {
return createInitialContextForNode(containmentLink, null, parentNode, currentChild, editorContext);
}
@NotNull
public static DefaultSubstituteMenuContext createInitialContextForNode(SContainmentLink containmentLink, SAbstractConcept targetConcept, SNode parentNode,
SNode currentChild, EditorContext editorContext) {
return new DefaultSubstituteMenuContext(new RecursionSafeMenuItemFactory<>(new DefaultSubstituteMenuItemFactory(MenuUtil.getUsedLanguages(parentNode))),
containmentLink, targetConcept, parentNode, currentChild, editorContext);
}
@Override
public int hashCode() {
return Objects.hash(getParentNode(), getEditorContext(), getCurrentTargetNode(), getLink(), getTargetConcept());
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DefaultSubstituteMenuContext that = (DefaultSubstituteMenuContext) o;
return getParentNode().equals(that.getParentNode()) && getEditorContext().equals(that.getEditorContext()) &&
Objects.equals(getCurrentTargetNode(), that.getCurrentTargetNode()) && Objects.equals(getLink(), that.getLink()) && Objects.equals(getTargetConcept(), that.getTargetConcept());
}
}