package jetbrains.mps.ide.editor.actions;
/*Generated by MPS */
import jetbrains.mps.nodeEditor.EditorComponent;
import jetbrains.mps.openapi.editor.cells.EditorCell;
import jetbrains.mps.editor.runtime.cells.ReadOnlyUtil;
import jetbrains.mps.openapi.editor.selection.Selection;
import jetbrains.mps.openapi.editor.selection.SingularSelection;
import java.util.Iterator;
import jetbrains.mps.nodeEditor.cells.EditorCell_Component;
import org.jetbrains.annotations.NotNull;
import jetbrains.mps.openapi.editor.ActionHandler;
import jetbrains.mps.nodeEditor.cells.APICellAdapter;
import jetbrains.mps.nodeEditor.cells.EditorCell_Label;
import jetbrains.mps.nodeEditor.ChildrenCollectionFinder;
import jetbrains.mps.openapi.editor.cells.CellActionType;
import jetbrains.mps.openapi.editor.cells.CellTraversalUtil;
import jetbrains.mps.nodeEditor.cells.GeometryUtil;
import jetbrains.mps.openapi.editor.cells.EditorCell_Collection;
import jetbrains.mps.baseLanguage.closures.runtime.Wrappers;
import jetbrains.mps.smodel.ModelAccess;
import jetbrains.mps.util.SNodeOperations;
import org.jetbrains.mps.openapi.language.SContainmentLink;
import org.jetbrains.mps.openapi.model.SNode;
public class EditorActionUtils {
public EditorActionUtils() {
}
/*package*/ static boolean isReadonlyActionEnabled(EditorComponent editorComponent) {
return !(editorComponent.getNodeSubstituteChooser().isVisible()) && editorComponent.getSelectionManager().getSelection() != null;
}
public static boolean isWriteActionEnabled(EditorComponent editorComponent, Iterable<EditorCell> changingCells) {
if (!(isReadonlyActionEnabled(editorComponent))) {
return false;
}
return !(ReadOnlyUtil.isCellsReadOnlyInEditor(editorComponent, changingCells));
}
/*package*/ static EditorCell getEditorCellToInsert(EditorComponent editorComponent) {
Selection selection = editorComponent.getSelectionManager().getSelection();
// TODO: remove this limitation
if (!(selection instanceof SingularSelection)) {
return null;
}
Iterator<EditorCell> iterator = selection.getSelectedCells().iterator();
if (!(iterator.hasNext())) {
return null;
}
EditorCell editorCell = iterator.next();
return (editorCell instanceof EditorCell_Component ? null : editorCell);
}
/**
* Should be executed inside read action
*/
public static void callInsertAction(@NotNull EditorCell cell) {
ActionHandler actionHandler = cell.getEditorComponent().getActionHandler();
if (cell.isErrorState() && APICellAdapter.validate(cell, false, true)) {
return;
}
if (cell instanceof EditorCell_Label && !(isLinkCollection(cell))) {
// Looking for the next child collection to the right from this cell
EditorCell cellWithRole = new ChildrenCollectionFinder(cell, true, false).find();
if (cellWithRole == null) {
// Looking for the next child collection in parents
cellWithRole = getSiblingCollectionForInsert(cell, true);
}
if (cellWithRole != null && actionHandler.executeAction(cellWithRole, CellActionType.INSERT)) {
return;
}
}
actionHandler.executeAction(cell, CellActionType.INSERT);
}
public static EditorCell getSiblingCollectionForInsert(@NotNull EditorCell cell, boolean forward) {
// TODO FIXME rewrite without hasSingleRolesAtLeftBoundary, cleanup ChildrenCollectionFinder
EditorCell nextLeaf = (forward ? CellTraversalUtil.getNextLeaf(cell) : CellTraversalUtil.getPrevLeaf(cell));
if ((cell.isBig() || GeometryUtil.isLastPositionInBigCell(cell)) && ((forward ? hasSingleRolesAtRightBoundary(cell) : hasSingleRolesAtLeftBoundary(cell))) && nextLeaf != null) {
// Looking for the next child collection in parents
return new ChildrenCollectionFinder(nextLeaf, cell, forward, true).find();
}
return null;
}
/**
* Should be executed inside read action
*/
public static void callInsertBeforeAction(@NotNull EditorCell cell) {
ActionHandler actionHandler = cell.getEditorComponent().getActionHandler();
if (cell.isErrorState() && APICellAdapter.validate(cell, true, true)) {
return;
}
if (cell instanceof EditorCell_Label && !(isLinkCollection(cell))) {
// Looking for the prev. child collection (to the left from this cell)
EditorCell cellWithRole = new ChildrenCollectionFinder(cell, false, false).find();
if (cellWithRole == null) {
// Looking for the next child collection in parents
cellWithRole = getSiblingCollectionForInsert(cell, false);
}
if (cellWithRole != null && actionHandler.executeAction(cellWithRole, CellActionType.INSERT_BEFORE)) {
return;
}
}
actionHandler.executeAction(cell, CellActionType.INSERT_BEFORE);
}
/**
* We can use this method to determine if we should redispatch insert event to the corresponding
* child collection below the cell returned from cell.getNextLeaf() or we should go on and insert
* next child into a collection containing cell itself.
*
* @return true if we should redispatch insert event to the next leaft cell
*/
private static boolean hasSingleRolesAtRightBoundary(EditorCell cell) {
if (!(hasSingleRole(cell))) {
return false;
}
if (isOnRightBoundary(cell)) {
final EditorCell_Collection parentCell = cell.getParent();
if (parentCell != null) {
final EditorCell nextLeaf = CellTraversalUtil.getNextLeaf(cell);
if (nextLeaf != null) {
final Wrappers._boolean ancestor = new Wrappers._boolean(false);
ModelAccess.instance().runReadAction(new Runnable() {
public void run() {
ancestor.value = SNodeOperations.isAncestor(parentCell.getSNode(), nextLeaf.getSNode());
}
});
if (ancestor.value) {
return true;
}
}
return hasSingleRolesAtRightBoundary(parentCell);
}
}
return true;
}
/**
* We can use this method to determine if we should redispatch insert event to the corresponding
* child collection below the cell returned from cell.getPrevLeaf() or we should go on and insert
* prev. child into a collection containing cell itself
*
* @return true if we should redispatch insert event to the prev. leaft cell
*/
private static boolean hasSingleRolesAtLeftBoundary(EditorCell cell) {
if (!(hasSingleRole(cell))) {
return false;
}
if (isOnLeftBoundary(cell)) {
final EditorCell_Collection parentCell = cell.getParent();
if (parentCell != null) {
final EditorCell prevLeaf = CellTraversalUtil.getPrevLeaf(cell);
if (prevLeaf != null) {
final Wrappers._boolean ancestor = new Wrappers._boolean(false);
ModelAccess.instance().runReadAction(new Runnable() {
public void run() {
ancestor.value = SNodeOperations.isAncestor(parentCell.getSNode(), prevLeaf.getSNode());
}
});
if (ancestor.value) {
return true;
}
}
return hasSingleRolesAtLeftBoundary((EditorCell) parentCell);
}
}
return true;
}
public static boolean isOnLeftBoundary(EditorCell cell) {
EditorCell prevLeaf = CellTraversalUtil.getPrevLeaf(cell);
return prevLeaf == null || prevLeaf.getSNode() != cell.getSNode();
}
public static boolean isOnRightBoundary(EditorCell cell) {
EditorCell nextLeaf = CellTraversalUtil.getNextLeaf(cell);
return nextLeaf == null || nextLeaf.getSNode() != cell.getSNode();
}
private static boolean hasSingleRole(final EditorCell cell) {
final Wrappers._boolean result = new Wrappers._boolean();
ModelAccess.instance().runReadAction(new Runnable() {
public void run() {
SContainmentLink l = jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations.getContainingLink(((SNode) cell.getSNode()));
result.value = l != null && l.isValid() && !(l.isMultiple());
}
});
return result.value;
}
private static boolean isLinkCollection(EditorCell cell) {
return cell.getRole() != null;
}
}