public void collapseFoldRegion(FoldRegion region) {
    assertIsDispatchThreadForEditor();
    if (!region.isExpanded()) return;

    if (!myIsBatchFoldingProcessing) {
      LOG.error("Fold regions must be collapsed or expanded inside batchFoldProcessing() only.");
    }

    List<Caret> carets = myEditor.getCaretModel().getAllCarets();
    for (Caret caret : carets) {
      LogicalPosition caretPosition = caret.getLogicalPosition();
      int caretOffset = myEditor.logicalPositionToOffset(caretPosition);

      if (FoldRegionsTree.contains(region, caretOffset)) {
        if (myDoNotCollapseCaret) return;
      }
    }
    for (Caret caret : carets) {
      LogicalPosition caretPosition = caret.getLogicalPosition();
      int caretOffset = myEditor.logicalPositionToOffset(caretPosition);

      if (FoldRegionsTree.contains(region, caretOffset)) {
        if (caret.getUserData(SAVED_CARET_POSITION) == null) {
          caret.putUserData(SAVED_CARET_POSITION, caretPosition.withoutVisualPositionInfo());
        }
      }
    }

    myFoldRegionsProcessed = true;
    ((FoldRegionImpl) region).setExpandedInternal(false);
    notifyListenersOnFoldRegionStateChange(region);
  }
예제 #2
0
  public void collapseFoldRegion(FoldRegion region) {
    assertIsDispatchThread();
    if (!region.isExpanded()) return;

    if (!myIsBatchFoldingProcessing) {
      LOG.error("Fold regions must be collapsed or expanded inside batchFoldProcessing() only.");
    }

    LogicalPosition caretPosition = myEditor.getCaretModel().getLogicalPosition();

    int caretOffset = myEditor.logicalPositionToOffset(caretPosition);

    if (FoldRegionsTree.contains(region, caretOffset)) {
      if (myDoNotCollapseCaret) return;

      if (!myCaretPositionSaved) {
        mySavedCaretX = caretPosition.column;
        mySavedCaretY = caretPosition.line;
        myCaretPositionSaved = true;
      }
    }

    int selectionStart = myEditor.getSelectionModel().getSelectionStart();
    int selectionEnd = myEditor.getSelectionModel().getSelectionEnd();

    if (FoldRegionsTree.contains(region, selectionStart - 1)
        || FoldRegionsTree.contains(region, selectionEnd))
      myEditor.getSelectionModel().removeSelection();

    myFoldRegionsProcessed = true;
    ((FoldRegionImpl) region).setExpandedInternal(false);
    notifyListenersOnFoldRegionStateChange(region);
  }
예제 #3
0
  private void runBatchFoldingOperation(final Runnable operation, final boolean dontCollapseCaret) {
    assertIsDispatchThread();
    boolean oldDontCollapseCaret = myDoNotCollapseCaret;
    myDoNotCollapseCaret |= dontCollapseCaret;
    boolean oldBatchFlag = myIsBatchFoldingProcessing;
    if (!oldBatchFlag) {
      mySavedCaretShift =
          myEditor.visibleLineToY(myEditor.getCaretModel().getVisualPosition().line)
              - myEditor.getScrollingModel().getVerticalScrollOffset();
    }

    myIsBatchFoldingProcessing = true;
    myFoldTree.myCachedLastIndex = -1;
    operation.run();
    myFoldTree.myCachedLastIndex = -1;

    if (!oldBatchFlag) {
      if (myFoldRegionsProcessed) {
        notifyBatchFoldingProcessingDone();
        myFoldRegionsProcessed = false;
      }
      myIsBatchFoldingProcessing = false;
    }
    myDoNotCollapseCaret = oldDontCollapseCaret;
  }
