/*
* 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.bookmark;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.AnActionEvent;
import jetbrains.mps.ide.bookmark.BookmarkManager.BookmarkListener;
import jetbrains.mps.ide.icons.IdeIcons;
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.openapi.navigation.EditorNavigator;
import jetbrains.mps.project.Project;
import jetbrains.mps.smodel.ModelReadRunnable;
import jetbrains.mps.workbench.action.ActionUtils;
import jetbrains.mps.workbench.action.BaseAction;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.model.SNodeReference;
import java.util.List;
import java.util.Map;
public class BookmarksTree extends MPSTree {
private final BookmarkManager myBookmarkManager;
private final Project myProject;
public BookmarksTree(Project project, BookmarkManager bookmarkManager) {
myBookmarkManager = bookmarkManager;
myProject = project;
myBookmarkManager.addBookmarkListener(new BookmarkListener() {
@Override
public void bookmarkAdded(int number, SNode node) {
rebuildBookmarksTree();
}
@Override
public void bookmarkRemoved(int number, SNode node) {
rebuildBookmarksTree();
}
private void rebuildBookmarksTree() {
BookmarksTree.this.rebuildLater();
}
});
}
@Override
protected void doInit(MPSTreeNode node, Runnable nodeInitRunnable) {
super.doInit(node, new ModelReadRunnable(myProject.getModelAccess(), nodeInitRunnable));
}
@Override
protected ActionGroup createPopupActionGroup(final MPSTreeNode node) {
if (node instanceof BookmarkNode) {
BaseAction action = new BaseAction("Remove Bookmark") {
@Override
protected void doExecute(AnActionEvent e, Map<String, Object> _params) {
((BookmarkNode) node).removeBookmark();
}
};
return ActionUtils.groupFromActions(action);
} else if(!(node instanceof SNodeTreeNode)){
BaseAction hierarchyAction = new BaseAction("Remove All Bookmarks") {
@Override
protected void doExecute(AnActionEvent e, Map<String, Object> _params) {
myBookmarkManager.clearBookmarks();
}
};
return ActionUtils.groupFromActions(hierarchyAction);
}
return null;
}
@Override
protected MPSTreeNode rebuild() {
MPSTreeNode root = new TextTreeNode("no bookmarks");
root.setIcon(IdeIcons.DEFAULT_ICON);
List<SNodeReference> nodePointers = myBookmarkManager.getAllNumberedBookmarks();
boolean hasBookmarks = false;
for (int i = 0; i < nodePointers.size(); i++) {
final SNodeReference nodePointer = nodePointers.get(i);
if (nodePointer != null && nodePointer.resolve(myProject.getRepository()) != null) {
hasBookmarks = true;
TextTreeNode textTreeNode = new MyTextTreeNodeNumbered(i);
textTreeNode.setIcon(BookmarkManager.getIcon(i));
textTreeNode.add(new SNodeTreeNode(nodePointer.resolve(myProject.getRepository())));
root.add(textTreeNode);
}
}
nodePointers = myBookmarkManager.getAllUnnumberedBookmarks();
for (SNodeReference nodePointer : nodePointers) {
if (nodePointer != null && nodePointer.resolve(myProject.getRepository()) != null) {
hasBookmarks = true;
TextTreeNode textTreeNode = new MyTextTreeNodeUnnumbered(nodePointer);
textTreeNode.setIcon(BookmarkManager.getIcon(-1));
textTreeNode.add(new SNodeTreeNode(nodePointer.resolve(myProject.getRepository())));
root.add(textTreeNode);
}
}
if (hasBookmarks) {
root.setText("bookmarks");
}
return root;
}
public void gotoSelectedBookmark() {
final BookmarkNode node = getSelectedBookmarkNode();
if (node != null) {
node.navigateToBookmark();
}
}
public void removeSelectedBookmark() {
BookmarkNode node = getSelectedBookmarkNode();
if (node != null) {
node.removeBookmark();
}
}
private BookmarkNode getSelectedBookmarkNode() {
MPSTreeNode selectedNode = (MPSTreeNode) getSelectionPath().getLastPathComponent();
while (selectedNode != null) {
if (selectedNode instanceof BookmarkNode) {
return (BookmarkNode) selectedNode;
}
selectedNode = (MPSTreeNode) selectedNode.getParent();
}
return null;
}
@Override
protected void doubleClick(@NotNull MPSTreeNode nodeToClick) {
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 interface BookmarkNode {
public void navigateToBookmark();
public void removeBookmark();
}
private class MyTextTreeNodeNumbered extends TextTreeNode implements BookmarkNode {
int myNumber;
public MyTextTreeNodeNumbered(int i) {
super("bookmark " + i);
myNumber = i;
setNodeIdentifier("bookmark" + i);
}
@Override
public void removeBookmark() {
myBookmarkManager.removeBookmark(myNumber);
}
@Override
public void navigateToBookmark() {
myBookmarkManager.navigateToBookmark(myNumber);
}
}
private class MyTextTreeNodeUnnumbered extends TextTreeNode implements BookmarkNode {
SNodeReference myNodePointer;
@Override
public void removeBookmark() {
myBookmarkManager.removeUnnumberedBookmark(myNodePointer);
}
public MyTextTreeNodeUnnumbered(SNodeReference nodePointer) {
super("bookmark");
myNodePointer = nodePointer;
setNodeIdentifier("bookmark_" + nodePointer.toString());
}
@Override
public void navigateToBookmark() {
new EditorNavigator(myProject).shallFocus(true).shallSelect(true).open(myNodePointer);
}
}
}