void (@NotNull MouseEvent e) { if (JBSwingUtilities.isRightMouseButton(e)) { return; } if (getMouseEventArea(e) == EditorMouseEventArea.LINE_MARKERS_AREA) { // 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; } 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 } 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) { 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; LogicalPosition newLogicalCaret = getLogicalPositionForScreenPos(x, y, !multiCaretSelection); if (multiCaretSelection) { myMultiSelectionInProgress = true; myRectangularSelectionInProgress = columnSelectionDrag || addRectangularSelectionEvent; myTargetMultiSelectionPosition = xyToVisualPosition(new Point(Math.max(x, 0), Math.max(y, 0))); } else { getCaretModel().moveToLogicalPosition(newLogicalCaret); } int newCaretOffset = getCaretModel().getOffset(); VisualPosition 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) { if (caretShift < 0) { int newSelection = newCaretOffset; if (getMouseSelectionState() == MOUSE_SELECTION_STATE_WORD_SELECTED) { newSelection = myCaretModel.getWordAtCaretStart(); } else { if (getMouseSelectionState() == MOUSE_SELECTION_STATE_LINE_SELECTED) { newSelection = logicalPositionToOffset(visualToLogicalPosition(new VisualPosition(getCaretModel().getVisualPosition().line, 0))); } } if (newSelection < 0) newSelection = newCaretOffset; selectionModel.setSelection(mySavedSelectionEnd, newSelection); getCaretModel().moveToOffset(newSelection); } else { int newSelection = newCaretOffset; if (getMouseSelectionState() == MOUSE_SELECTION_STATE_WORD_SELECTED) { newSelection = myCaretModel.getWordAtCaretEnd(); } else { if (getMouseSelectionState() == MOUSE_SELECTION_STATE_LINE_SELECTED) { newSelection = logicalPositionToOffset(visualToLogicalPosition(new VisualPosition(getCaretModel().getVisualPosition().line + 1, 0))); } } if (newSelection < 0) newSelection = newCaretOffset; selectionModel.setSelection(mySavedSelectionStart, newSelection); getCaretModel().moveToOffset(newSelection); } cancelAutoResetForMouseSelectionState(); return; } if (!myMousePressedInsideSelection) { // There is a possible case that lead selection position should be adjusted in accordance with the mouse move direction. // E.g. consider situation when user selects the whole line by clicking at 'line numbers' area. 'Line end' is considered // to be lead selection point then. However, when 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(); } } if (oldVisLeadSelectionStart != null) { setSelectionAndBlockActions(e, oldVisLeadSelectionStart, oldSelectionStart, newVisualCaret, newCaretOffset); } else { setSelectionAndBlockActions(e, oldSelectionStart, newCaretOffset); } cancelAutoResetForMouseSelectionState(); } else { if (caretShift != 0) { if (myMousePressedEvent != null) { if (mySettings.isDndEnabled()) { if (myDraggedRange == null) { 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); } }