예제 #4
0
 public void documentChanged(DocumentEvent event) {
   if (((DocumentEx) event.getDocument()).isInBulkUpdate()) {
     myFoldTree.clear();
   } else {
     updateCachedOffsets();
   }
 }
  @Override
  public boolean addFoldRegion(@NotNull final FoldRegion region) {
    assertIsDispatchThreadForEditor();
    if (!isFoldingEnabled()) {
      return false;
    }
    if (!myIsBatchFoldingProcessing) {
      LOG.error("Fold regions must be added or removed inside batchFoldProcessing() only.");
      return false;
    }

    myFoldRegionsProcessed = true;
    if (myFoldTree.addRegion(region)) {
      final FoldingGroup group = region.getGroup();
      if (group != null) {
        myGroups.putValue(group, region);
      }
      for (FoldingListener listener : myListeners) {
        listener.onFoldRegionStateChange(region);
      }
      return true;
    }

    return false;
  }
 public int getFoldedLinesCountBefore(int offset) {
   if (!myDocumentChangeProcessed && myEditor.getDocument().isInEventsHandling()) {
     // There is a possible case that this method is called on document update before fold regions
     // are recalculated.
     // We return zero in such situations then.
     return 0;
   }
   return myFoldTree.getFoldedLinesCountBefore(offset);
 }
  @Override
  @Nullable
  public FoldRegion getFoldingPlaceholderAt(Point p) {
    assertReadAccess();
    LogicalPosition pos = myEditor.xyToLogicalPosition(p);
    int line = pos.line;

    if (line >= myEditor.getDocument().getLineCount()) return null;

    int offset = myEditor.logicalPositionToOffset(pos);

    return myFoldTree.fetchOutermost(offset);
  }
예제 #8
0
  public void removeFoldRegion(@NotNull final FoldRegion region) {
    assertIsDispatchThread();

    if (!myIsBatchFoldingProcessing) {
      LOG.error("Fold regions must be added or removed inside batchFoldProcessing() only.");
    }

    region.setExpanded(true);
    final FoldingGroup group = region.getGroup();
    if (group != null) {
      myGroups.removeValue(group, region);
    }

    myFoldTree.removeRegion(region);
    myFoldRegionsProcessed = true;
    region.dispose();
  }
