From e58ef02791bf36f28af883fa1f52a614212c35b8 Mon Sep 17 00:00:00 2001 From: Dmitry Batrak Date: Tue, 25 Feb 2014 13:49:39 +0400 Subject: [PATCH] Make EditorToggleColumnMode action work with multiple carets like previously with block selection (IDEA-80056) --- .../intellij/openapi/editor/CaretModel.java | 3 +- .../injected/editor/CaretModelWindow.java | 6 +- .../actions/ToggleColumnModeAction.java | 50 ++++++-- .../openapi/editor/impl/CaretModelImpl.java | 2 +- .../textarea/TextComponentCaretModel.java | 5 +- .../ToggleColumnModeActionMultiCaretTest.java | 112 ++++++++++++++++++ 6 files changed, 156 insertions(+), 22 deletions(-) create mode 100644 platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/ToggleColumnModeActionMultiCaretTest.java diff --git a/platform/editor-ui-api/src/com/intellij/openapi/editor/CaretModel.java b/platform/editor-ui-api/src/com/intellij/openapi/editor/CaretModel.java index f92b5741ae5d..17ddb3f820b3 100644 --- a/platform/editor-ui-api/src/com/intellij/openapi/editor/CaretModel.java +++ b/platform/editor-ui-api/src/com/intellij/openapi/editor/CaretModel.java @@ -21,7 +21,6 @@ import com.intellij.openapi.util.Segment; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collection; import java.util.List; /** @@ -186,7 +185,7 @@ public interface CaretModel { * Returns all carets currently existing in the document, ordered by their position in the document. */ @NotNull - Collection getAllCarets(); + List getAllCarets(); /** * Returns a caret at the given position in the document, or null, if there's no caret there. diff --git a/platform/lang-impl/src/com/intellij/injected/editor/CaretModelWindow.java b/platform/lang-impl/src/com/intellij/injected/editor/CaretModelWindow.java index 225bb0fd374c..cee529aecccf 100644 --- a/platform/lang-impl/src/com/intellij/injected/editor/CaretModelWindow.java +++ b/platform/lang-impl/src/com/intellij/injected/editor/CaretModelWindow.java @@ -165,9 +165,9 @@ public class CaretModelWindow implements CaretModel { @NotNull @Override - public Collection getAllCarets() { - Collection hostCarets = myDelegate.getAllCarets(); - Collection carets = new ArrayList(hostCarets.size()); + public List getAllCarets() { + List hostCarets = myDelegate.getAllCarets(); + List carets = new ArrayList(hostCarets.size()); for (Caret hostCaret : hostCarets) { carets.add(createInjectedCaret(hostCaret)); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/actions/ToggleColumnModeAction.java b/platform/platform-impl/src/com/intellij/openapi/editor/actions/ToggleColumnModeAction.java index 64659ce3a5a0..e17dfd7c7a40 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/actions/ToggleColumnModeAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/actions/ToggleColumnModeAction.java @@ -27,50 +27,74 @@ package com.intellij.openapi.editor.actions; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.ToggleAction; +import com.intellij.openapi.editor.Caret; import com.intellij.openapi.editor.CaretModel; import com.intellij.openapi.editor.LogicalPosition; import com.intellij.openapi.editor.SelectionModel; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.project.DumbAware; +import java.util.List; + public class ToggleColumnModeAction extends ToggleAction implements DumbAware { @Override public void setSelected(AnActionEvent e, boolean state) { final EditorEx editor = getEditor(e); - if (editor.getCaretModel().supportsMultipleCarets()) { - editor.setColumnMode(state); - return; - } final SelectionModel selectionModel = editor.getSelectionModel(); + final CaretModel caretModel = editor.getCaretModel(); if (state) { - boolean hasSelection = selectionModel.hasSelection(); + boolean hasSelection = caretModel.getAllCarets().size() == 1 && selectionModel.hasSelection(); int selStart = selectionModel.getSelectionStart(); int selEnd = selectionModel.getSelectionEnd(); - final CaretModel caretModel = editor.getCaretModel(); - LogicalPosition blockStart = selStart == caretModel.getOffset() + LogicalPosition blockStart, blockEnd; + if (caretModel.supportsMultipleCarets()) { + LogicalPosition logicalSelStart = editor.offsetToLogicalPosition(selStart); + LogicalPosition logicalSelEnd = editor.offsetToLogicalPosition(selEnd); + int caretOffset = caretModel.getOffset(); + blockStart = selStart == caretOffset ? logicalSelEnd : logicalSelStart; + blockEnd = selStart == caretOffset ? logicalSelStart : logicalSelEnd; + } + else { + blockStart = selStart == caretModel.getOffset() + ? caretModel.getLogicalPosition() + : editor.offsetToLogicalPosition(selStart); + blockEnd = selEnd == caretModel.getOffset() ? caretModel.getLogicalPosition() - : editor.offsetToLogicalPosition(selStart); - LogicalPosition blockEnd = selEnd == caretModel.getOffset() - ? caretModel.getLogicalPosition() - : editor.offsetToLogicalPosition(selEnd); + : editor.offsetToLogicalPosition(selEnd); + } editor.setColumnMode(true); if (hasSelection) { selectionModel.setBlockSelection(blockStart, blockEnd); } - else { + else if (!caretModel.supportsMultipleCarets()) { selectionModel.removeSelection(); } } else { - final boolean hasSelection = selectionModel.hasBlockSelection(); + boolean hasSelection = selectionModel.hasBlockSelection(); final LogicalPosition blockStart = selectionModel.getBlockStart(); final LogicalPosition blockEnd = selectionModel.getBlockEnd(); int selStart = hasSelection && blockStart != null ? editor.logicalPositionToOffset(blockStart) : 0; int selEnd = hasSelection && blockEnd != null ? editor.logicalPositionToOffset(blockEnd) : 0; + if (caretModel.supportsMultipleCarets()) { + hasSelection = true; + List allCarets = caretModel.getAllCarets(); + Caret fromCaret = allCarets.get(0); + Caret toCaret = allCarets.get(allCarets.size() - 1); + if (fromCaret == caretModel.getPrimaryCaret()) { + Caret tmp = fromCaret; + fromCaret = toCaret; + toCaret = tmp; + } + selStart = fromCaret.getLeadSelectionOffset(); + selEnd = toCaret.getSelectionStart() == toCaret.getLeadSelectionOffset() ? toCaret.getSelectionEnd() : toCaret.getSelectionStart(); + } + editor.setColumnMode(false); + caretModel.removeSecondaryCarets(); if (hasSelection) { selectionModel.setSelection(selStart, selEnd); } diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretModelImpl.java b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretModelImpl.java index 69678c7cfba9..aeafd225adaa 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretModelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/impl/CaretModelImpl.java @@ -271,7 +271,7 @@ public class CaretModelImpl implements CaretModel, PrioritizedDocumentListener, @Override @NotNull - public Collection getAllCarets() { + public List getAllCarets() { List carets; synchronized (myCarets) { carets = new ArrayList(myCarets); diff --git a/platform/platform-impl/src/com/intellij/openapi/editor/textarea/TextComponentCaretModel.java b/platform/platform-impl/src/com/intellij/openapi/editor/textarea/TextComponentCaretModel.java index 6e4ea35a7f1f..607e182dd3cb 100644 --- a/platform/platform-impl/src/com/intellij/openapi/editor/textarea/TextComponentCaretModel.java +++ b/platform/platform-impl/src/com/intellij/openapi/editor/textarea/TextComponentCaretModel.java @@ -25,7 +25,6 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.text.BadLocationException; import javax.swing.text.JTextComponent; -import java.util.Collection; import java.util.Collections; import java.util.List; @@ -154,8 +153,8 @@ public class TextComponentCaretModel implements CaretModel { @NotNull @Override - public Collection getAllCarets() { - return Collections.singleton(myCaret); + public List getAllCarets() { + return Collections.singletonList(myCaret); } @Nullable diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/ToggleColumnModeActionMultiCaretTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/ToggleColumnModeActionMultiCaretTest.java new file mode 100644 index 000000000000..43366d555f14 --- /dev/null +++ b/platform/platform-tests/testSrc/com/intellij/openapi/editor/actions/ToggleColumnModeActionMultiCaretTest.java @@ -0,0 +1,112 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.openapi.editor.actions; + +import com.intellij.openapi.fileTypes.FileTypes; +import com.intellij.testFramework.EditorTestUtil; +import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; + +public class ToggleColumnModeActionMultiCaretTest extends LightPlatformCodeInsightFixtureTestCase { + public void setUp() throws Exception { + super.setUp(); + EditorTestUtil.enableMultipleCarets(); + } + + public void tearDown() throws Exception { + EditorTestUtil.disableMultipleCarets(); + super.tearDown(); + } + + public void testSingleCaretWithoutSelection() throws Exception { + doTestToggleOnOff("line1\n" + + "line2", + + "line1\n" + + "line2", + + "line1\n" + + "line2" + ); + } + + public void testSingleCaretWithForwardSelection() throws Exception { + doTestToggleOnOff("line1\n" + + "line2", + + "line1\n" + + "line2", + + "line1\n" + + "line2" + ); + } + + public void testSingleCaretWithBackwardSelection() throws Exception { + doTestToggleOnOff("line1\n" + + "line2", + + "line1\n" + + "line2", + + "line1\n" + + "line2" + ); + } + + public void testSingleCaretWithCrossSelection() throws Exception { + doTestToggleOnOff("line1\n" + + "line2", + + "line1\n" + + "line2", + + "line1\n" + + "line2" + ); + } + + public void testSingleCaretWithCrossSelection2() throws Exception { + doTestToggleOnOff("line1\n" + + "line2", + + "line1\n" + + "line2", + + "line1\n" + + "line2" + ); + } + + public void testMultipleCarets() throws Exception { + doTestToggleOnOff("line1\n" + + "line2", + + "line1\n" + + "line2", + + "line1\n" + + "line2" + ); + } + + private void doTestToggleOnOff(String initialState, String afterToggleOn, String afterToggleOff) { + myFixture.configureByText(FileTypes.PLAIN_TEXT, initialState); + myFixture.performEditorAction("EditorToggleColumnMode"); + myFixture.checkResult(afterToggleOn); + myFixture.performEditorAction("EditorToggleColumnMode"); + myFixture.checkResult(afterToggleOff); + } +}