/*
* Copyright 2003-2015 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.cellProviders;
import jetbrains.mps.editor.runtime.impl.cellActions.CellAction_DeleteEasily;
import jetbrains.mps.kernel.model.SModelUtil;
import jetbrains.mps.logging.Logger;
import jetbrains.mps.nodeEditor.cellActions.CellAction_DeleteNode;
import jetbrains.mps.nodeEditor.cellActions.CellAction_DeleteNode.DeleteDirection;
import jetbrains.mps.nodeEditor.cellActions.CellAction_Insert;
import jetbrains.mps.nodeEditor.cellMenu.CellContext;
import jetbrains.mps.nodeEditor.cellMenu.DefaultReferenceSubstituteInfo;
import jetbrains.mps.nodeEditor.cellMenu.DefaultSChildSubstituteInfo;
import jetbrains.mps.nodeEditor.cellProviders.CellProviderWithRole;
import jetbrains.mps.nodeEditor.cells.EditorCell_Constant;
import jetbrains.mps.nodeEditor.cells.EditorCell_Error;
import jetbrains.mps.nodeEditor.cells.EditorCell_Label;
import jetbrains.mps.openapi.editor.EditorContext;
import jetbrains.mps.openapi.editor.cells.CellActionType;
import jetbrains.mps.openapi.editor.cells.EditorCell;
import jetbrains.mps.openapi.editor.cells.SubstituteInfo;
import jetbrains.mps.smodel.NodeReadAccessCasterInEditor;
import jetbrains.mps.smodel.SNodeLegacy;
import jetbrains.mps.smodel.SNodeUtil;
import jetbrains.mps.smodel.adapter.MetaAdapterByDeclaration;
import jetbrains.mps.util.IterableUtil;
import org.apache.log4j.LogManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.model.SReference;
import java.util.List;
public abstract class AbstractReferentCellProvider extends CellProviderWithRole {
public static final Logger LOG = Logger.wrap(LogManager.getLogger(AbstractReferentCellProvider.class));
protected SNode myLinkDeclaration;
protected String myGenuineRole;
protected String myRole;
protected SNode myGenuineLinkDeclaration;
protected boolean myIsAggregation;
protected boolean myIsCardinality1;
private String myErrorText = null;
//it is important for descendants to have a unique constructor and with the same parameters as this one
public AbstractReferentCellProvider(@NotNull SNode node, EditorContext context) {
super(node, context);
}
@Override
public void setRole(final Object role) {
NodeReadAccessCasterInEditor.runReadTransparentAction(new Runnable() {
@Override
public void run() {
myLinkDeclaration = new SNodeLegacy(getSNode()).getLinkDeclaration(role.toString());
if (myLinkDeclaration == null) {
myErrorText = "?" + role.toString() + "?";
LOG.error("can't find a link declaration '" + role.toString() + "' in " + getSNode(), getSNode());
return;
}
myRole = role.toString();
myGenuineLinkDeclaration = SModelUtil.getGenuineLinkDeclaration(myLinkDeclaration);
myGenuineRole = SModelUtil.getLinkDeclarationRole(myGenuineLinkDeclaration);
myIsAggregation = !SNodeUtil.getLinkDeclaration_IsReference(myGenuineLinkDeclaration);
myIsCardinality1 = SNodeUtil.getLinkDeclaration_IsAtLeastOneMultiplicity(myGenuineLinkDeclaration);
}
});
}
@Override
public EditorCell createEditorCell(EditorContext context) {
return createCell_internal(myEditorContext);
}
protected EditorCell createCell_internal(EditorContext context) {
SNode node = getSNode();
if (myErrorText != null) {
return createErrorCell(myErrorText, node, context);
}
SNode referentNode = null;
if (myIsAggregation) {
List<? extends SNode> ch = IterableUtil.asList(node.getChildren(myGenuineRole));
referentNode = ch.iterator().hasNext() ? ch.iterator().next() : null;
} else {
SReference reference = node.getReference(myGenuineRole);
if (reference != null) {
referentNode = reference.getTargetNode();
if (referentNode == null || referentNode.getModel() == null) {
String rinfo = ((jetbrains.mps.smodel.SReference) reference).getResolveInfo();
myErrorText = rinfo != null ? rinfo : "?" + myRole + "?";
return createErrorCell(myErrorText, node, context);
}
}
}
if (referentNode == null) {
EditorCell_Label noRefCell = myIsCardinality1 ?
new EditorCell_Error(context, node, myNoTargetText) :
new EditorCell_Constant(context, node, "");
noRefCell.setText("");
noRefCell.setEditable(true);
noRefCell.setDefaultText(myNoTargetText);
noRefCell.setAction(CellActionType.DELETE, new CellAction_DeleteEasily(getSNode(), DeleteDirection.FORWARD));
noRefCell.setAction(CellActionType.BACKSPACE, new CellAction_DeleteEasily(getSNode(), DeleteDirection.BACKWARD));
if (myIsAggregation) {
noRefCell.setAction(CellActionType.INSERT, new CellAction_Insert(getSNode(), myGenuineRole));
noRefCell.setAction(CellActionType.INSERT_BEFORE, new CellAction_Insert(getSNode(), myGenuineRole));
}
noRefCell.setCellId("empty_" + myRole);
setRoleForCellWithNoTarget(noRefCell);
return noRefCell;
}
return createRefCell(context, referentNode, node);
}
protected EditorCell createErrorCell(String error, SNode node, EditorContext context) {
EditorCell_Error errorCell = new EditorCell_Error(context, node, error);
errorCell.setAction(CellActionType.DELETE, new CellAction_DeleteNode(getSNode(), DeleteDirection.FORWARD));
errorCell.setAction(CellActionType.BACKSPACE, new CellAction_DeleteNode(getSNode(), DeleteDirection.BACKWARD));
setRoleForCellWithNoTarget(errorCell);
return errorCell;
}
private void setRoleForCellWithNoTarget(EditorCell cell) {
if (myGenuineRole != null) {
cell.setRole(myGenuineRole);
if (!myIsAggregation) {
cell.setReferenceCell(true);
}
}
}
protected abstract EditorCell createRefCell(EditorContext context, SNode referencedNode, SNode node);
@Override
public SubstituteInfo createDefaultSubstituteInfo() {
if (myIsAggregation) {
return new DefaultSChildSubstituteInfo(getSNode(), MetaAdapterByDeclaration.getContainmentLink(myLinkDeclaration), myEditorContext);
}
return new DefaultReferenceSubstituteInfo(getSNode(), myLinkDeclaration, myEditorContext);
}
public SNode getLinkDeclaration() {
return myLinkDeclaration;
}
@Override
public CellContext getCellContext() {
if (myIsAggregation) {
SNode parentNode = getSNode();
List<? extends SNode> ch = IterableUtil.asList(parentNode.getChildren(myGenuineRole));
SNode currentChild = ch.iterator().hasNext() ? ch.iterator().next() : null;
return new AggregationCellContext(parentNode, currentChild, myLinkDeclaration);
}
SNode referenceNode = getSNode();
SNode currentReferent = referenceNode.getReferenceTarget(myGenuineRole);
return new ReferenceCellContext(referenceNode, currentReferent, myLinkDeclaration);
}
}