/*
* 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.ide.devkit.components;
import com.intellij.ide.actions.CloseTabToolbarAction;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.ActionPlaces;
import com.intellij.openapi.actionSystem.ActionToolbar;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.ui.ScrollPaneFactory;
import jetbrains.mps.icons.MPSIcons.Nodes;
import jetbrains.mps.ide.ui.smodel.ConceptTreeNode;
import jetbrains.mps.ide.ui.smodel.PropertiesTreeNode;
import jetbrains.mps.ide.ui.smodel.ReferencesTreeNode;
import jetbrains.mps.ide.ui.tree.MPSTree;
import jetbrains.mps.ide.ui.tree.MPSTreeNode;
import jetbrains.mps.ide.ui.tree.TextTreeNode;
import jetbrains.mps.ide.ui.tree.smodel.NodeTargetProvider;
import jetbrains.mps.ide.ui.tree.smodel.SNodeTreeNode;
import jetbrains.mps.ide.ui.tree.smodel.SNodeTreeNode.NodeChildrenProvider;
import jetbrains.mps.openapi.navigation.EditorNavigator;
import jetbrains.mps.project.MPSProject;
import jetbrains.mps.smodel.ModelReadRunnable;
import jetbrains.mps.typesystem.PresentationManager;
import jetbrains.mps.typesystem.inference.TypeChecker;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.model.SNodeReference;
import org.jetbrains.mps.openapi.model.SReference;
import javax.swing.JPanel;
import java.awt.BorderLayout;
public class NodeExplorerComponent extends JPanel implements Disposable {
private MPSProject myProject;
private SNode myNode;
private final MyTree myTree = new MyTree();
private Runnable myCloseAction = null;
public NodeExplorerComponent(MPSProject mpsProject, SNode node) {
super(new BorderLayout());
myProject = mpsProject;
this.add(ScrollPaneFactory.createScrollPane(myTree), BorderLayout.CENTER);
DefaultActionGroup group = new DefaultActionGroup();
group.addAll(new CloseTabToolbarAction() {
@Override
public void actionPerformed(AnActionEvent e) {
if(myCloseAction != null) {
myCloseAction.run();
}
}
}, ActionManager.getInstance().getAction(IdeActions.ACTION_PIN_ACTIVE_TAB));
final ActionToolbar actionToolbar = ActionManager.getInstance().createActionToolbar(ActionPlaces.TOOLBAR, group, false);
actionToolbar.setTargetComponent(myTree);
this.add(actionToolbar.getComponent(), BorderLayout.WEST);
myNode = node;
myTree.rebuildNow();
}
public void setCloseAction(Runnable closeAction) {
myCloseAction = closeAction;
}
@Override
public void dispose() {
myProject = null;
myNode = null;
myTree.dispose();
}
private class MyTree extends MPSTree implements NodeChildrenProvider {
@Override
protected ActionGroup createPopupActionGroup(MPSTreeNode node) {
return null;
}
@Override
protected void doInit(MPSTreeNode node, Runnable nodeInitRunnable) {
super.doInit(node, new ModelReadRunnable(myProject.getModelAccess(), nodeInitRunnable));
}
@Override
protected MPSTreeNode rebuild() {
myTree.setRootVisible(myNode == null);
if (myNode == null) {
return new TextTreeNode("No node");
} else {
TextTreeNode textTreeNode = new TextTreeNode("Node");
SNodeTreeNode sNodeTreeNode = new SNodeTreeNodeWithType(myNode);
textTreeNode.add(sNodeTreeNode);
return textTreeNode;
}
}
@Override
public void populate(SNodeTreeNode treeNode) {
SNode n = treeNode.getSNode();
if (n == null || n.getModel() == null) {
return;
}
treeNode.add(new ConceptTreeNode(n));
treeNode.add(new PropertiesTreeNode(n));
treeNode.add(new ReferencesTreeNode(n) {
@Override
protected void doInit() {
// TODO: move to base ReferencesTreeNode class as option?
for (final SReference ref : getSNode().getReferences()) {
final SNode targetNode = ref.getTargetNode();
if (targetNode != null) {
add(new SNodeTreeNodeWithType(targetNode, ref.getLink().getName()));
} else {
// Try to show user as much info as possible
add(new TextTreeNode(Nodes.Unknown, String.valueOf(ref.getTargetNodeReference())));
}
}
myInitialized = true;
}
});
}
@Override
protected void doubleClick(@NotNull MPSTreeNode nodeToClick) {
// TODO: update navigation logic to avoid this copy/paste
// Copied from jetbrains.mps.ide.projectPane.logicalview.ProjectPaneTree.doubleClick()
if (nodeToClick instanceof NodeTargetProvider) {
final SNodeReference navigationTarget = ((NodeTargetProvider) nodeToClick).getNavigationTarget();
if (navigationTarget != null) {
new EditorNavigator(myProject).shallFocus(true).selectIfChild().open(navigationTarget);
return;
}
// fall-through
}
super.doubleClick(nodeToClick);
}
}
private class SNodeTreeNodeWithType extends SNodeTreeNode {
public SNodeTreeNodeWithType(SNode node) {
super(node);
}
public SNodeTreeNodeWithType(SNode node, String role) {
super(node, role);
}
@Override
protected void doUpdatePresentation_internal() {
super.doUpdatePresentation_internal();
// TODO: add to base SNodeTreeNode class and get rid of this inner class?
String string = getText();
final SNode typeOf = TypeChecker.getInstance().getTypeOf(getSNode());
if (typeOf != null) {
String typeInfo = " {" + PresentationManager.toString(typeOf) + "}";
setText(string + typeInfo);
}
}
}
}