예제 #9
0
  public void expandFoldRegion(FoldRegion region) {
    assertIsDispatchThread();
    if (region.isExpanded() || region.shouldNeverExpand()) return;

    if (!myIsBatchFoldingProcessing) {
      LOG.error("Fold regions must be collapsed or expanded inside batchFoldProcessing() only.");
    }

    if (myCaretPositionSaved) {
      int savedOffset =
          myEditor.logicalPositionToOffset(new LogicalPosition(mySavedCaretY, mySavedCaretX));

      FoldRegion[] allCollapsed = myFoldTree.fetchCollapsedAt(savedOffset);
      if (allCollapsed.length == 1 && allCollapsed[0] == region) {
        LogicalPosition pos = new LogicalPosition(mySavedCaretY, mySavedCaretX);
        myEditor.getCaretModel().moveToLogicalPosition(pos);
      }
    }

    myFoldRegionsProcessed = true;
    ((FoldRegionImpl) region).setExpandedInternal(true);
    notifyListenersOnFoldRegionStateChange(region);
  }
  public void expandFoldRegion(FoldRegion region) {
    assertIsDispatchThreadForEditor();
    if (region.isExpanded() || region.shouldNeverExpand()) return;

    if (!myIsBatchFoldingProcessing) {
      LOG.error("Fold regions must be collapsed or expanded inside batchFoldProcessing() only.");
    }

    for (Caret caret : myEditor.getCaretModel().getAllCarets()) {
      LogicalPosition savedPosition = caret.getUserData(SAVED_CARET_POSITION);
      if (savedPosition != null) {
        int savedOffset = myEditor.logicalPositionToOffset(savedPosition);

        FoldRegion[] allCollapsed = myFoldTree.fetchCollapsedAt(savedOffset);
        if (allCollapsed.length == 1 && allCollapsed[0] == region) {
          caret.moveToLogicalPosition(savedPosition);
        }
      }
    }

    myFoldRegionsProcessed = true;
    ((FoldRegionImpl) region).setExpandedInternal(true);
    notifyListenersOnFoldRegionStateChange(region);
  }
 public FoldRegion[] fetchVisible() {
   return myFoldTree.fetchVisible();
 }
 public FoldRegion[] fetchCollapsedAt(int offset) {
   return myFoldTree.fetchCollapsedAt(offset);
 }
 @Override
 public boolean intersectsRegion(int startOffset, int endOffset) {
   return myFoldTree.intersectsRegion(startOffset, endOffset);
 }
 @Override
 @Nullable
 public FoldRegion[] fetchTopLevel() {
   return myFoldTree.fetchTopLevel();
 }
 @Override
 @Nullable
 public FoldRegion fetchOutermost(int offset) {
   return myFoldTree.fetchOutermost(offset);
 }
 void onBulkDocumentUpdateFinished() {
   myFoldTree.rebuild();
 }
 @Override
 @Nullable
 public FoldRegion getCollapsedRegionAtOffset(int offset) {
   return myFoldTree.fetchOutermost(offset);
 }
  private void notifyBatchFoldingProcessingDone(final boolean moveCaretFromCollapsedRegion) {
    rebuild();

    for (FoldingListener listener : myListeners) {
      listener.onFoldProcessingEnd();
    }

    myEditor.updateCaretCursor();
    myEditor.recalculateSizeAndRepaint();
    myEditor.getGutterComponentEx().updateSize();
    myEditor.getGutterComponentEx().repaint();

    for (Caret caret : myEditor.getCaretModel().getAllCarets()) {
      // There is a possible case that caret position is already visual position aware. But visual
      // position depends on number of folded
      // logical lines as well, hence, we can't be sure that target logical position defines correct
      // visual position because fold
      // regions have just changed. Hence, we use 'raw' logical position instead.
      LogicalPosition caretPosition = caret.getLogicalPosition().withoutVisualPositionInfo();
      int caretOffset = myEditor.logicalPositionToOffset(caretPosition);
      int selectionStart = caret.getSelectionStart();
      int selectionEnd = caret.getSelectionEnd();

      LogicalPosition positionToUse = null;
      int offsetToUse = -1;

      FoldRegion collapsed = myFoldTree.fetchOutermost(caretOffset);
      LogicalPosition savedPosition = caret.getUserData(SAVED_CARET_POSITION);
      if (savedPosition != null) {
        int savedOffset = myEditor.logicalPositionToOffset(savedPosition);
        FoldRegion collapsedAtSaved = myFoldTree.fetchOutermost(savedOffset);
        if (collapsedAtSaved == null) {
          positionToUse = savedPosition;
        } else {
          offsetToUse = collapsedAtSaved.getStartOffset();
        }
      }

      if (collapsed != null && positionToUse == null) {
        positionToUse = myEditor.offsetToLogicalPosition(collapsed.getStartOffset());
      }

      if (moveCaretFromCollapsedRegion && caret.isUpToDate()) {
        if (offsetToUse >= 0) {
          caret.moveToOffset(offsetToUse);
        } else if (positionToUse != null) {
          caret.moveToLogicalPosition(positionToUse);
        } else {
          caret.moveToLogicalPosition(caretPosition);
        }
      }

      caret.putUserData(SAVED_CARET_POSITION, savedPosition);

      if (isOffsetInsideCollapsedRegion(selectionStart)
          || isOffsetInsideCollapsedRegion(selectionEnd)) {
        caret.removeSelection();
      } else if (selectionStart < myEditor.getDocument().getTextLength()) {
        caret.setSelection(selectionStart, selectionEnd);
      }
    }

    if (mySavedCaretShift > 0) {
      final ScrollingModel scrollingModel = myEditor.getScrollingModel();
      scrollingModel.disableAnimation();
      scrollingModel.scrollVertically(
          myEditor.visibleLineToY(myEditor.getCaretModel().getVisualPosition().line)
              - mySavedCaretShift);
      scrollingModel.enableAnimation();
    }
  }
 @Override
 public void rebuild() {
   if (!myEditor.getDocument().isInBulkUpdate()) {
     myFoldTree.rebuild();
   }
 }
예제 #20
0
 public int getFoldedLinesCountBefore(int offset) {
   return myFoldTree.getFoldedLinesCountBefore(offset);
 }
예제 #21
0
 @Override
 public void rebuild() {
   myFoldTree.rebuild();
 }
 public void doClearFoldRegions() {
   myGroups.clear();
   myFoldTree.clear();
 }
