/*
* 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.cellExplorer.cellsTree;
import jetbrains.mps.icons.MPSIcons.CellExplorer;
import jetbrains.mps.ide.devkit.cellExplorer.CellExplorerTool;
import jetbrains.mps.ide.devkit.cellExplorer.MPSTreeWithAction;
import jetbrains.mps.ide.ui.tree.MPSTreeNode;
import jetbrains.mps.ide.ui.tree.TextTreeNode;
import jetbrains.mps.nodeEditor.EditorComponent;
import jetbrains.mps.openapi.editor.cells.CellTraversalUtil;
import jetbrains.mps.openapi.editor.cells.EditorCell;
import jetbrains.mps.openapi.editor.update.UpdaterListener;
import jetbrains.mps.openapi.editor.update.UpdaterListenerAdapter;
import jetbrains.mps.smodel.ModelReadRunnable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import java.util.Collections;
import java.util.List;
public class CellsTree extends MPSTreeWithAction {
private final UpdaterListener mySynchronizationListener = new MyUpdaterListenerAdapter();
private EditorComponent myCurrentEditor;
public CellsTree() {
setRootVisible(true);
}
@Override
protected void doInit(MPSTreeNode node, Runnable nodeInitRunnable) {
// myCurrentEditor could not be null, otherwise we won't get to CellNode.init()
super.doInit(node, new ModelReadRunnable(myCurrentEditor.getEditorContext().getRepository().getModelAccess(), nodeInitRunnable));
}
@Override
protected MPSTreeNode rebuild() {
if (myCurrentEditor == null || myCurrentEditor.getRootCell() == null) {
TextTreeNode rv = new TextTreeNode("No editor selected");
rv.setIcon(CellExplorer.CellExplorer);
return rv;
} else {
return new CellNode(myCurrentEditor.getRootCell());
}
}
public void setCurrentEditor(EditorComponent cellEditor) {
if (myCurrentEditor == cellEditor) return;
if (myCurrentEditor != null) {
myCurrentEditor.getUpdater().removeListener(mySynchronizationListener);
}
myCurrentEditor = cellEditor;
if (myCurrentEditor != null) {
myCurrentEditor.getUpdater().addListener(mySynchronizationListener);
}
rebuildNow();
}
@Override
public void dispose() {
setCurrentEditor(null);
super.dispose();
}
public void showCellInTree(EditorCell cell) {
EditorComponent cellEditor = (EditorComponent) cell.getEditorComponent();
setCurrentEditor(cellEditor);
MPSTreeNode current = findCellNode(cell);
if (current == null) {
CellExplorerTool.LOG.warn("Can't find cell in tree");
return;
}
selectNode(current);
}
private MPSTreeNode findCellNode(EditorCell cell) {
if (cell == null) return null;
List<EditorCell> path = getEditorCellPath(cell);
MPSTreeNode current = getRootNode();
if (current.getUserObject() != path.get(0)) return null;
for (int i = 1; i < path.size(); i++) {
if (!current.isInitialized()) current.init();
current = current.findExactChildWith(path.get(i));
if (current == null) return null;
}
return current;
}
@NotNull
private static List<EditorCell> getEditorCellPath(EditorCell cell) {
List<EditorCell> path = CellTraversalUtil.getParents(cell, true);
Collections.reverse(path);
return path;
}
@Nullable
public EditorCell getCellByPath(@Nullable TreePath path) {
if (path == null) return null;
Object[] nodes = path.getPath();
for (int i = nodes.length - 1; i >= 0; i--) {
Object node = nodes[i];
if (!(node instanceof DefaultMutableTreeNode)) continue;
Object userObject = ((DefaultMutableTreeNode) node).getUserObject();
if (userObject instanceof EditorCell) return ((EditorCell) userObject);
}
return null;
}
private class MyUpdaterListenerAdapter extends UpdaterListenerAdapter {
private CellNode myCachedPropertyCellNode = null;
@Override
public void cellSynchronizedWithModel(EditorCell cell) {
if (cell == null) {
return;
}
CellNode cellNode;
if (myCachedPropertyCellNode != null && cell == myCachedPropertyCellNode.getUserObject()) {
cellNode = myCachedPropertyCellNode;
} else {
cellNode = (CellNode) findCellNode(cell);
myCachedPropertyCellNode = cellNode;
}
if (cellNode == null) {
return;
}
cellNode.updatePresentation(true, false);
repaint();
}
@Override
public void editorUpdated(jetbrains.mps.openapi.editor.EditorComponent editorComponent) {
rebuildLater();
}
}
}