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-2015 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() {
95  return biasLeft ? selectionStart : selectionEnd;
96  }
97 
101  public int getCaretLine() {
102  return biasLeft ? selectionStartLine : selectionEndLine;
103  }
104 
110  public int getMarkPosition() {
111  return biasLeft ? selectionEnd : selectionStart;
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  } else {
167  return getText(selectionStart, selectionEnd - selectionStart);
168  }
169  }
170 
171  public void disableSelectionIfEmpty() {
172  // Disable rectangle select if selection start = selection end
173  if (selectionStart == selectionEnd) {
174  rectangleSelect = false;
175  }
176  }
177 
184  @Nullable
185  public String getText(final int start, final int len) {
186  try {
187  return document.getText(start, len);
188  } catch (final BadLocationException bl) {
189  bl.printStackTrace();
190  return null;
191  }
192  }
193 
201  public void getText(final int start, final int len, @NotNull final Segment segment) {
202  try {
203  document.getText(start, len, segment);
204  } catch (final BadLocationException bl) {
205  bl.printStackTrace();
206  segment.offset = 0;
207  segment.count = 0;
208  }
209  }
210 
215  public void setSelectedText(@NotNull final String selectedText) {
217 
218  try {
219  if (rectangleSelect) {
220  final Element map = document.getDefaultRootElement();
221 
222  int start = selectionStart - map.getElement(selectionStartLine).getStartOffset();
223  int end = selectionEnd - map.getElement(selectionEndLine).getStartOffset();
224 
225  // Certain rectangles satisfy this condition...
226  if (end < start) {
227  final int tmp = end;
228  end = start;
229  start = tmp;
230  }
231 
232  int lastNewline = 0;
233  int currNewline = 0;
234 
235  for (int i = selectionStartLine; i <= selectionEndLine; i++) {
236  final Element lineElement = map.getElement(i);
237  final int lineStart = lineElement.getStartOffset();
238  final int lineEnd = lineElement.getEndOffset() - 1;
239  final int rectangleStart = Math.min(lineEnd, lineStart + start);
240 
241  document.remove(rectangleStart, Math.min(lineEnd - rectangleStart, end - start));
242 
243  if (selectedText == null) {
244  continue;
245  }
246 
247  currNewline = selectedText.indexOf('\n', lastNewline);
248  if (currNewline == -1) {
249  currNewline = selectedText.length();
250  }
251 
252  document.insertString(rectangleStart, selectedText.substring(lastNewline, currNewline), null);
253 
254  lastNewline = Math.min(selectedText.length(), currNewline + 1);
255  }
256 
257  if (selectedText != null && currNewline != selectedText.length()) {
258  final int offset = map.getElement(selectionEndLine).getEndOffset() - 1;
259  document.insertString(offset, "\n", null);
260  document.insertString(offset + 1, selectedText.substring(currNewline + 1), null);
261  }
262  } else {
263  document.remove(selectionStart, selectionEnd - selectionStart);
264  if (selectedText != null) {
265  document.insertString(selectionStart, selectedText, null);
266  }
267  }
268  } catch (final BadLocationException bl) {
269  bl.printStackTrace();
270  throw new InternalError("Cannot replace selection");
271  } finally {
272  // No matter what happens... stops us from leaving document
273  // in a bad state
275  }
276  }
277 
281  public boolean isSelectionRectangular() {
282  return rectangleSelect;
283  }
284 
290  public void setSelectionRectangular(final boolean rectangleSelect) {
291  this.rectangleSelect = rectangleSelect;
292  }
293 
297  @NotNull
299  return document;
300  }
301 
306  @Nullable
308  return document.getTokenMarker();
309  }
310 
315  public int getDocumentLength() {
316  return document.getLength();
317  }
318 
322  public int getLineCount() {
323  return document.getDefaultRootElement().getElementCount();
324  }
325 
330  public int getLineOfOffset(final int offset) {
331  return document.getDefaultRootElement().getElementIndex(offset);
332  }
333 
340  public int getLineStartOffset(final int line) {
341  final Element lineElement = document.getDefaultRootElement().getElement(line);
342  if (lineElement == null) {
343  return -1;
344  } else {
345  return lineElement.getStartOffset();
346  }
347  }
348 
355  public int getLineEndOffset(final int line) {
356  final Element lineElement = document.getDefaultRootElement().getElement(line);
357  if (lineElement == null) {
358  return -1;
359  } else {
360  return lineElement.getEndOffset();
361  }
362  }
363 
368  public int getLineLength(final int line) {
369  final Element lineElement = document.getDefaultRootElement().getElement(line);
370  if (lineElement == null) {
371  return -1;
372  } else {
373  return lineElement.getEndOffset() - lineElement.getStartOffset() - 1;
374  }
375  }
376 
380  @NotNull
381  public String getText() {
382  try {
383  return document.getText(0, document.getLength());
384  } catch (final BadLocationException bl) {
385  bl.printStackTrace();
386  return "";
387  }
388  }
389 
393  public void setText(@NotNull final String text) {
394  try {
396  document.remove(0, document.getLength());
397  document.insertString(0, text, null);
398  } catch (final BadLocationException bl) {
399  bl.printStackTrace();
400  } finally {
402  }
403  }
404 
410  @NotNull
411  public CharSequence getLineText(final int lineIndex) {
412  final int start = getLineStartOffset(lineIndex);
413  return getText(start, getLineEndOffset(lineIndex) - start - 1);
414  }
415 
421  public void getLineText(final int lineIndex, @NotNull final Segment segment) {
422  final int start = getLineStartOffset(lineIndex);
423  getText(start, getLineEndOffset(lineIndex) - start - 1, segment);
424  }
425 
426 }
A document implementation that can be tokenized by the syntax highlighting system.
final SyntaxDocument document
The SyntaxDocument this selection is part of.
int getSelectionEnd()
Returns the selection end offset.
int getCaretPosition()
Returns the caret position.
int getSelectionStart()
Returns the selection start offset.
TextAreaSelection(@NotNull final SyntaxDocument document)
Creates a new instance.
int getLineCount()
Returns the number of lines in the document.
void getLineText(final int lineIndex, @NotNull final Segment segment)
Copies the text on the specified line into a segment.
int getLineLength(final int line)
Returns the length of the specified line.
TokenMarker getTokenMarker()
Returns the document&#39;s token marker.
Base package of all Gridarta classes.
TokenMarker getTokenMarker()
Returns the token marker that is to be used to split lines of this document up into tokens...
CharSequence getLineText(final int lineIndex)
Returns the text on the specified line.
void setSelection(final int newStart, final int newEnd, final int newStartLine, final int newEndLine, final boolean newBias)
SyntaxDocument getDocument()
Returns the document this text area is editing.
static void beginCompoundEdit()
Starts a compound edit that can be undone in one operation.
void setText(@NotNull final String text)
Sets the entire text of this text area.
int getSelectionStartLine()
Returns the selection start line.
This package contains the other part of the script editor.
static void endCompoundEdit()
Ends a compound edit that can be undone in one operation.
void setSelectionRectangular(final boolean rectangleSelect)
Sets if the selection should be rectangular.
String getText(final int start, final int len)
Returns the specified substring of the document.
void getText(final int start, final int len, @NotNull final Segment segment)
Copies the specified substring of the document into a segment.
int getLineEndOffset(final int line)
Returns the end offset of the specified line.
A token marker that splits lines of text into tokens.
boolean isSelectionRectangular()
Returns true if the selection is rectangular, false otherwise.
int getLineStartOffset(final int line)
Returns the start offset of the specified line.
String getText()
Returns the entire text of this text area.
int getSelectionEndLine()
Returns the selection end line.
int getLineOfOffset(final int offset)
Returns the line containing the specified offset.
int getDocumentLength()
Returns the length of the document.
String getSelectedText()
Returns the selected text, or null if no selection is active.
void setSelectedText(@NotNull final String selectedText)
Replaces the selection with the specified text.