private void runBatchFoldingOperation( final Runnable operation, final boolean dontCollapseCaret, final boolean moveCaret) { assertIsDispatchThreadForEditor(); boolean oldDontCollapseCaret = myDoNotCollapseCaret; myDoNotCollapseCaret |= dontCollapseCaret; boolean oldBatchFlag = myIsBatchFoldingProcessing; if (!oldBatchFlag) { ((ScrollingModelImpl) myEditor.getScrollingModel()).finishAnimation(); mySavedCaretShift = myEditor.visibleLineToY(myEditor.getCaretModel().getVisualPosition().line) - myEditor.getScrollingModel().getVerticalScrollOffset(); } myIsBatchFoldingProcessing = true; try { operation.run(); } finally { if (!oldBatchFlag) { if (myFoldRegionsProcessed) { notifyBatchFoldingProcessingDone(moveCaret); myFoldRegionsProcessed = false; } myIsBatchFoldingProcessing = false; } myDoNotCollapseCaret = oldDontCollapseCaret; } }
public void recalculate() { myApplianceManager.reset(); myStorage.removeAll(); myDeferredFoldRegions.clear(); myEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER); myApplianceManager.recalculateIfNecessary(); }
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; }
/** * Called on editor settings change. Current model is expected to drop all cached information * about the settings if any. */ public void reinitSettings() { boolean softWrapsUsedBefore = myUseSoftWraps; myUseSoftWraps = areSoftWrapsEnabledInEditor(); int tabWidthBefore = myTabWidth; myTabWidth = EditorUtil.getTabSize(myEditor); boolean fontsChanged = false; if (!myFontPreferences.equals(myEditor.getColorsScheme().getFontPreferences()) && myEditorTextRepresentationHelper instanceof DefaultEditorTextRepresentationHelper) { fontsChanged = true; myEditor.getColorsScheme().getFontPreferences().copyTo(myFontPreferences); ((DefaultEditorTextRepresentationHelper) myEditorTextRepresentationHelper) .clearSymbolWidthCache(); myPainter.reinit(); } if ((myUseSoftWraps ^ softWrapsUsedBefore) || (tabWidthBefore >= 0 && myTabWidth != tabWidthBefore) || fontsChanged) { myApplianceManager.reset(); myDeferredFoldRegions.clear(); myStorage.removeAll(); myEditor.getScrollingModel().scrollToCaret(ScrollType.CENTER); } }
@Override public boolean isSoftWrappingEnabled() { if (!myUseSoftWraps || (!myEditor.myUseNewRendering && myEditor.isOneLineMode()) || myEditor.isPurePaintingMode()) { return false; } // We check that current thread is EDT because attempt to retrieve information about visible // area width may fail otherwise Application application = ApplicationManager.getApplication(); Thread lastEdt = myLastEdt.get(); Thread currentThread = Thread.currentThread(); if (lastEdt != currentThread) { if (application.isDispatchThread()) { myLastEdt = new SoftReference<Thread>(currentThread); } else { myLastEdt = new SoftReference<Thread>(null); return false; } } Rectangle visibleArea = myEditor.getScrollingModel().getVisibleArea(); return visibleArea.width > 0 && visibleArea.height > 0; }
public void doClick(final MouseEvent e, final int width) { RangeHighlighter marker = getNearestRangeHighlighter(e, width); if (marker == null) return; int offset = marker.getStartOffset(); final Document doc = myEditor.getDocument(); if (doc.getLineCount() > 0) { // Necessary to expand folded block even if navigating just before one // Very useful when navigating to first unused import statement. int lineEnd = doc.getLineEndOffset(doc.getLineNumber(offset)); myEditor.getCaretModel().moveToOffset(lineEnd); } myEditor.getCaretModel().moveToOffset(offset); myEditor.getSelectionModel().removeSelection(); ScrollingModel scrollingModel = myEditor.getScrollingModel(); scrollingModel.disableAnimation(); scrollingModel.scrollToCaret(ScrollType.CENTER); scrollingModel.enableAnimation(); fireErrorMarkerClicked(marker, e); }
private void requestRepaint(VerticalInfo oldCaretInfo) { int lineHeight = myEditor.getLineHeight(); Rectangle visibleArea = myEditor.getScrollingModel().getVisibleArea(); final EditorGutterComponentEx gutter = myEditor.getGutterComponentEx(); final EditorComponentImpl content = myEditor.getContentComponent(); int updateWidth = myEditor.getScrollPane().getHorizontalScrollBar().getValue() + visibleArea.width; if (Math.abs(myCaretInfo.y - oldCaretInfo.y) <= 2 * lineHeight) { int minY = Math.min(oldCaretInfo.y, myCaretInfo.y); int maxY = Math.max(oldCaretInfo.y + oldCaretInfo.height, myCaretInfo.y + myCaretInfo.height); content.repaintEditorComponent(0, minY, updateWidth, maxY - minY); gutter.repaint(0, minY, gutter.getWidth(), maxY - minY); } else { content.repaintEditorComponent( 0, oldCaretInfo.y, updateWidth, oldCaretInfo.height + lineHeight); gutter.repaint(0, oldCaretInfo.y, updateWidth, oldCaretInfo.height + lineHeight); content.repaintEditorComponent( 0, myCaretInfo.y, updateWidth, myCaretInfo.height + lineHeight); gutter.repaint(0, myCaretInfo.y, updateWidth, myCaretInfo.height + lineHeight); } }
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(); } }
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(); } }
public void moveCaretRelatively( int columnShift, int lineShift, boolean withSelection, boolean blockSelection, boolean scrollToCaret) { assertIsDispatchThread(); SelectionModel selectionModel = myEditor.getSelectionModel(); int selectionStart = selectionModel.getLeadSelectionOffset(); LogicalPosition blockSelectionStart = selectionModel.hasBlockSelection() ? selectionModel.getBlockStart() : getLogicalPosition(); EditorSettings editorSettings = myEditor.getSettings(); VisualPosition visualCaret = getVisualPosition(); int desiredX = myDesiredX; if (columnShift == 0) { if (myDesiredX < 0) { desiredX = myEditor.visualPositionToXY(visualCaret).x; } } else { myDesiredX = desiredX = -1; } int newLineNumber = visualCaret.line + lineShift; int newColumnNumber = visualCaret.column + columnShift; if (desiredX >= 0 && !ApplicationManager.getApplication().isUnitTestMode()) { newColumnNumber = myEditor.xyToVisualPosition( new Point(desiredX, Math.max(0, newLineNumber) * myEditor.getLineHeight())) .column; } Document document = myEditor.getDocument(); if (!editorSettings.isVirtualSpace() && columnShift == 0 && getLogicalPosition().softWrapLinesOnCurrentLogicalLine <= 0) { newColumnNumber = myEditor.getLastColumnNumber(); } else if (!editorSettings.isVirtualSpace() && lineShift == 0 && columnShift == 1) { int lastLine = document.getLineCount() - 1; if (lastLine < 0) lastLine = 0; if (EditorModificationUtil.calcAfterLineEnd(myEditor) >= 0 && newLineNumber < myEditor.logicalToVisualPosition(new LogicalPosition(lastLine, 0)).line) { newColumnNumber = 0; newLineNumber++; } } else if (!editorSettings.isVirtualSpace() && lineShift == 0 && columnShift == -1) { if (newColumnNumber < 0 && newLineNumber > 0) { newLineNumber--; newColumnNumber = EditorUtil.getLastVisualLineColumnNumber(myEditor, newLineNumber); } } if (newColumnNumber < 0) newColumnNumber = 0; // There is a possible case that caret is located at the first line and user presses 'Shift+Up'. // We want to select all text // from the document start to the current caret position then. So, we have a dedicated flag for // tracking that. boolean selectToDocumentStart = false; if (newLineNumber < 0) { selectToDocumentStart = true; newLineNumber = 0; // We want to move caret to the first column if it's already located at the first line and // 'Up' is pressed. newColumnNumber = 0; desiredX = -1; } VisualPosition pos = new VisualPosition(newLineNumber, newColumnNumber); int lastColumnNumber = newColumnNumber; if (!editorSettings.isCaretInsideTabs() && !myEditor.getSoftWrapModel().isInsideSoftWrap(pos)) { LogicalPosition log = myEditor.visualToLogicalPosition(new VisualPosition(newLineNumber, newColumnNumber)); int offset = myEditor.logicalPositionToOffset(log); if (offset >= document.getTextLength()) { int lastOffsetColumn = myEditor.offsetToVisualPosition(document.getTextLength()).column; // We want to move caret to the last column if if it's located at the last line and 'Down' // is pressed. newColumnNumber = lastColumnNumber = Math.max(lastOffsetColumn, newColumnNumber); desiredX = -1; } CharSequence text = document.getCharsSequence(); if (offset >= 0 && offset < document.getTextLength()) { if (text.charAt(offset) == '\t' && (columnShift <= 0 || offset == myOffset)) { if (columnShift <= 0) { newColumnNumber = myEditor.offsetToVisualPosition(offset).column; } else { SoftWrap softWrap = myEditor.getSoftWrapModel().getSoftWrap(offset + 1); // There is a possible case that tabulation symbol is the last document symbol // represented on a visual line before // soft wrap. We can't just use column from 'offset + 1' because it would point on a // next visual line. if (softWrap == null) { newColumnNumber = myEditor.offsetToVisualPosition(offset + 1).column; } else { newColumnNumber = EditorUtil.getLastVisualLineColumnNumber(myEditor, newLineNumber); } } } } } pos = new VisualPosition(newLineNumber, newColumnNumber); if (columnShift != 0 && lineShift == 0 && myEditor.getSoftWrapModel().isInsideSoftWrap(pos)) { LogicalPosition logical = myEditor.visualToLogicalPosition(pos); int softWrapOffset = myEditor.logicalPositionToOffset(logical); if (columnShift >= 0) { moveToOffset(softWrapOffset); } else { int line = myEditor.offsetToVisualLine(softWrapOffset - 1); moveToVisualPosition( new VisualPosition(line, EditorUtil.getLastVisualLineColumnNumber(myEditor, line))); } } else { moveToVisualPosition(pos); if (!editorSettings.isVirtualSpace() && columnShift == 0) { myEditor.setLastColumnNumber(lastColumnNumber); } } if (withSelection) { if (blockSelection) { selectionModel.setBlockSelection(blockSelectionStart, getLogicalPosition()); } else { if (selectToDocumentStart) { selectionModel.setSelection(selectionStart, 0); } else if (pos.line >= myEditor.getVisibleLineCount()) { if (selectionStart < document.getTextLength()) { selectionModel.setSelection(selectionStart, document.getTextLength()); } } else { selectionModel.setSelection(selectionStart, getVisualPosition(), getOffset()); } } } else { selectionModel.removeSelection(); } if (scrollToCaret) { myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE); } if (desiredX >= 0) { myDesiredX = desiredX; } EditorActionUtil.selectNonexpandableFold(myEditor); }