예제 #23
0
 @Override
 public String toString() {
   return Arrays.toString(myFoldTree.fetchTopLevel());
 }
 @Nullable
 @Override
 public FoldRegion getFoldRegion(int startOffset, int endOffset) {
   assertReadAccess();
   return myFoldTree.getRegionAt(startOffset, endOffset);
 }
 @Override
 public int getLastCollapsedRegionBefore(int offset) {
   return myFoldTree.getLastTopLevelIndexBefore(offset);
 }
 private void updateCachedOffsets() {
   myFoldTree.updateCachedOffsets();
 }
 void onBulkDocumentUpdateStarted() {
   myFoldTree.clearCachedValues();
 }
예제 #28
0
  private void doNotifyBatchFoldingProcessingDone() {
    myFoldTree.rebuild();

    for (FoldingListener listener : myListeners) {
      listener.onFoldProcessingEnd();
    }

    myEditor.updateCaretCursor();
    myEditor.recalculateSizeAndRepaint();
    if (myEditor.getGutterComponentEx().isFoldingOutlineShown()) {
      myEditor.getGutterComponentEx().repaint();
    }

    LogicalPosition caretPosition = myEditor.getCaretModel().getLogicalPosition();
    // There is a possible case that caret position is already visual position aware. But visual
    // position depends on number of folded
    // logical lines as well, hence, we can't be sure that target logical position defines correct
    // visual position because fold
    // regions have just changed. Hence, we use 'raw' logical position instead.
    if (caretPosition.visualPositionAware) {
      caretPosition = new LogicalPosition(caretPosition.line, caretPosition.column);
    }
    int caretOffset = myEditor.logicalPositionToOffset(caretPosition);
    boolean hasBlockSelection = myEditor.getSelectionModel().hasBlockSelection();
    int selectionStart = myEditor.getSelectionModel().getSelectionStart();
    int selectionEnd = myEditor.getSelectionModel().getSelectionEnd();

    int column = -1;
    int line = -1;
    int offsetToUse = -1;

    FoldRegion collapsed = myFoldTree.fetchOutermost(caretOffset);
    if (myCaretPositionSaved) {
      int savedOffset =
          myEditor.logicalPositionToOffset(new LogicalPosition(mySavedCaretY, mySavedCaretX));
      FoldRegion collapsedAtSaved = myFoldTree.fetchOutermost(savedOffset);
      if (collapsedAtSaved == null) {
        column = mySavedCaretX;
        line = mySavedCaretY;
      } else {
        offsetToUse = collapsedAtSaved.getStartOffset();
      }
    }

    if (collapsed != null && column == -1) {
      line = collapsed.getDocument().getLineNumber(collapsed.getStartOffset());
      column = myEditor.offsetToLogicalPosition(collapsed.getStartOffset()).column;
    }

    boolean oldCaretPositionSaved = myCaretPositionSaved;

    if (offsetToUse >= 0) {
      myEditor.getCaretModel().moveToOffset(offsetToUse);
    } else if (column != -1) {
      myEditor.getCaretModel().moveToLogicalPosition(new LogicalPosition(line, column));
    } else {
      myEditor.getCaretModel().moveToLogicalPosition(caretPosition);
    }

    myCaretPositionSaved = oldCaretPositionSaved;

    if (!hasBlockSelection && selectionStart < myEditor.getDocument().getTextLength()) {
      myEditor.getSelectionModel().setSelection(selectionStart, selectionEnd);
    }

    if (mySavedCaretShift > 0) {
      myEditor.getScrollingModel().disableAnimation();
      int scrollTo =
          myEditor.visibleLineToY(myEditor.getCaretModel().getVisualPosition().line)
              - mySavedCaretShift;
      myEditor.getScrollingModel().scrollVertically(scrollTo);
      myEditor.getScrollingModel().enableAnimation();
    }
  }
 @NotNull
 @Override
 public String dumpState() {
   return Arrays.toString(myFoldTree.fetchTopLevel());
 }
 @Override
 @NotNull
 public FoldRegion[] getAllFoldRegions() {
   assertReadAccess();
   return myFoldTree.fetchAllRegions();
 }