/*
* 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.lang.editor.menus.substitute;
import jetbrains.mps.actions.runtime.impl.ActionsUtil;
import jetbrains.mps.nodeEditor.EditorComponent;
import jetbrains.mps.nodeEditor.EditorManager;
import jetbrains.mps.nodeEditor.cellMenu.AbstractNodeSubstituteInfo;
import jetbrains.mps.nodeEditor.cells.CellFinderUtil;
import jetbrains.mps.openapi.editor.EditorContext;
import jetbrains.mps.openapi.editor.cells.EditorCell;
import jetbrains.mps.openapi.editor.menus.substitute.SubstituteMenuItem;
import jetbrains.mps.smodel.action.NodeFactoryManager;
import jetbrains.mps.smodel.presentation.NodePresentationUtil;
import jetbrains.mps.smodel.runtime.IconResource;
import jetbrains.mps.smodel.runtime.IconResourceUtil;
import jetbrains.mps.typesystem.inference.TypeChecker;
import jetbrains.mps.util.PatternUtil;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.mps.openapi.language.SAbstractConcept;
import org.jetbrains.mps.openapi.language.SConcept;
import org.jetbrains.mps.openapi.model.SNode;
/**
* @author simon
*/
public class DefaultSubstituteMenuItem implements SubstituteMenuItem {
private static final Logger LOG = LogManager.getLogger(DefaultSubstituteMenuItem.class);
@NotNull
private SAbstractConcept myConcept;
@NotNull
private final SNode myParentNode;
@Nullable
private final SNode myCurrentChild;
@NotNull
private EditorContext myEditorContext;
public DefaultSubstituteMenuItem(@NotNull SAbstractConcept concept, @NotNull SNode parentNode, @Nullable SNode currentChild, @NotNull EditorContext editorContext) {
myConcept = concept;
myParentNode = parentNode;
myCurrentChild = currentChild;
myEditorContext = editorContext;
}
@Nullable
@Override
public SAbstractConcept getOutputConcept() {
return myConcept;
}
@Nullable
@Override
public SNode getType(@NotNull String pattern) {
SNode node = createNode(pattern);
if (node == null) return null;
if (node.getParent() != null) {
LOG.warn("Node, created by " + this.getClass() + " action already has parent node.", new Throwable());
}
if (ActionsUtil.isInstanceOfIType(node)) return node;
//the following is for smart-type completion
AbstractNodeSubstituteInfo.getModelForTypechecking().addRootNode(node);
try {
return TypeChecker.getInstance().getTypeOf(node);
} finally {
AbstractNodeSubstituteInfo.getModelForTypechecking().removeRootNode(node);
}
}
@Nullable
@Override
public String getMatchingText(@NotNull String pattern) {
return NodePresentationUtil.matchingText(myConcept);
}
@Nullable
@Override
public String getDescriptionText(@NotNull String pattern) {
return NodePresentationUtil.descriptionText(myConcept);
}
@Override
public boolean canExecute(@NotNull String pattern) {
return PatternUtil.matchesPattern(pattern, getMatchingText(pattern));
}
@Override
public boolean canExecuteStrictly(@NotNull String pattern) {
return pattern.equals(getMatchingText(pattern));
}
@Nullable
@Override
public SNode createNode(@NotNull String pattern) {
SNode currentChild = myCurrentChild;
if (myCurrentChild != null) {
final Object oldNodeForSubstitute = myCurrentChild.getUserObject(EditorManager.OLD_NODE_FOR_SUBSTITUTION);
if (oldNodeForSubstitute != null) {
currentChild = ((SNode) oldNodeForSubstitute);
}
}
return NodeFactoryManager.createNode(myConcept, currentChild, myParentNode, myParentNode.getModel());
}
@Nullable
@Override
public IconResource getIcon(@NotNull String pattern) {
return IconResourceUtil.getIconResourceForConcept(myConcept);
}
@Override
public void select(@NotNull SNode createdNode, @NotNull String pattern) {
EditorComponent editorComponent = ((EditorComponent) myEditorContext.getEditorComponent());
EditorCell cell = editorComponent.findNodeCell(createdNode);
if (cell != null) {
EditorCell errorCell = CellFinderUtil.findFirstError(cell, true);
if (errorCell != null) {
editorComponent.changeSelectionWRTFocusPolicy(errorCell);
} else {
editorComponent.changeSelectionWRTFocusPolicy(cell);
}
}
}
@Nullable
protected SNode getCurrentChild() {
return myCurrentChild;
}
@NotNull
protected SNode getParentNode() {
return myParentNode;
}
}