2 * Copyright 2000-2007 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.openapi
.editor
;
18 import com
.intellij
.codeStyle
.CodeStyleFacade
;
19 import com
.intellij
.openapi
.editor
.actionSystem
.EditorActionManager
;
20 import com
.intellij
.openapi
.editor
.event
.DocumentEvent
;
21 import com
.intellij
.openapi
.editor
.event
.MockDocumentEvent
;
22 import com
.intellij
.openapi
.ide
.CopyPasteManager
;
23 import com
.intellij
.openapi
.project
.Project
;
24 import com
.intellij
.openapi
.util
.TextRange
;
25 import com
.intellij
.openapi
.util
.text
.LineTokenizer
;
26 import com
.intellij
.openapi
.util
.text
.StringUtil
;
27 import org
.jetbrains
.annotations
.Nullable
;
29 import java
.awt
.datatransfer
.Clipboard
;
30 import java
.awt
.datatransfer
.DataFlavor
;
31 import java
.awt
.datatransfer
.Transferable
;
32 import java
.awt
.datatransfer
.UnsupportedFlavorException
;
33 import java
.io
.IOException
;
35 public class EditorModificationUtil
{
36 private EditorModificationUtil() {}
38 public static void deleteSelectedText(Editor editor
) {
39 SelectionModel selectionModel
= editor
.getSelectionModel();
40 if (selectionModel
.hasBlockSelection()) deleteBlockSelection(editor
);
41 if(!selectionModel
.hasSelection()) return;
43 int selectionStart
= selectionModel
.getSelectionStart();
44 int selectionEnd
= selectionModel
.getSelectionEnd();
46 editor
.getCaretModel().moveToOffset(selectionStart
);
47 selectionModel
.removeSelection();
48 editor
.getDocument().deleteString(selectionStart
, selectionEnd
);
49 editor
.getScrollingModel().scrollToCaret(ScrollType
.RELATIVE
);
52 public static void deleteBlockSelection(Editor editor
) {
53 SelectionModel selectionModel
= editor
.getSelectionModel();
54 if (!selectionModel
.hasBlockSelection()) return;
56 int startLine
= selectionModel
.getBlockStart().line
;
57 int endLine
= selectionModel
.getBlockEnd().line
;
59 int[] starts
= selectionModel
.getBlockSelectionStarts();
60 int[] ends
= selectionModel
.getBlockSelectionEnds();
62 for (int i
= starts
.length
- 1; i
>= 0; i
--) {
63 editor
.getDocument().deleteString(starts
[i
], ends
[i
]);
66 editor
.getScrollingModel().scrollToCaret(ScrollType
.RELATIVE
);
68 zeroWidthBlockSelectionAtCaretColumn(editor
, startLine
, endLine
);
71 private static void zeroWidthBlockSelectionAtCaretColumn(final Editor editor
, final int startLine
, final int endLine
) {
72 int caretColumn
= editor
.getCaretModel().getLogicalPosition().column
;
73 editor
.getSelectionModel().setBlockSelection(new LogicalPosition(startLine
, caretColumn
), new LogicalPosition(endLine
, caretColumn
));
76 public static void insertStringAtCaret(Editor editor
, String s
) {
77 insertStringAtCaret(editor
, s
, false, true);
80 public static int insertStringAtCaret(Editor editor
, String s
, boolean toProcessOverwriteMode
, boolean toMoveCaret
) {
81 final SelectionModel selectionModel
= editor
.getSelectionModel();
82 if (selectionModel
.hasSelection()) {
83 editor
.getCaretModel().moveToOffset(selectionModel
.getSelectionStart());
86 int oldOffset
= editor
.getCaretModel().getOffset();
88 String filler
= calcStringToFillVitualSpace(editor
);
89 if (filler
.length() > 0) {
93 if (editor
.isInsertMode() || !toProcessOverwriteMode
) {
94 if (selectionModel
.hasSelection()) {
95 editor
.getDocument().replaceString(selectionModel
.getSelectionStart(), selectionModel
.getSelectionEnd(), s
);
97 editor
.getDocument().insertString(oldOffset
, s
);
100 deleteSelectedText(editor
);
101 Document document
= editor
.getDocument();
102 int lineNumber
= editor
.getCaretModel().getLogicalPosition().line
;
103 if (lineNumber
>= document
.getLineCount()){
104 return insertStringAtCaret(editor
, s
, false, toMoveCaret
);
107 int endOffset
= document
.getLineEndOffset(lineNumber
);
108 document
.replaceString(oldOffset
, Math
.min(endOffset
, oldOffset
+ s
.length()), s
);
111 int offset
= oldOffset
+ s
.length();
113 editor
.getCaretModel().moveToOffset(offset
);
114 editor
.getScrollingModel().scrollToCaret(ScrollType
.RELATIVE
);
115 selectionModel
.removeSelection();
122 public static TextRange
pasteFromClipboard(Editor editor
) {
123 return pasteFromTransferrable(getClipboardContent(editor
), editor
);
127 public static TextRange
pasteFromTransferrable(Transferable content
, Editor editor
) {
128 if (content
!= null) {
130 String s
= getStringContent(content
);
132 int caretOffset
= editor
.getCaretModel().getOffset();
133 insertStringAtCaret(editor
, s
, false, true);
134 return new TextRange(caretOffset
, caretOffset
+ s
.length());
135 } catch (Exception exception
) {
136 editor
.getComponent().getToolkit().beep();
143 private static String
getStringContent(final Transferable content
) throws UnsupportedFlavorException
, IOException
{
146 raw
= (RawText
)content
.getTransferData(RawText
.FLAVOR
);
148 catch (UnsupportedFlavorException e
) {
149 // OK. raw will be null and we'll get plain string
151 catch (IOException e
) {
152 // OK. raw will be null and we'll get plain string
160 s
= (String
)content
.getTransferData(DataFlavor
.stringFlavor
);
163 s
= StringUtil
.convertLineSeparators(s
);
167 private static Transferable
getClipboardContent(Editor editor
) {
168 Transferable content
;
169 Project project
= editor
.getProject();
171 if (project
!= null) {
172 content
= CopyPasteManager
.getInstance().getContents();
174 Clipboard clipboard
= editor
.getComponent().getToolkit().getSystemClipboard();
175 content
= clipboard
.getContents(editor
.getComponent());
180 public static void pasteFromClipboardAsBlock(Editor editor
) {
181 Transferable content
= getClipboardContent(editor
);
183 if (content
!= null) {
185 int caretLine
= editor
.getCaretModel().getLogicalPosition().line
;
186 int originalCaretLine
= caretLine
;
188 int selectedLinesCount
= 0;
189 final SelectionModel selectionModel
= editor
.getSelectionModel();
190 if (selectionModel
.hasBlockSelection()) {
191 final LogicalPosition start
= selectionModel
.getBlockStart();
192 final LogicalPosition end
= selectionModel
.getBlockEnd();
193 assert start
!= null;
195 LogicalPosition caret
= new LogicalPosition(Math
.min(start
.line
, end
.line
), Math
.min(start
.column
, end
.column
));
196 selectedLinesCount
= Math
.abs(end
.line
- start
.line
);
197 caretLine
= caret
.line
;
199 deleteSelectedText(editor
);
200 editor
.getCaretModel().moveToLogicalPosition(caret
);
203 LogicalPosition caretToRestore
= editor
.getCaretModel().getLogicalPosition();
204 String s
= getStringContent(content
);
206 String
[] lines
= LineTokenizer
.tokenize(s
.toCharArray(), false);
207 if (lines
.length
> 1 || selectedLinesCount
<= 1) {
208 int longestLineLength
= 0;
209 for (String line
: lines
) {
210 longestLineLength
= Math
.max(longestLineLength
, line
.length());
211 insertStringAtCaret(editor
, line
, false, true);
212 editor
.getCaretModel().moveCaretRelatively(-line
.length(), 1, false, false, true);
214 caretToRestore
= new LogicalPosition(originalCaretLine
, caretToRestore
.column
+ longestLineLength
);
217 for (int i
= 0; i
<= selectedLinesCount
; i
++) {
218 insertStringAtCaret(editor
, s
, false, true);
219 editor
.getCaretModel().moveCaretRelatively(-s
.length(), 1, false, false, true);
221 caretToRestore
= new LogicalPosition(originalCaretLine
, caretToRestore
.column
+ s
.length());
223 editor
.getCaretModel().moveToLogicalPosition(caretToRestore
);
224 zeroWidthBlockSelectionAtCaretColumn(editor
, caretLine
, caretLine
+ selectedLinesCount
);
225 } catch (Exception exception
) {
226 editor
.getComponent().getToolkit().beep();
231 public static int calcAfterLineEnd(Editor editor
) {
232 Document document
= editor
.getDocument();
233 LogicalPosition logicalPosition
= editor
.getCaretModel().getLogicalPosition();
234 int columnNumber
= logicalPosition
.column
;
235 int lineNumber
= logicalPosition
.line
;
236 if (lineNumber
>= document
.getLineCount()) {
239 int lineEndOffset
= document
.getLineEndOffset(lineNumber
);
240 int lineEndColumnNumber
= editor
.offsetToLogicalPosition(lineEndOffset
).column
;
241 return columnNumber
- lineEndColumnNumber
;
244 public static String
calcStringToFillVitualSpace(Editor editor
) {
245 int afterLineEnd
= calcAfterLineEnd(editor
);
246 if (afterLineEnd
> 0) {
247 final Project project
= editor
.getProject();
248 StringBuilder buf
= new StringBuilder();
249 final Document doc
= editor
.getDocument();
250 final int caretOffset
= editor
.getCaretModel().getOffset();
251 boolean atLineStart
= caretOffset
>= doc
.getTextLength() || doc
.getLineStartOffset(doc
.getLineNumber(caretOffset
)) == caretOffset
;
252 if (atLineStart
&& project
!= null) {
253 String properIndent
= CodeStyleFacade
.getInstance(project
).getLineIndent(editor
);
254 if (properIndent
!= null) {
255 int tabSize
= editor
.getSettings().getTabSize(project
);
256 for (int i
= 0; i
< properIndent
.length(); i
++) {
257 if (properIndent
.charAt(i
) == ' ') {
260 else if (properIndent
.charAt(i
) == '\t') {
261 if (afterLineEnd
< tabSize
) {
264 afterLineEnd
-= tabSize
;
266 buf
.append(properIndent
.charAt(i
));
267 if (afterLineEnd
== 0) break;
272 for (int i
= 0; i
< afterLineEnd
; i
++) {
276 return buf
.toString();
282 public static void typeInStringAtCaretHonorBlockSelection(final Editor editor
, final String str
, final boolean toProcessOverwriteMode
)
283 throws ReadOnlyFragmentModificationException
285 Document doc
= editor
.getDocument();
286 final SelectionModel selectionModel
= editor
.getSelectionModel();
287 if (selectionModel
.hasBlockSelection()) {
288 RangeMarker guard
= selectionModel
.getBlockSelectionGuard();
290 DocumentEvent evt
= new MockDocumentEvent(doc
, editor
.getCaretModel().getOffset());
291 ReadOnlyFragmentModificationException e
= new ReadOnlyFragmentModificationException(evt
, guard
);
292 EditorActionManager
.getInstance().getReadonlyFragmentModificationHandler(doc
).handle(e
);
295 final LogicalPosition start
= selectionModel
.getBlockStart();
296 final LogicalPosition end
= selectionModel
.getBlockEnd();
297 assert start
!= null;
300 int column
= Math
.min(start
.column
, end
.column
);
301 int startLine
= Math
.min(start
.line
, end
.line
);
302 int endLine
= Math
.max(start
.line
, end
.line
);
303 deleteBlockSelection(editor
);
304 for (int i
= startLine
; i
<= endLine
; i
++) {
305 editor
.getCaretModel().moveToLogicalPosition(new LogicalPosition(i
, column
));
306 insertStringAtCaret(editor
, str
, toProcessOverwriteMode
, true);
308 selectionModel
.setBlockSelection(new LogicalPosition(startLine
, column
+ str
.length()),
309 new LogicalPosition(endLine
, column
+ str
.length()));
313 insertStringAtCaret(editor
, str
, toProcessOverwriteMode
, true);