boolean (@NotNull MouseEvent e) { if (myMouseSelectionState != MOUSE_SELECTION_STATE_NONE && System.currentTimeMillis() - myMouseSelectionChangeTimestamp > Registry.intValue( "editor.mouseSelectionStateResetTimeout")) { resetMouseSelectionState(e, null); } int x = e.getX(); int y = e.getY(); if (x < 0) x = 0; if (y < 0) y = 0; EditorMouseEventArea eventArea = getMouseEventArea(e); myMousePressArea = eventArea; if (eventArea == EditorMouseEventArea.FOLDING_OUTLINE_AREA) { FoldRegion range = myGutterComponent.findFoldingAnchorAt(x, y); if (range != null) { boolean expansion = !range.isExpanded(); UIEventLogger.EditorFoldingIconClicked.log(expansion, e.isAltDown()); int scrollShift = expansion ? 0 : visualLineToY(yToVisualLine(y)) - getScrollingModel().getVerticalScrollOffset(); getFoldingModel().runBatchFoldingOperation(() -> { range.setExpanded(expansion); if (e.isAltDown()) { for (FoldRegion region : myFoldingModel.getAllFoldRegions()) { if (region.getStartOffset() >= range.getStartOffset() && region.getEndOffset() <= range.getEndOffset()) { region.setExpanded(expansion); } } } }, true, false); if (!expansion) { int newY = visualLineToY(offsetToVisualLine(range.getStartOffset())); EditorUtil.runWithAnimationDisabled(EditorImpl.this, () -> myScrollingModel.scrollVertically(newY - scrollShift)); } myGutterComponent.updateSize(); validateMousePointer(e, null); e.consume(); return false; } } if (e.getSource() == myGutterComponent) { if (!tweakSelectionIfNecessary(e)) { myGutterComponent.mousePressed(e); } if (e.isConsumed()) return false; x = 0; } Caret selectionCaret = null; int oldSelectionStart = mySelectionModel.getLeadSelectionOffset(); int oldStart = mySelectionModel.getSelectionStart(); int oldEnd = mySelectionModel.getSelectionEnd(); LogicalPosition oldBlockStart = null; if (isColumnMode()) { @NotNull List<CaretState> caretsAndSelections = getCaretModel().getCaretsAndSelections(); CaretState originalCaret = caretsAndSelections.get(0); oldBlockStart = Objects.equals(originalCaret.getCaretPosition(), originalCaret.getSelectionEnd()) ? originalCaret.getSelectionStart() : originalCaret.getSelectionEnd(); } boolean toggleCaret = e.getSource() != myGutterComponent && isToggleCaretEvent(e); boolean lastPressCreatedCaret = myLastPressCreatedCaret; if (e.getClickCount() == 1) { myLastPressCreatedCaret = false; } myLastPressWasAtBlockInlay = eventArea == EditorMouseEventArea.EDITING_AREA && hasBlockInlay(e.getPoint()); // Don't move the caret when the mouse is pressed in the gutter line markers area // (a place where breakpoints, 'override'/'implements' and other icons are drawn) or in the "annotations" area. // // For example, we don't want to change the caret position // when the user sets a new breakpoint by clicking at the 'line markers' area. // Also, don't move the caret when the context menu for an inlay is invoked. boolean moveCaret = (eventArea == EditorMouseEventArea.LINE_NUMBERS_AREA) || isInsideGutterWhitespaceArea(e) || eventArea == EditorMouseEventArea.EDITING_AREA && !myLastPressWasAtBlockInlay; if (moveCaret) { // We don't know which caret we want to work with yet VisualPosition visualPosition = getTargetPosition(x, y, true, null); LogicalPosition pos = visualToLogicalPosition(visualPosition); if (toggleCaret) { Caret caret = getCaretModel().getCaretAt(visualPosition); if (e.getClickCount() == 1) { if (caret == null) { myLastPressCreatedCaret = !EditorUtil.checkMaxCarets(EditorImpl.this) && getCaretModel().addCaret(visualPosition) != null; } else { getCaretModel().removeCaret(caret); } } else if (e.getClickCount() == 3 && lastPressCreatedCaret) { getCaretModel().moveToVisualPosition(visualPosition); } } else if (e.getSource() != myGutterComponent && isCreateRectangularSelectionEvent(e)) { CaretState anchorCaretState = myCaretModel.getCaretsAndSelections().get(0); LogicalPosition anchor = Objects.equals(anchorCaretState.getCaretPosition(), anchorCaretState.getSelectionStart()) ? anchorCaretState.getSelectionEnd() : anchorCaretState.getSelectionStart(); if (anchor == null) anchor = myCaretModel.getLogicalPosition(); mySelectionModel.setBlockSelection(anchor, pos); } else { selectionCaret = eventArea == EditorMouseEventArea.EDITING_AREA && SwingUtilities.isRightMouseButton(e) && getCaretModel().getCaretCount() > 1 ? getSelectionCaret(pos) : null; if (selectionCaret == null) { getCaretModel().removeSecondaryCarets(); getCaretModel().moveToVisualPosition(visualPosition); } else { selectionCaret.moveToVisualPosition(visualPosition); } } } if (e.isPopupTrigger()) return false; requestFocus(); int caretOffset = getCaretModel().getOffset(); int newStart = mySelectionModel.getSelectionStart(); int newEnd = mySelectionModel.getSelectionEnd(); Point p = new Point(x, y); myMouseSelectedRegion = myFoldingModel.getFoldingPlaceholderAt(p); myKeepSelectionOnMousePress = selectionCaret != null || mySelectionModel.hasSelection() && caretOffset >= mySelectionModel.getSelectionStart() && caretOffset <= mySelectionModel.getSelectionEnd() && !isPointAfterSelectionEnd(p) && (SwingUtilities.isLeftMouseButton(e) && mySettings.isDndEnabled() || SwingUtilities.isRightMouseButton(e)); boolean isNavigation = oldStart == oldEnd && newStart == newEnd && oldStart != newStart; if (getMouseEventArea(e) == EditorMouseEventArea.LINE_NUMBERS_AREA && e.getClickCount() == 1) { if (ExperimentalUI.isNewUI() && EditorUtil.isBreakPointsOnLineNumbers()) { //do nothing here and set/unset a breakpoint if possible in XLineBreakpointManager return false; } else { // Move the caret to the end of the selection, that is, the beginning of the next line. // This is more consistent with the caret placement on "Extend line selection" and on dragging through the line numbers area. selectLineAtCaret(true); } return isNavigation; } if (moveCaret) { if (e.isShiftDown() && !e.isControlDown() && !e.isAltDown() && !e.isMetaDown()) { if (oldBlockStart != null) { mySelectionModel.setBlockSelection(oldBlockStart, getCaretModel().getLogicalPosition()); } else { int startToUse; if (getMouseSelectionState() != MOUSE_SELECTION_STATE_NONE) { if (caretOffset < mySavedSelectionStart) { startToUse = mySavedSelectionEnd; } else { startToUse = mySavedSelectionStart; } } else { startToUse = oldSelectionStart; if (mySelectionModel.isUnknownDirection() && caretOffset > startToUse) { startToUse = Math.min(oldStart, oldEnd); } } mySelectionModel.setSelection(startToUse, caretOffset); } } else { if (!myKeepSelectionOnMousePress && getSelectionModel().hasSelection() && !isCreateRectangularSelectionEvent(e) && e.getClickCount() == 1) { if (!toggleCaret) { setMouseSelectionState(MOUSE_SELECTION_STATE_NONE); mySelectionModel.setSelection(caretOffset, caretOffset); } } else { if (e.getButton() == MouseEvent.BUTTON1 && (eventArea == EditorMouseEventArea.EDITING_AREA || eventArea == EditorMouseEventArea.LINE_NUMBERS_AREA) && (!toggleCaret || lastPressCreatedCaret) && !(myMouseSelectedRegion instanceof CustomFoldRegion)) { switch (e.getClickCount()) { case 2: selectWordAtCaret(mySettings.isMouseClickSelectionHonorsCamelWords() && mySettings.isCamelWords()); break; case 3: if (eventArea == EditorMouseEventArea.EDITING_AREA && HONOR_CAMEL_HUMPS_ON_TRIPLE_CLICK && mySettings.isCamelWords()) { // We want to differentiate between triple and quadruple clicks when 'select by camel humps' is on. The former // is assumed to select 'hump' while the latter points to the whole word. selectWordAtCaret(false); break; } //noinspection fallthrough case 4: // Triple and quadruple clicks on the line number reset the selection to a single line, // except that in this case we keep the caret at the beginning of this line, not the next line. selectLineAtCaret(false); mySelectionModel.setUnknownDirection(true); break; } } } } } return isNavigation; }