/* * 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); } }