void (@NotNull MouseEvent e) { if (!SwingUtilities.isLeftMouseButton(e) && !SwingUtilities.isMiddleMouseButton(e) || (Registry.is("editor.disable.drag.with.right.button") && SwingUtilities.isRightMouseButton(e))) { return; } EditorMouseEventArea eventArea = getMouseEventArea(e); if (eventArea == EditorMouseEventArea.ANNOTATIONS_AREA) return; if (eventArea == EditorMouseEventArea.LINE_MARKERS_AREA || eventArea == EditorMouseEventArea.FOLDING_OUTLINE_AREA && !isInsideGutterWhitespaceArea(e)) { // The general idea is that we don't want to change caret position on gutter marker area click (e.g., on setting a breakpoint) // but do want to allow bulk selection on gutter marker mouse drag. However, when a drag is performed, the first event is // a 'mouse pressed' event, that's why we remember target line on 'mouse pressed' processing and use that information on // further dragging (if any). if (myDragOnGutterSelectionStartLine >= 0) { mySelectionModel.removeSelection(); myCaretModel.moveToOffset(myDragOnGutterSelectionStartLine < myDocument.getLineCount() ? myDocument.getLineStartOffset(myDragOnGutterSelectionStartLine) : myDocument.getTextLength()); } myDragOnGutterSelectionStartLine = -1; } if (eventArea == EditorMouseEventArea.LINE_NUMBERS_AREA && NewUI.isEnabled() && EditorUtil.isBreakPointsOnLineNumbers() && getMouseSelectionState() != MOUSE_SELECTION_STATE_LINE_SELECTED) { //IDEA-305975 selectLineAtCaret(true); getGutterComponentEx().putClientProperty("active.line.number", null); //clear hovered breakpoint } boolean columnSelectionDragEvent = isColumnSelectionDragEvent(e); boolean toggleCaretEvent = isToggleCaretEvent(e); boolean addRectangularSelectionEvent = isAddRectangularSelectionEvent(e); boolean columnSelectionDrag = isColumnMode() && !myLastPressCreatedCaret || columnSelectionDragEvent; if (!columnSelectionDragEvent && toggleCaretEvent && !myLastPressCreatedCaret) { return; // ignoring drag after removing a caret } if (myLastPressWasAtBlockInlay) { return; // ignoring drag originating over block inlay } Rectangle visibleArea = getScrollingModel().getVisibleArea(); int x = e.getX(); if (e.getSource() == myGutterComponent) { x = 0; } int dx = 0; if (x < visibleArea.x && visibleArea.x > 0) { dx = x - visibleArea.x; } else { if (x > visibleArea.x + visibleArea.width) { dx = x - visibleArea.x - visibleArea.width; } } int dy = 0; int y = e.getY(); if (y < visibleArea.y && visibleArea.y > 0) { dy = y - visibleArea.y; } else { if (y > visibleArea.y + visibleArea.height && visibleArea.y + visibleArea.height < myEditorComponent.getHeight()) { dy = y - visibleArea.y - visibleArea.height; } } if (dx == 0 && dy == 0) { myScrollingTimer.stop(); SelectionModel selectionModel = getSelectionModel(); Caret leadCaret = getLeadCaret(); int oldSelectionStart = leadCaret.getLeadSelectionOffset(); VisualPosition oldVisLeadSelectionStart = leadCaret.getLeadSelectionPosition(); int oldCaretOffset = getCaretModel().getOffset(); boolean multiCaretSelection = columnSelectionDrag || toggleCaretEvent; VisualPosition newVisualCaret = getTargetPosition(x, y, !multiCaretSelection, leadCaret); LogicalPosition newLogicalCaret = visualToLogicalPosition(newVisualCaret); if (multiCaretSelection) { myMultiSelectionInProgress = true; myRectangularSelectionInProgress = columnSelectionDrag || addRectangularSelectionEvent; myTargetMultiSelectionPosition = xyToVisualPosition(new Point(Math.max(x, 0), Math.max(y, 0))); } else { getCaretModel().moveToVisualPosition(newVisualCaret); } int newCaretOffset = getCaretModel().getOffset(); newVisualCaret = getCaretModel().getVisualPosition(); int caretShift = newCaretOffset - mySavedSelectionStart; if (myMousePressedEvent != null && getMouseEventArea(myMousePressedEvent) != EditorMouseEventArea.EDITING_AREA && getMouseEventArea(myMousePressedEvent) != EditorMouseEventArea.LINE_NUMBERS_AREA) { selectionModel.setSelection(oldSelectionStart, newCaretOffset); } else { if (multiCaretSelection) { if (myLastMousePressedLocation != null && (myCurrentDragIsSubstantial || !newLogicalCaret.equals(myLastMousePressedLocation))) { createSelectionTill(newLogicalCaret); blockActionsIfNeeded(e, myLastMousePressedLocation, newLogicalCaret); } } else { if (getMouseSelectionState() != MOUSE_SELECTION_STATE_NONE) { setupSpecialSelectionOnMouseDrag(newCaretOffset, caretShift); cancelAutoResetForMouseSelectionState(); return; } if (!myKeepSelectionOnMousePress) { // There is a possible case that lead selection position should be adjusted in accordance with the mouse move direction. // E.g., consider a situation when a user selects the whole line by clicking at 'line numbers' area. // 'Line end' is considered to be lead selection point then. // However, when the mouse is dragged down, we want to consider 'line start' to be lead selection point. if ((myMousePressArea == EditorMouseEventArea.LINE_NUMBERS_AREA || myMousePressArea == EditorMouseEventArea.LINE_MARKERS_AREA) && selectionModel.hasSelection()) { if (newCaretOffset >= selectionModel.getSelectionEnd()) { oldSelectionStart = selectionModel.getSelectionStart(); oldVisLeadSelectionStart = selectionModel.getSelectionStartPosition(); } else if (newCaretOffset <= selectionModel.getSelectionStart()) { oldSelectionStart = selectionModel.getSelectionEnd(); oldVisLeadSelectionStart = selectionModel.getSelectionEndPosition(); } } else if (EditorUtil.isBlockLikeCaret(getCaretModel().getPrimaryCaret()) && Registry.is("editor.block.caret.selection.vim-like")) { // adjust selection range, so that it covers caret location if (mySelectionModel.hasSelection() && oldVisLeadSelectionStart.equals(mySelectionModel.getSelectionEndPosition())) { oldVisLeadSelectionStart = prevSelectionVisualPosition(oldVisLeadSelectionStart); } if (newVisualCaret.after(oldVisLeadSelectionStart)) { newVisualCaret = nextSelectionVisualPosition(newVisualCaret); newCaretOffset = visualPositionToOffset(newVisualCaret); } else if (oldVisLeadSelectionStart.after(newVisualCaret) || oldVisLeadSelectionStart.equals(newVisualCaret) && mySelectionModel.hasSelection()) { oldVisLeadSelectionStart = nextSelectionVisualPosition(oldVisLeadSelectionStart); } oldSelectionStart = visualPositionToOffset(oldVisLeadSelectionStart); } setSelectionAndBlockActions(e, oldVisLeadSelectionStart, oldSelectionStart, newVisualCaret, newCaretOffset); cancelAutoResetForMouseSelectionState(); } else { if (caretShift != 0) { if (myMousePressedEvent != null && myGutterComponent.getGutterRenderer(e.getPoint()) == null) { if (mySettings.isDndEnabled()) { if (!myDragStarted) { if (ApplicationManager.getApplication().isUnitTestMode()) { // It can lead to process hanging, and breaking drag-n-drop in other applications throw new UnsupportedOperationException("Drag'n'drop operation shouldn't be started in tests"); } myDragStarted = true; boolean isCopy = UIUtil.isControlKeyDown(e) || isViewer() || !getDocument().isWritable(); mySavedCaretOffsetForDNDUndoHack = oldCaretOffset; getContentComponent().getTransferHandler().exportAsDrag(getContentComponent(), e, isCopy ? TransferHandler.COPY : TransferHandler.MOVE); } } else { selectionModel.removeSelection(); } } } } } } } else { myScrollingTimer.start(dx, dy); onSubstantialDrag(e); } }