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;
 }
Beispiel #10
0
  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);
  }
Beispiel #11
0
  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;
  }
Beispiel #15
0
  @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);
                      }
                    });
          }
        });
  }