/*
* 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.ide.ui.tree.smodel;
import com.intellij.openapi.editor.colors.ColorKey;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import jetbrains.mps.ide.icons.IconManager;
import jetbrains.mps.ide.ui.tree.ErrorState;
import jetbrains.mps.ide.ui.tree.MPSTree;
import jetbrains.mps.ide.ui.tree.MPSTreeNodeEx;
import jetbrains.mps.ide.ui.util.NodeAttributesUtil;
import jetbrains.mps.smodel.MPSModuleRepository;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.mps.openapi.language.SContainmentLink;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.model.SNodeReference;
import org.jetbrains.mps.openapi.model.SNodeUtil;
import org.jetbrains.mps.util.Condition;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import java.awt.Color;
import java.awt.font.TextAttribute;
import java.util.stream.StreamSupport;
public class SNodeTreeNode extends MPSTreeNodeEx implements NodeTargetProvider {
private static final Logger LOG = LogManager.getLogger(SNodeTreeNode.class);
protected boolean myInitialized = false;
private SNode myNode;
private String myRole;
private final Condition<SNode> myCondition;
public SNodeTreeNode(SNode node) {
this(node, null);
}
public SNodeTreeNode(SNode node, String role) {
this(node, role, Condition.always());
}
public SNodeTreeNode(SNode node, String role, Condition<SNode> condition) {
myNode = node;
myRole = role;
myCondition = condition;
setUserObject(node.getNodeId().toString());
if (myNode == null) {
setNodeIdentifier("null");
} else {
setNodeIdentifier(myNode.getNodeId().toString());
}
setToggleClickCount(-1);
}
@Override
protected final void doUpdatePresentation() {
if (getSModelModelTreeNode() != null) {
getSModelModelTreeNode().getDependencyRecorder().rebuild(this, new Runnable() {
@Override
public void run() {
doUpdatePresentation_internal();
}
});
} else {
doUpdatePresentation_internal();
}
}
@Override
protected void onRemove() {
super.onRemove();
if (getSModelModelTreeNode() != null) {
getSModelModelTreeNode().getDependencyRecorder().remove(this);
}
}
protected void doUpdatePresentation_internal() {
if (myNode == null) {
return;
}
if (hasErrors()) {
setColor(Color.RED);
} else {
setColor(EditorColorsManager.getInstance().getGlobalScheme().getColor(ColorKey.createColorKey("FILESTATUS_NOT_CHANGED")));
}
setIcon(IconManager.getIconFor(myNode));
if (!myNode.getConcept().isValid()) {
setErrorState(ErrorState.ERROR);
}
if (NodeAttributesUtil.isDeprecatedNode(myNode)) {
addFontAttribute(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON);
}
setText(calculateNodeTextPresentation());
setAutoExpandable(myNode.getModel() == null || myNode.getParent() != null);
}
@Nullable
public SModelTreeNode getSModelModelTreeNode() {
if (getParent() instanceof SModelTreeNode) {
return (SModelTreeNode) getParent();
}
if (getParent() instanceof SNodeTreeNode) {
return ((SNodeTreeNode) getParent()).getSModelModelTreeNode();
}
if (getParent() instanceof SNodeGroupTreeNode) {
TreeNode node = getParent();
while (node != null && !(node instanceof SModelTreeNode)) {
node = node.getParent();
}
return (SModelTreeNode) node;
}
return null;
}
@Override
public SNode getSNode() {
return myNode;
}
@Override
protected void doUpdate() {
this.removeAllChildren();
myInitialized = false;
}
@Override
public boolean isInitialized() {
return myInitialized;
}
@Override
protected void doInit() {
this.removeAllChildren();
SNode n = getSNode();
if (n == null || !SNodeUtil.isAccessible(n, MPSModuleRepository.getInstance())) {
return;
}
NodeChildrenProvider provider = getAncestor(NodeChildrenProvider.class);
if (provider != null) {
provider.populate(this);
}
if (isShowStructure()) {
StreamSupport.stream(n.getChildren().spliterator(), false).filter(myCondition::met).forEach(o -> add(createChildTreeNode(o)));
}
DefaultTreeModel treeModel = (DefaultTreeModel) getTree().getModel();
treeModel.nodeStructureChanged(this);
myInitialized = true;
}
@Override
public boolean isLeaf() {
return !isShowStructure();
}
private boolean isShowStructure() {
MPSTree tree = getTree();
if (!(tree instanceof TreeNodeParamProvider)) return true; //not to affect usages other than those we want to
return ((TreeNodeParamProvider) tree).isShowStructure();
}
protected SNodeTreeNode createChildTreeNode(SNode childNode) {
SContainmentLink cl = childNode.getContainmentLink();
return createChildTreeNode(childNode, cl == null ? null : cl.getName());
}
protected SNodeTreeNode createChildTreeNode(SNode childNode, String role) {
SModelTreeNode sModelTreeNode = getSModelModelTreeNode();
return sModelTreeNode == null ? new SNodeTreeNode(childNode, role, myCondition)
: sModelTreeNode.createSNodeTreeNode(childNode, role, myCondition);
}
@Nullable
@Override
public SNodeReference getNavigationTarget() {
return myNode == null ? null : myNode.getReference();
}
private String calculateNodeTextPresentation() {
StringBuilder output = new StringBuilder();
if (myRole != null) {
output.append(myRole).append(" : ");
}
SNode node = getSNode();
if (node != null) {
String nodePresentation;
try {
nodePresentation = node.getPresentation();
} catch (Throwable t) {
nodePresentation = null;
LOG.error(null, t);
}
String nodeString = nodePresentation;
output.append(nodeString);
/*if (myRole != null) {
String presentation = node.getPresentation();
if (presentation != null && !presentation.equals(nodeString)) {
output.append(" [").append(presentation).append("]");
}
}*/
}
return output.toString();
}
public boolean hasErrors() {
return false;
}
public interface NodeChildrenProvider {
void populate(SNodeTreeNode treeNode);
}
}