/*
* 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.nodeEditor;
import com.intellij.openapi.wm.IdeFocusManager;
import jetbrains.mps.ide.ThreadUtils;
import jetbrains.mps.ide.project.ProjectHelper;
import jetbrains.mps.nodeEditor.assist.DisabledContextAssistantManager;
import jetbrains.mps.nodeEditor.cells.EditorCell_Label;
import jetbrains.mps.nodeEditor.configuration.EditorConfiguration;
import jetbrains.mps.nodeEditor.configuration.EditorConfigurationBuilder;
import jetbrains.mps.nodeEditor.inspector.InspectorEditorComponent;
import jetbrains.mps.openapi.editor.EditorComponentState;
import jetbrains.mps.openapi.editor.EditorInspector;
import jetbrains.mps.openapi.editor.EditorPanelManager;
import jetbrains.mps.openapi.editor.assist.ContextAssistantManager;
import jetbrains.mps.openapi.editor.cells.EditorCell;
import jetbrains.mps.openapi.editor.cells.EditorCellFactory;
import jetbrains.mps.openapi.editor.selection.SelectionManager;
import jetbrains.mps.project.GlobalOperationContext;
import jetbrains.mps.project.ModuleContext;
import jetbrains.mps.project.Project;
import jetbrains.mps.project.ProjectOperationContext;
import jetbrains.mps.smodel.IOperationContext;
import jetbrains.mps.smodel.ModelAccess;
import jetbrains.mps.util.Computable;
import jetbrains.mps.util.performance.IPerformanceTracer;
import jetbrains.mps.util.performance.PerformanceTracer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.mps.openapi.model.EditableSModel;
import org.jetbrains.mps.openapi.model.SModel;
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.module.SModule;
import org.jetbrains.mps.openapi.module.SRepository;
import java.util.List;
/**
* Author: Sergey Dmitriev
* Created Sep 14, 2003
*/
public class EditorContext implements jetbrains.mps.openapi.editor.EditorContext {
private final EditorComponent myNodeEditorComponent;
private final SRepository myRepository;
private final SModel myModel;
private final EditorConfiguration myConfiguration;
private EditorManager myEditorManager;
private EditorCell myContextCell;
private IPerformanceTracer myPerformanceTracer = null;
@NotNull
private final ContextAssistantManager myContextAssistantManager;
public EditorContext(@NotNull EditorComponent editorComponent, @Nullable SModel model, @NotNull SRepository repository) {
this(editorComponent, model, repository, EditorConfigurationBuilder.buildDefault(), new DisabledContextAssistantManager());
}
public EditorContext(@NotNull EditorComponent editorComponent, @Nullable SModel model, @NotNull SRepository repository, EditorConfiguration configuration,
@NotNull ContextAssistantManager contextAssistantManager) {
myNodeEditorComponent = editorComponent;
myModel = model;
myRepository = repository;
myContextAssistantManager = contextAssistantManager;
myConfiguration = configuration;
}
public EditorComponent getNodeEditorComponent() {
return myNodeEditorComponent;
}
@NotNull
@Override
public jetbrains.mps.openapi.editor.EditorComponent getEditorComponent() {
return myNodeEditorComponent;
}
@Override
public boolean isEditable() {
SNode node = myNodeEditorComponent.getRootCell().getSNode();
if (node == null) {
return false;
}
SModel model = node.getModel();
return model instanceof EditableSModel && !model.isReadOnly();
}
@Override
public boolean isInspector() {
return myNodeEditorComponent instanceof InspectorEditorComponent;
}
@Override
public EditorCell getSelectedCell() {
return myNodeEditorComponent.getSelectedCell();
}
public String getSelectedCellText() {
EditorCell selectedCell = getSelectedCell();
if (selectedCell instanceof EditorCell_Label) {
return ((EditorCell_Label) selectedCell).getRenderedText();
}
return null;
}
@NotNull
@Override
public SRepository getRepository() {
return myRepository;
}
@Override
public SNode getSelectedNode() {
return myNodeEditorComponent.getSelectedNode();
}
@Override
public SModel getModel() {
return myModel;
}
@Override
public IOperationContext getOperationContext() {
Project project = ProjectHelper.getProject(myRepository);
if (project == null) {
return new GlobalOperationContext() {
@Override
public <T> T getComponent(Class<T> clazz) {
if (EditorManager.class == clazz) {
return (T) getEditorManager();
}
return super.getComponent(clazz);
}
};
}
SModule module = myModel == null ? null : myModel.getModule();
if (module == null) {
return new ProjectOperationContext(project) {
@Override
public <T> T getComponent(@NotNull Class<T> clazz) {
if (EditorManager.class == clazz) {
return (T) getEditorManager();
}
return super.getComponent(clazz);
}
};
}
return new ModuleContext(module, project) {
@Override
public <T> T getComponent(@NotNull Class<T> clazz) {
if (EditorManager.class == clazz) {
return (T) getEditorManager();
}
return super.getComponent(clazz);
}
};
}
@Override
public void flushEvents() {
// TODO: replace all usages by updater.flushModelEvents() ?
myNodeEditorComponent.getUpdater().flushModelEvents();
}
/**
* @deprecated Since MPS 3.4 use getState()
*/
@Deprecated
@Override
public Object createMemento() {
return getEditorComponentState();
}
@Override
public EditorComponentState getEditorComponentState() {
return new Memento(this, false);
}
/**
* @deprecated Since MPS 3.4 use getState()
*/
@Deprecated
@Override
public boolean setMemento(Object o) {
if (o instanceof EditorComponentState) {
restoreEditorComponentState((EditorComponentState) o);
return true;
}
return false;
}
@Override
public void restoreEditorComponentState(EditorComponentState state) {
if (state instanceof Memento) {
Memento memento = (Memento) state;
ModelAccess.instance().runReadAction(() -> {
myNodeEditorComponent.relayout();
memento.restore(myNodeEditorComponent);
});
myNodeEditorComponent.getUpdater().flushModelEvents();
}
}
@Override
public void select(final SNode node) {
flushEvents();
getNodeEditorComponent().selectNode(node);
}
@Override
public void selectRange(SNode first, SNode last) {
flushEvents();
SelectionManager selectionManager = getNodeEditorComponent().getSelectionManager();
selectionManager.setSelection(selectionManager.createRangeSelection(first, last));
}
@Override
public void selectWRTFocusPolicy(final SNode node) {
selectWRTFocusPolicy(node, true);
}
@Override
public EditorInspector getInspector() {
return getOperationContext().getComponent(InspectorTool.class);
}
@Override
public void selectWRTFocusPolicy(final SNode node, final boolean force) {
flushEvents();
if (!force && getNodeEditorComponent().getSelectedNode() == node) {
return;
}
EditorCell cell = getNodeEditorComponent().findNodeCell(node);
if (cell != null) {
getNodeEditorComponent().changeSelectionWRTFocusPolicy(cell);
}
}
@Override
public void selectWRTFocusPolicy(EditorCell editorCell) {
getNodeEditorComponent().changeSelectionWRTFocusPolicy(editorCell);
}
@Override
public void openInspector() {
ThreadUtils.runInUIThreadNoWait(() -> IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> {
final InspectorTool inspector = getOperationContext().getComponent(InspectorTool.class);
if (inspector != null) {
inspector.openTool(true);
}
}));
}
@Override
public EditorCell getContextCell() {
if (myContextCell == null) {
return getNodeEditorComponent().getSelectedCell();
}
return myContextCell;
}
@Override
public void runWithContextCell(EditorCell contextCell, final Runnable r) {
runWithContextCell(contextCell, () -> {
r.run();
return null;
});
}
@Override
public <T> T runWithContextCell(EditorCell contextCell, Computable<T> r) {
EditorCell oldContextCell = myContextCell;
myContextCell = contextCell;
try {
return r.compute();
} finally {
myContextCell = oldContextCell;
}
}
@Override
public List<SNode> getSelectedNodes() {
return myNodeEditorComponent.getSelectedNodes();
}
void startTracing(String name) {
assert myPerformanceTracer == null;
myPerformanceTracer = new PerformanceTracer(name);
}
String stopTracing() {
assert myPerformanceTracer != null;
String result = myPerformanceTracer.report();
myPerformanceTracer = null;
return result;
}
boolean isTracing() {
return myPerformanceTracer != null;
}
public void pushTracerTask(String message, boolean isMajor) {
if (myPerformanceTracer == null) {
return;
}
myPerformanceTracer.push(message, isMajor);
}
public void popTracerTask() {
if (myPerformanceTracer == null) {
return;
}
myPerformanceTracer.pop();
}
@Override
public EditorCellFactory getCellFactory() {
return getEditorComponent().getUpdater().getCurrentUpdateSession().getCellFactory();
}
@Override
public SelectionManager getSelectionManager() {
return myNodeEditorComponent.getSelectionManager();
}
@NotNull
@Override
public ContextAssistantManager getContextAssistantManager() {
return myContextAssistantManager;
}
public EditorManager getEditorManager() {
if (myEditorManager == null) {
myEditorManager = new EditorManager(this);
}
return myEditorManager;
}
void reset() {
myEditorManager = null;
}
@Nullable
@Override
public EditorPanelManager getEditorPanelManager() {
return myConfiguration.editorPanelManager;
}
}