public static EditorCell getSiblingCollectionForInsert( @NotNull EditorCell cell, boolean forward) { // TODO FIXME rewrite without hasSingleRolesAtLeftBoundary, cleanup ChildrenCollectionFinder EditorCell nextLeaf = (forward ? APICellAdapter.getNextLeaf(cell) : APICellAdapter.getPrevLeaf(cell)); if ((APICellAdapter.isBigCell(cell) || APICellAdapter.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; }
/** * 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 = APICellAdapter.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((jetbrains.mps.nodeEditor.cells.EditorCell) parentCell); } } return true; }
public EditorCellLabelSelection( EditorComponent editorComponent, Map<String, String> properties, CellInfo cellInfo) throws SelectionStoreException, SelectionRestoreException { super(editorComponent, properties, cellInfo); if (!(getEditorCell() instanceof EditorCell_Label)) { throw new SelectionRestoreException(); } myNonTrivialSelection = SelectionInfoImpl.Util.getBooleanProperty( properties, HAS_NON_TRIVIAL_SELECTION_PROPERTY_NAME); if (APICellAdapter.getCellInfo(getEditorCell()).equals(cellInfo)) { if (myNonTrivialSelection) { /* This is kind of hack for EditorManager.STHintCellInfo - if located cell is different from the original one then we do not restore selection. */ mySelectionStart = SelectionInfoImpl.Util.getIntProperty(properties, SELECTION_START_PROPERTY_NAME); mySelectionEnd = SelectionInfoImpl.Util.getIntProperty(properties, SELECTION_END_PROPERTY_NAME); } } else { myNonTrivialSelection = false; } }
public int getIconCoordinate(EditorMessageIconRenderer renderer) { jetbrains.mps.openapi.editor.cells.EditorCell anchorCell = getAnchorCell(renderer); if (anchorCell == null || APICellAdapter.isUnderFolded(anchorCell)) { // no anchorCell return -1; } if (renderer.getIcon() == null) { LOG.error("null icon was returned by renderer: " + renderer); return -1; } return anchorCell.getY() + anchorCell.getHeight() / 2 - renderer.getIcon().getIconHeight() / 2; }
/** Should be executed inside read action */ public static void callInsertBeforeAction(@NotNull EditorCell cell) { 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 && APICellAdapter.executeAction(cellWithRole, CellActionType.INSERT_BEFORE)) { return; } } APICellAdapter.executeAction(cell, CellActionType.INSERT_BEFORE); }
@Override public void doExecute(@NotNull final AnActionEvent event, final Map<String, Object> _params) { FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.goto.definition"); final SNode targetNode = APICellAdapter.getSNodeWRTReference( ((EditorCell) MapSequence.fromMap(_params).get("cell"))); NavigationSupport.getInstance() .openNode( ((IOperationContext) MapSequence.fromMap(_params).get("context")), targetNode, true, !(SNodeOperations.isRoot(targetNode))); }
@Override public boolean isApplicable(AnActionEvent event, final Map<String, Object> _params) { SNode targetNode = APICellAdapter.getSNodeWRTReference( ((EditorCell) MapSequence.fromMap(_params).get("cell"))); if (targetNode == null) { return false; } if (targetNode == ((EditorCell) MapSequence.fromMap(_params).get("cell")).getSNode()) { return false; } return true; }
public boolean processKeyTyped(EditorContext editorContext, final KeyEvent keyEvent) { EditorComponent nodeEditor = editorContext.getNodeEditorComponent(); nodeEditor.hideMessageToolTip(); if (processKeyMaps(editorContext, keyEvent)) { return true; } final EditorCell selectedCell = editorContext.getSelectedCell(); if (selectedCell != null && ((jetbrains.mps.nodeEditor.cells.EditorCell) selectedCell) .processKeyTyped(keyEvent, false)) { keyEvent.consume(); return true; } jetbrains.mps.openapi.editor.cells.CellActionType actionType = editorContext.getNodeEditorComponent().getActionType(keyEvent, editorContext); if (selectedCell != null) { boolean strictMatching = jetbrains.mps.openapi.editor.cells.CellActionType.RIGHT_TRANSFORM.equals(actionType) || jetbrains.mps.openapi.editor.cells.CellActionType.LEFT_TRANSFORM.equals( actionType); if (selectedCell.isErrorState() && strictMatching) { if (APICellAdapter.validate(selectedCell, strictMatching, false)) { return true; } } if (actionType != null) { if (editorContext .getEditorComponent() .getActionHandler() .executeAction(selectedCell, actionType)) { return true; } } } if (selectedCell != null && ((jetbrains.mps.nodeEditor.cells.EditorCell) selectedCell) .processKeyTyped(keyEvent, true)) { keyEvent.consume(); return true; } return false; }
@Override protected boolean suppressDelete(CellActionType type) { if (!super.suppressDelete(type)) { return false; } EditorCell_Label label = getEditorCellLabel(); if (label.getText().length() == 0) { return false; } if (label instanceof EditorCell_Constant || label instanceof EditorCell_Property) { return label.isEditable() || CellFinderUtil.findLastSelectableLeaf(APICellAdapter.getContainingBigCell(label)) != label; } return true; }
private boolean canPasteBefore(EditorCell selectedCell, List<SNode> pasteNodes) { if (!APICellAdapter.isFirstPositionInBigCell(selectedCell)) return false; SNode anchor = selectedCell.getSNode(); if (anchor.getParent() == null) return false; NodeAndRole nodeAndRole = new NodePaster(pasteNodes).getActualAnchorNode(anchor, anchor.getRoleInParent(), false); if (nodeAndRole == null) return false; EditorCell targetCell = selectedCell.getEditorComponent().findNodeCell(nodeAndRole.myNode); return targetCell != null && ((jetbrains.mps.nodeEditor.cells.EditorCell) targetCell) .getFirstLeaf(CellConditions.SELECTABLE) == selectedCell && new NodePaster(pasteNodes).canPasteRelative(nodeAndRole.myNode); }
private EditorCell getCellToPasteTo(EditorCell cell) { if (cell == null) { return cell; } if (APICellAdapter.isLastPositionInBigCell(cell)) return cell; if (cell instanceof EditorCell_Label && cell.getRole() == null) { EditorCell result = new ChildrenCollectionFinder(cell, true, false).find(); if (result != null) { return result; } result = new ChildrenCollectionFinder(cell, false, false).find(); if (result != null) { if (result instanceof EditorCell_Collection) { return ((EditorCell_Collection) result).lastCell(); } return result; } } return cell; }
public static boolean isOnRightBoundary(EditorCell cell) { EditorCell nextLeaf = APICellAdapter.getNextLeaf(cell); return nextLeaf == null || nextLeaf.getSNode() != cell.getSNode(); }
public static boolean isOnLeftBoundary(EditorCell cell) { EditorCell prevLeaf = APICellAdapter.getPrevLeaf(cell); return prevLeaf == null || prevLeaf.getSNode() != cell.getSNode(); }
private boolean processSideDeletes(CellActionType type) { // TODO: review this logic - it was originally copied from EditorComponentKeyboardHandler final EditorCell selectedCell = getEditorCell(); if (type == CellActionType.DELETE && APICellAdapter.isLastPositionInBigCell(selectedCell) && !APICellAdapter.isFirstPositionInBigCell(selectedCell)) { final EditorCell target; EditorCell bigCellNextSibling = CellTraversalUtil.getNextSibling(APICellAdapter.getContainingBigCell(selectedCell)); if (bigCellNextSibling != null) { target = bigCellNextSibling; } else { EditorCell nextSibling = CellTraversalUtil.getNextSibling(APICellAdapter.getContainingBigCell(selectedCell)); if (nextSibling != null) { target = nextSibling; } else { target = CellTraversalUtil.getNextLeaf( selectedCell, jetbrains.mps.openapi.editor.cells.CellConditions.SELECTABLE); } } if (target == null || ModelAccess.instance() .runReadAction( new Computable<Boolean>() { @Override public Boolean compute() { return jetbrains.mps.util.SNodeOperations.isAncestor( target.getSNode(), selectedCell.getSNode()); } })) return false; return getEditorComponent().getActionHandler().executeAction(target, type); } if (type == CellActionType.BACKSPACE && APICellAdapter.isFirstPositionInBigCell(selectedCell) && !APICellAdapter.isLastPositionInBigCell(selectedCell)) { final EditorCell target; EditorCell bigCellPrevSibling = CellTraversalUtil.getPrevSibling(APICellAdapter.getContainingBigCell(selectedCell)); if (bigCellPrevSibling != null) { target = bigCellPrevSibling; } else { EditorCell prevSibling = CellTraversalUtil.getPrevSibling(selectedCell); if (prevSibling != null) { target = prevSibling; } else { target = CellTraversalUtil.getPrevLeaf( selectedCell, jetbrains.mps.openapi.editor.cells.CellConditions.SELECTABLE); } } if (target == null || ReadOnlyUtil.isCellReadOnly(target)) return false; /* Was commented out (again) to let some of our unit-tests be green. in particular - pressing BackSpace at this situation: <code> int a = 1; --|a; <code> where "|" is a position of cursor; if (ModelAccess.instance().runReadAction(new Computable<Boolean>() { public Boolean compute() { return jetbrains.mps.util.SNodeOperations.isAncestor(target.getSNode(), selectedCell.getSNode()); } })) return false; */ return getEditorComponent().getActionHandler().executeAction(target, type); } return false; }
@Override public void execute(final EditorContext context) { LOG.assertLog( context.getRepository().getModelAccess().isCommandAction(), "This action must be performed in command"); final EditorComponent editorComponent = (EditorComponent) context.getEditorComponent(); final Selection selection = editorComponent.getSelectionManager().getSelection(); final List<SNode> selectedNodes = selection.getSelectedNodes(); // this is used in case node is in repo to pass it into invokeLater final List<SNodeReference> selectedReferences = new ArrayList<SNodeReference>(); for (SNode node : selectedNodes) { selectedReferences.add(node.getReference()); } final CellInfo pasteTargetCellInfo; final SNode cellNodeSelected; final SNodeReference selectedCellReference; if (selection instanceof SingularSelection) { EditorCell pasteTargetCell = getCellToPasteTo(context.getSelectedCell()); if (pasteTargetCell == null) { return; } pasteTargetCellInfo = APICellAdapter.getCellInfo(pasteTargetCell); cellNodeSelected = pasteTargetCell.getSNode(); selectedCellReference = cellNodeSelected.getReference(); } else { pasteTargetCellInfo = null; cellNodeSelected = null; selectedCellReference = null; } final SModel modelToPaste = selectedNodes.get(0).getModel(); // sometimes model is not in repository (paste in merge dialog) final boolean inRepository = modelToPaste.getReference().resolve(context.getRepository()) != null; // FIXME relationship between Project and Editor needs attention, it's bad to extract final Project mpsProject = ProjectHelper.getProject(context.getRepository()); if (mpsProject == null) { LOG.warning("Paste needs a project to show a dialog for additional imports"); return; } final PasteNodeData pasteNodeData = CopyPasteUtil.getPasteNodeDataFromClipboard(modelToPaste); // FIXME why SwingUtlities? Is it necessary to execute in EDT thread? If yes, use ThreadUtils. // If not, use any other thread than UI, e.g. app's pooled one. SwingUtilities.invokeLater( new Runnable() { @Override public void run() { final Runnable addImportsRunnable = CopyPasteUtil.addImportsWithDialog(pasteNodeData, modelToPaste, mpsProject); context .getRepository() .getModelAccess() .executeCommandInEDT( new Runnable() { @Override public void run() { if (addImportsRunnable != null) { addImportsRunnable.run(); } List<SNode> pasteNodes = pasteNodeData.getNodes(); List<SNode> currentSelectedNodes; if (!inRepository) { currentSelectedNodes = selectedNodes; } else { currentSelectedNodes = new ArrayList<SNode>(); for (SNodeReference ref : selectedReferences) { currentSelectedNodes.add( ref.resolve(MPSModuleRepository.getInstance())); } } NodePaster nodePaster = new NodePaster(pasteNodes); boolean disposed = checkDisposedSelectedNodes(currentSelectedNodes, selectedReferences); boolean canPasteWithRemove = !disposed && nodePaster.canPasteWithRemove(currentSelectedNodes); if (selection instanceof SingularSelection && (selection instanceof EditorCellLabelSelection && !isCompletelySelected((EditorCellLabelSelection) selection) || (selection instanceof EditorCellSelection && !canPasteWithRemove))) { EditorCell selectedCell = pasteTargetCellInfo.findCell(editorComponent); assert selectedCell != null; if (canPasteBefore(selectedCell, pasteNodes)) { SNode selectedNode = inRepository ? selectedCellReference.resolve( MPSModuleRepository.getInstance()) : cellNodeSelected; if (checkDisposed(selectedCellReference, cellNodeSelected)) { return; } new NodePaster(pasteNodes) .pasteRelative(selectedNode, PastePlaceHint.BEFORE_ANCHOR); } else { new NodePaster(pasteNodes).paste(selectedCell); } } else if ((selection instanceof MultipleSelection || selection instanceof EditorCellSelection) && canPasteWithRemove) { nodePaster.pasteWithRemove(currentSelectedNodes); } else { return; } Set<SReference> requireResolveReferences = new HashSet<SReference>(); for (SReference ref : pasteNodeData.getRequireResolveReferences()) { // ref can be detached from modeltoPaste while using copy/paste handlers if (ref.getSourceNode() == null || ref.getSourceNode().getModel() == null) continue; requireResolveReferences.add(ref); } ResolverComponent.getInstance() .resolveScopesOnly(requireResolveReferences, context.getRepository()); // set selection editorComponent.getUpdater().flushModelEvents(); SNode lastNode = pasteNodes.get(pasteNodes.size() - 1); editorComponent .getSelectionManager() .setSelection(lastNode, SelectionManager.LAST_CELL, -1); } }); } }); }