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; } }