package jetbrains.mps.ide.hierarchy;
/*Generated by MPS */
import jetbrains.mps.ide.ui.tree.MPSTree;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.module.SRepository;
import javax.swing.Icon;
import jetbrains.mps.ide.ui.tree.TextTreeNode;
import javax.swing.tree.DefaultTreeModel;
import org.jetbrains.annotations.Nullable;
import jetbrains.mps.ide.ui.tree.MPSTreeNode;
import jetbrains.mps.smodel.ModelReadRunnable;
import jetbrains.mps.smodel.ModelAccessHelper;
import jetbrains.mps.util.Computable;
import java.util.Set;
import jetbrains.mps.util.CollectionUtil;
import org.jetbrains.mps.util.Condition;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations;
import java.util.ArrayList;
import java.util.HashSet;
import org.jetbrains.annotations.NotNull;
import jetbrains.mps.smodel.SModelStereotype;
import com.intellij.openapi.actionSystem.ActionGroup;
import jetbrains.mps.workbench.action.BaseAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import java.util.Map;
import jetbrains.mps.workbench.action.ActionUtils;
public abstract class AbstractHierarchyTree extends MPSTree {
private AbstractHierarchyView myHierarchyView;
private SNode myHierarchyNode;
protected boolean myIsParentHierarchy;
protected boolean myOnlyInOneModel;
protected boolean myShowGeneratorModels;
private final SRepository myRepostitory;
private HierarchyTreeNode myTreeNode;
public AbstractHierarchyTree(SRepository repostitory) {
myRepostitory = repostitory;
}
/**
* Tree shall not depend on hierarchy view, and all uses of myHierarchyView/getHierarchyView() shall get refactored and removed.
*/
public void setHierarchyView(AbstractHierarchyView hv) {
myHierarchyView = hv;
}
/**
* Change text and icon of current root, if any. Only reasonable use is part of tree rebuild
*/
public void setRootNodeText(String text, Icon icon) {
if (getRootNode() instanceof TextTreeNode) {
TextTreeNode rv = ((TextTreeNode) getRootNode());
rv.setText(text);
rv.setIcon(icon);
if (getModel() instanceof DefaultTreeModel) {
((DefaultTreeModel) getModel()).nodeChanged(rv);
}
}
}
@Nullable
public AbstractHierarchyView getHierarchyView() {
return myHierarchyView;
}
public void setHierarchyNode(SNode modelNode) {
myHierarchyNode = modelNode;
}
public boolean overridesNodeIdentifierCalculation() {
return false;
}
public String calculateNodeIdentifier(HierarchyTreeNode node) {
throw new UnsupportedOperationException();
}
public boolean isParentHierarchy() {
return myIsParentHierarchy;
}
/*package*/ void setParentHierarchy(boolean isParentHierarchy) {
myIsParentHierarchy = isParentHierarchy;
}
public boolean isOnlyInOneModel() {
return myOnlyInOneModel;
}
/*package*/ void setIsOnlyInOneModel(boolean isOnlyInOneModel) {
boolean oldOnlyInOneModel = myOnlyInOneModel;
myOnlyInOneModel = isOnlyInOneModel;
if (oldOnlyInOneModel != myOnlyInOneModel) {
rebuildNow();
}
}
public boolean isShowGeneratorModels() {
return myShowGeneratorModels;
}
public void setShowGeneratorModels(boolean showGeneratorModels) {
boolean oldShowGeneratorModels = myShowGeneratorModels;
myShowGeneratorModels = showGeneratorModels;
if (oldShowGeneratorModels != myShowGeneratorModels) {
rebuildNow();
}
}
@Override
protected void doInit(MPSTreeNode node, Runnable runnable) {
super.doInit(node, new ModelReadRunnable(myRepostitory.getModelAccess(), runnable));
}
@Override
protected MPSTreeNode rebuild() {
if (myHierarchyNode == null) {
return new TextTreeNode(noNodeString());
}
return new ModelAccessHelper(myRepostitory.getModelAccess()).runReadAction(new Computable<MPSTreeNode>() {
@Override
public MPSTreeNode compute() {
return rebuildParentHierarchy();
}
});
}
protected abstract String noNodeString();
protected abstract SNode getParent(SNode node);
protected abstract Set<SNode> getParents(SNode node, Set<SNode> visited) throws CircularHierarchyException;
protected abstract Set<SNode> getDescendants(SNode node, Set<SNode> visited) throws CircularHierarchyException;
protected Set<SNode> getAbstractChildren(final SNode node, Set<SNode> visited) throws CircularHierarchyException {
Set<SNode> result;
if (myIsParentHierarchy) {
result = getParents(node, visited);
} else {
result = getDescendants(node, visited);
}
if (myOnlyInOneModel) {
result = CollectionUtil.filter(result, new Condition<SNode>() {
@Override
public boolean met(SNode n) {
if (n == null) {
return false;
}
return SNodeOperations.getModel(n) == SNodeOperations.getModel(node);
}
});
}
if (!(myShowGeneratorModels)) {
result = CollectionUtil.filter(result, new Condition<SNode>() {
@Override
public boolean met(SNode n) {
if (n == null) {
return false;
}
return !(isInGeneratorModel(n));
}
});
}
return result;
}
protected SNode getAbstractParent(SNode node) {
if (myIsParentHierarchy) {
return null;
}
SNode result = getParent(node);
if (result == null) {
return null;
}
if (!(myShowGeneratorModels)) {
while (isInGeneratorModel(result)) {
result = getParent(result);
if (result == null) {
return null;
}
}
}
if (myOnlyInOneModel && (SNodeOperations.getModel(result) != SNodeOperations.getModel(node))) {
return null;
}
return result;
}
protected MPSTreeNode rebuildParentHierarchy() {
ArrayList<SNode> parentHierarchy = new ArrayList<SNode>();
SNode parentDeclaration = myHierarchyNode;
while (parentDeclaration != null) {
parentHierarchy.add(parentDeclaration);
parentDeclaration = getAbstractParent(parentDeclaration);
}
HierarchyTreeNode parentTreeNode = null;
HierarchyTreeNode hierarchyTreeNode = null;
HierarchyTreeNode rootNode = null;
Set<SNode> visited = new HashSet<SNode>();
for (int i = parentHierarchy.size() - 1; i >= 0; i--) {
hierarchyTreeNode = (i > 0 ? (new HierarchyTreeNode(parentHierarchy.get(i), this)) : new ChildHierarchyTreeNode(parentHierarchy.get(i), this, visited));
if (i == parentHierarchy.size() - 1) {
rootNode = hierarchyTreeNode;
}
visited.add(parentHierarchy.get(i));
if (parentTreeNode != null) {
parentTreeNode.add(hierarchyTreeNode);
}
parentTreeNode = hierarchyTreeNode;
}
myTreeNode = hierarchyTreeNode;
MPSTreeNode topRootNode = new TextTreeNode("Hierarchy");
topRootNode.add(rootNode);
return topRootNode;
}
/*package*/ HierarchyTreeNode getActiveTreeNode() {
// I've got no idea what's the need behind this, and 'active' is just a quess here.
// I merely moved this field from HierarchyView, where it's read, here, where it's modified.
return myTreeNode;
}
@Override
protected void doubleClick(@NotNull MPSTreeNode node) {
if (node instanceof HierarchyTreeNode && myHierarchyView != null) {
myHierarchyView.openNode(((HierarchyTreeNode) node).getNodeReference());
} else {
super.doubleClick(node);
}
}
private boolean isInGeneratorModel(SNode n) {
return SNodeOperations.getModel(n) != null && SModelStereotype.isGeneratorModel(SNodeOperations.getModel(n));
}
@Override
protected ActionGroup createPopupActionGroup(final MPSTreeNode treeNode) {
if (!(treeNode instanceof HierarchyTreeNode)) {
return null;
}
final AbstractHierarchyView hierarchyView = getHierarchyView();
if (hierarchyView == null) {
return null;
}
BaseAction hierarchyAction = new BaseAction("Show Hierarchy For This Node") {
@Override
protected void doExecute(AnActionEvent e, Map<String, Object> _params) {
final SNode node = ((HierarchyTreeNode) treeNode).getNode();
hierarchyView.showItemInHierarchy(node);
}
};
return ActionUtils.groupFromActions(hierarchyAction);
}
}