Gridarta Editor
TextAreaSelection.java
Go to the documentation of this file.
1 /*
2  * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games.
3  * Copyright (C) 2000-2023 The Gridarta Developers.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 package net.sf.gridarta.textedit.textarea;
21 
22 import javax.swing.text.BadLocationException;
23 import javax.swing.text.Element;
24 import javax.swing.text.Segment;
26 import org.jetbrains.annotations.NotNull;
27 import org.jetbrains.annotations.Nullable;
28 
29 public class TextAreaSelection {
30 
34  @NotNull
35  private final SyntaxDocument document;
36 
37  private int selectionStart;
38 
39  private int selectionStartLine;
40 
41  private int selectionEnd;
42 
43  private int selectionEndLine;
44 
45  private boolean biasLeft;
46 
47  private boolean rectangleSelect;
48 
53  public TextAreaSelection(@NotNull final SyntaxDocument document) {
54  this.document = document;
55  }
56 
60  public int getSelectionStart() {
61  return selectionStart;
62  }
63 
67  public int getSelectionStartLine() {
68  return selectionStartLine;
69  }
70 
74  public int getSelectionEnd() {
75  return selectionEnd;
76  }
77 
81  public int getSelectionEndLine() {
82  return selectionEndLine;
83  }
84 
85  public boolean getBiasLeft() {
86  return biasLeft;
87  }
88 
94  public int getCaretPosition() {
96  }
97 
101  public int getCaretLine() {
103  }
104 
110  public int getMarkPosition() {
112  }
113 
114  public void setSelection(final int newStart, final int newEnd, final int newStartLine, final int newEndLine, final boolean newBias) {
115  selectionStart = newStart;
116  selectionEnd = newEnd;
117  selectionStartLine = newStartLine;
118  selectionEndLine = newEndLine;
119  biasLeft = newBias;
120  }
121 
125  @Nullable
126  public String getSelectedText() {
127  if (selectionStart == selectionEnd) {
128  return null;
129  }
130 
131  if (rectangleSelect) {
132  // Return each row of the selection on a new line
133 
134  final Element map = document.getDefaultRootElement();
135 
136  int start = selectionStart - map.getElement(selectionStartLine).getStartOffset();
137  int end = selectionEnd - map.getElement(selectionEndLine).getStartOffset();
138 
139  // Certain rectangles satisfy this condition...
140  if (end < start) {
141  final int tmp = end;
142  end = start;
143  start = tmp;
144  }
145 
146  final StringBuilder buf = new StringBuilder();
147  final Segment seg = new Segment();
148 
149  for (int i = selectionStartLine; i <= selectionEndLine; i++) {
150  final Element lineElement = map.getElement(i);
151  int lineStart = lineElement.getStartOffset();
152  final int lineEnd = lineElement.getEndOffset() - 1;
153 
154  lineStart = Math.min(lineStart + start, lineEnd);
155  final int lineLen = Math.min(end - start, lineEnd - lineStart);
156 
157  getText(lineStart, lineLen, seg);
158  buf.append(seg.array, seg.offset, seg.count);
159 
160  if (i != selectionEndLine) {
161  buf.append('\n');
162  }
163  }
164 
165  return buf.toString();
166  }
168  }
169 
170  public void disableSelectionIfEmpty() {
171  // Disable rectangle select if selection start = selection end
172  if (selectionStart == selectionEnd) {
173  rectangleSelect = false;
174  }
175  }
176 
183  @Nullable
184  public String getText(final int start, final int len) {
185  try {
186  return document.getText(start, len);
187  } catch (final BadLocationException bl) {
188  bl.printStackTrace();
189  return null;
190  }
191  }
192 
200  public void getText(final int start, final int len, @NotNull final Segment segment) {
201  try {
202  document.getText(start, len, segment);
203  } catch (final BadLocationException bl) {
204  bl.printStackTrace();
205  segment.offset = 0;
206  segment.count = 0;
207  }
208  }
209 
214  public void setSelectedText(@NotNull final String selectedText) {
216 
217  try {
218  if (rectangleSelect) {
219  final Element map = document.getDefaultRootElement();
220 
221  int start = selectionStart - map.getElement(selectionStartLine).getStartOffset();
222  int end = selectionEnd - map.getElement(selectionEndLine).getStartOffset();
223 
224  // Certain rectangles satisfy this condition...
225  if (end < start) {
226  final int tmp = end;
227  end = start;
228  start = tmp;
229  }
230 
231  int lastNewline = 0;
232  int currNewline = 0;
233 
234  for (int i = selectionStartLine; i <= selectionEndLine; i++) {
235  final Element lineElement = map.getElement(i);
236  final int lineStart = lineElement.getStartOffset();
237  final int lineEnd = lineElement.getEndOffset() - 1;
238  final int rectangleStart = Math.min(lineEnd, lineStart + start);
239 
240  document.remove(rectangleStart, Math.min(lineEnd - rectangleStart, end - start));
241 
242  if (selectedText == null) {
243  continue;
244  }
245 
246  currNewline = selectedText.indexOf('\n', lastNewline);
247  if (currNewline == -1) {
248  currNewline = selectedText.length();
249  }
250 
251  document.insertString(rectangleStart, selectedText.substring(lastNewline, currNewline), null);
252 
253  lastNewline = Math.min(selectedText.length(), currNewline + 1);
254  }
255 
256  if (selectedText != null && currNewline != selectedText.length()) {
257  final int offset = map.getElement(selectionEndLine).getEndOffset() - 1;
258  document.insertString(offset, "\n", null);
259  document.insertString(offset + 1, selectedText.substring(currNewline + 1), null);
260  }
261  } else {
263  if (selectedText != null) {
264  document.insertString(selectionStart, selectedText, null);
265  }
266  }
267  } catch (final BadLocationException bl) {
268  bl.printStackTrace();
269  throw new InternalError("Cannot replace selection");
270  } finally {
271  // No matter what happens... stops us from leaving document
272  // in a bad state
274  }
275  }
276 
280  public boolean isSelectionRectangular() {
281  return rectangleSelect;
282  }
283 
289  public void setSelectionRectangular(final boolean rectangleSelect) {
290  this.rectangleSelect = rectangleSelect;
291  }
292 
296  @NotNull
298  return document;
299  }
300 
305  @Nullable
307  return document.getTokenMarker();
308  }
309 
314  public int getDocumentLength() {
315  return document.getLength();
316  }
317 
321  public int getLineCount() {
322  return document.getDefaultRootElement().getElementCount();
323  }
324 
329  public int getLineOfOffset(final int offset) {
330  return document.getDefaultRootElement().getElementIndex(offset);
331  }
332 
339  public int getLineStartOffset(final int line) {
340  final Element lineElement = document.getDefaultRootElement().getElement(line);
341  return lineElement == null ? -1 : lineElement.getStartOffset();
342  }
343 
350  public int getLineEndOffset(final int line) {
351  final Element lineElement = document.getDefaultRootElement().getElement(line);
352  return lineElement == null ? -1 : lineElement.getEndOffset();
353  }
354 
359  public int getLineLength(final int line) {
360  final Element lineElement = document.getDefaultRootElement().getElement(line);
361  return lineElement == null ? -1 : lineElement.getEndOffset() - lineElement.getStartOffset() - 1;
362  }
363 
367  @NotNull
368  public String getText() {
369  try {
370  return document.getText(0, document.getLength());
371  } catch (final BadLocationException bl) {
372  bl.printStackTrace();
373  return "";
374  }
375  }
376 
380  public void setText(@NotNull final String text) {
381  try {
383  document.remove(0, document.getLength());
384  document.insertString(0, text, null);
385  } catch (final BadLocationException bl) {
386  bl.printStackTrace();
387  } finally {
389  }
390  }
391 
397  @NotNull
398  public CharSequence getLineText(final int lineIndex) {
399  final int start = getLineStartOffset(lineIndex);
400  return getText(start, getLineEndOffset(lineIndex) - start - 1);
401  }
402 
408  public void getLineText(final int lineIndex, @NotNull final Segment segment) {
409  final int start = getLineStartOffset(lineIndex);
410  getText(start, getLineEndOffset(lineIndex) - start - 1, segment);
411  }
412 
413 }
net.sf.gridarta.textedit.textarea.SyntaxDocument.getTokenMarker
TokenMarker getTokenMarker()
Returns the token marker that is to be used to split lines of this document up into tokens.
Definition: SyntaxDocument.java:42
net.sf.gridarta.textedit.textarea.TextAreaSelection.getSelectionStart
int getSelectionStart()
Returns the selection start offset.
Definition: TextAreaSelection.java:60
net.sf.gridarta.textedit.textarea.TextAreaSelection.getSelectionEnd
int getSelectionEnd()
Returns the selection end offset.
Definition: TextAreaSelection.java:74
net.sf.gridarta.textedit.textarea.TextAreaSelection.getBiasLeft
boolean getBiasLeft()
Definition: TextAreaSelection.java:85
net.sf.gridarta.textedit.textarea.TextAreaSelection.getLineEndOffset
int getLineEndOffset(final int line)
Returns the end offset of the specified line.
Definition: TextAreaSelection.java:350
net.sf.gridarta.textedit.textarea.TextAreaSelection.selectionEndLine
int selectionEndLine
Definition: TextAreaSelection.java:43
net.sf.gridarta.textedit.textarea.TextAreaSelection.getSelectionEndLine
int getSelectionEndLine()
Returns the selection end line.
Definition: TextAreaSelection.java:81
net.sf.gridarta.textedit.textarea
This package contains the other part of the script editor.
net.sf.gridarta
Base package of all Gridarta classes.
net.sf.gridarta.textedit.textarea.TextAreaSelection.isSelectionRectangular
boolean isSelectionRectangular()
Returns true if the selection is rectangular, false otherwise.
Definition: TextAreaSelection.java:280
net.sf.gridarta.textedit.textarea.TextAreaSelection.getTokenMarker
TokenMarker getTokenMarker()
Returns the document's token marker.
Definition: TextAreaSelection.java:306
net.sf
net.sf.gridarta.textedit.textarea.TextAreaSelection.biasLeft
boolean biasLeft
Definition: TextAreaSelection.java:45
net.sf.gridarta.textedit.textarea.TextAreaSelection.getText
void getText(final int start, final int len, @NotNull final Segment segment)
Copies the specified substring of the document into a segment.
Definition: TextAreaSelection.java:200
net.sf.gridarta.textedit.textarea.TextAreaSelection.rectangleSelect
boolean rectangleSelect
Definition: TextAreaSelection.java:47
net.sf.gridarta.textedit.textarea.TextAreaSelection.getLineText
CharSequence getLineText(final int lineIndex)
Returns the text on the specified line.
Definition: TextAreaSelection.java:398
net.sf.gridarta.textedit.textarea.TextAreaSelection.getSelectedText
String getSelectedText()
Returns the selected text, or null if no selection is active.
Definition: TextAreaSelection.java:126
net.sf.gridarta.textedit.textarea.TextAreaSelection.getText
String getText()
Returns the entire text of this text area.
Definition: TextAreaSelection.java:368
net.sf.gridarta.textedit.textarea.TextAreaSelection.selectionEnd
int selectionEnd
Definition: TextAreaSelection.java:41
net.sf.gridarta.textedit.textarea.TextAreaSelection.getDocument
SyntaxDocument getDocument()
Returns the document this text area is editing.
Definition: TextAreaSelection.java:297
net.sf.gridarta.textedit
net.sf.gridarta.textedit.textarea.TextAreaSelection
Definition: TextAreaSelection.java:29
net.sf.gridarta.textedit.textarea.SyntaxDocument
A document implementation that can be tokenized by the syntax highlighting system.
Definition: SyntaxDocument.java:29
net.sf.gridarta.textedit.textarea.TextAreaSelection.getLineCount
int getLineCount()
Returns the number of lines in the document.
Definition: TextAreaSelection.java:321
net.sf.gridarta.textedit.textarea.TextAreaSelection.getLineStartOffset
int getLineStartOffset(final int line)
Returns the start offset of the specified line.
Definition: TextAreaSelection.java:339
net.sf.gridarta.textedit.textarea.tokenmarker
Definition: CrossfireDialogTokenMarker.java:20
net.sf.gridarta.textedit.textarea.TextAreaSelection.getDocumentLength
int getDocumentLength()
Returns the length of the document.
Definition: TextAreaSelection.java:314
net
net.sf.gridarta.textedit.textarea.TextAreaSelection.getCaretPosition
int getCaretPosition()
Returns the caret position.
Definition: TextAreaSelection.java:94
net.sf.gridarta.textedit.textarea.SyntaxDocument.beginCompoundEdit
static void beginCompoundEdit()
Starts a compound edit that can be undone in one operation.
Definition: SyntaxDocument.java:102
net.sf.gridarta.textedit.textarea.TextAreaSelection.setSelection
void setSelection(final int newStart, final int newEnd, final int newStartLine, final int newEndLine, final boolean newBias)
Definition: TextAreaSelection.java:114
net.sf.gridarta.textedit.textarea.TextAreaSelection.selectionStartLine
int selectionStartLine
Definition: TextAreaSelection.java:39
net.sf.gridarta.textedit.textarea.TextAreaSelection.getLineOfOffset
int getLineOfOffset(final int offset)
Returns the line containing the specified offset.
Definition: TextAreaSelection.java:329
net.sf.gridarta.textedit.textarea.TextAreaSelection.setSelectionRectangular
void setSelectionRectangular(final boolean rectangleSelect)
Sets if the selection should be rectangular.
Definition: TextAreaSelection.java:289
net.sf.gridarta.textedit.textarea.SyntaxDocument.endCompoundEdit
static void endCompoundEdit()
Ends a compound edit that can be undone in one operation.
Definition: SyntaxDocument.java:110
net.sf.gridarta.textedit.textarea.TextAreaSelection.setText
void setText(@NotNull final String text)
Sets the entire text of this text area.
Definition: TextAreaSelection.java:380
net.sf.gridarta.textedit.textarea.TextAreaSelection.document
final SyntaxDocument document
The SyntaxDocument this selection is part of.
Definition: TextAreaSelection.java:35
net.sf.gridarta.textedit.textarea.TextAreaSelection.disableSelectionIfEmpty
void disableSelectionIfEmpty()
Definition: TextAreaSelection.java:170
net.sf.gridarta.textedit.textarea.TextAreaSelection.getText
String getText(final int start, final int len)
Returns the specified substring of the document.
Definition: TextAreaSelection.java:184
net.sf.gridarta.textedit.textarea.TextAreaSelection.getMarkPosition
int getMarkPosition()
Returns the mark position.
Definition: TextAreaSelection.java:110
net.sf.gridarta.textedit.textarea.tokenmarker.TokenMarker
A token marker that splits lines of text into tokens.
Definition: TokenMarker.java:32
net.sf.gridarta.textedit.textarea.TextAreaSelection.getLineText
void getLineText(final int lineIndex, @NotNull final Segment segment)
Copies the text on the specified line into a segment.
Definition: TextAreaSelection.java:408
net.sf.gridarta.textedit.textarea.TextAreaSelection.selectionStart
int selectionStart
Definition: TextAreaSelection.java:37
net.sf.gridarta.textedit.textarea.TextAreaSelection.getLineLength
int getLineLength(final int line)
Returns the length of the specified line.
Definition: TextAreaSelection.java:359
net.sf.gridarta.textedit.textarea.TextAreaSelection.TextAreaSelection
TextAreaSelection(@NotNull final SyntaxDocument document)
Creates a new instance.
Definition: TextAreaSelection.java:53
net.sf.gridarta.textedit.textarea.TextAreaSelection.setSelectedText
void setSelectedText(@NotNull final String selectedText)
Replaces the selection with the specified text.
Definition: TextAreaSelection.java:214
net.sf.gridarta.textedit.textarea.TextAreaSelection.getSelectionStartLine
int getSelectionStartLine()
Returns the selection start line.
Definition: TextAreaSelection.java:67
net.sf.gridarta.textedit.textarea.TextAreaSelection.getCaretLine
int getCaretLine()
Returns the caret line.
Definition: TextAreaSelection.java:101