author | darcy |
Fri, 24 Jan 2014 07:16:53 -0800 | |
changeset 22574 | 7f8ce0c8c20a |
parent 20458 | f2423fb3fd19 |
child 25193 | 187a455af8f8 |
permissions | -rw-r--r-- |
2 | 1 |
/* |
22574
7f8ce0c8c20a
8032627: Add @SuppressWarnings("serial") to appropriate javax.swing classes
darcy
parents:
20458
diff
changeset
|
2 |
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. |
2 | 3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 10 |
* |
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
5506 | 21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
2 | 24 |
*/ |
25 |
package javax.swing.text; |
|
26 |
||
27 |
import java.util.Vector; |
|
28 |
import java.io.Serializable; |
|
29 |
import javax.swing.undo.*; |
|
30 |
import javax.swing.SwingUtilities; |
|
31 |
||
32 |
/** |
|
33 |
* An implementation of the AbstractDocument.Content interface that is |
|
34 |
* a brute force implementation that is useful for relatively small |
|
35 |
* documents and/or debugging. It manages the character content |
|
36 |
* as a simple character array. It is also quite inefficient. |
|
37 |
* <p> |
|
38 |
* It is generally recommended that the gap buffer or piece table |
|
39 |
* implementations be used instead. This buffer does not scale up |
|
40 |
* to large sizes. |
|
41 |
* <p> |
|
42 |
* <strong>Warning:</strong> |
|
43 |
* Serialized objects of this class will not be compatible with |
|
44 |
* future Swing releases. The current serialization support is |
|
45 |
* appropriate for short term storage or RMI between applications running |
|
46 |
* the same version of Swing. As of 1.4, support for long term storage |
|
20458 | 47 |
* of all JavaBeans™ |
2 | 48 |
* has been added to the <code>java.beans</code> package. |
49 |
* Please see {@link java.beans.XMLEncoder}. |
|
50 |
* |
|
51 |
* @author Timothy Prinzing |
|
52 |
*/ |
|
22574
7f8ce0c8c20a
8032627: Add @SuppressWarnings("serial") to appropriate javax.swing classes
darcy
parents:
20458
diff
changeset
|
53 |
@SuppressWarnings("serial") // Same-version serialization only |
2 | 54 |
public final class StringContent implements AbstractDocument.Content, Serializable { |
55 |
||
56 |
/** |
|
57 |
* Creates a new StringContent object. Initial size defaults to 10. |
|
58 |
*/ |
|
59 |
public StringContent() { |
|
60 |
this(10); |
|
61 |
} |
|
62 |
||
63 |
/** |
|
64 |
* Creates a new StringContent object, with the initial |
|
20158
1c5d22e5b898
8025117: [cleanup] Eliminate doclint errors in javax/swing/text classes
yan
parents:
5506
diff
changeset
|
65 |
* size specified. If the length is < 1, a size of 1 is used. |
2 | 66 |
* |
67 |
* @param initialLength the initial size |
|
68 |
*/ |
|
69 |
public StringContent(int initialLength) { |
|
70 |
if (initialLength < 1) { |
|
71 |
initialLength = 1; |
|
72 |
} |
|
73 |
data = new char[initialLength]; |
|
74 |
data[0] = '\n'; |
|
75 |
count = 1; |
|
76 |
} |
|
77 |
||
78 |
/** |
|
79 |
* Returns the length of the content. |
|
80 |
* |
|
20158
1c5d22e5b898
8025117: [cleanup] Eliminate doclint errors in javax/swing/text classes
yan
parents:
5506
diff
changeset
|
81 |
* @return the length >= 1 |
2 | 82 |
* @see AbstractDocument.Content#length |
83 |
*/ |
|
84 |
public int length() { |
|
85 |
return count; |
|
86 |
} |
|
87 |
||
88 |
/** |
|
89 |
* Inserts a string into the content. |
|
90 |
* |
|
20158
1c5d22e5b898
8025117: [cleanup] Eliminate doclint errors in javax/swing/text classes
yan
parents:
5506
diff
changeset
|
91 |
* @param where the starting position >= 0 && < length() |
2 | 92 |
* @param str the non-null string to insert |
93 |
* @return an UndoableEdit object for undoing |
|
94 |
* @exception BadLocationException if the specified position is invalid |
|
95 |
* @see AbstractDocument.Content#insertString |
|
96 |
*/ |
|
97 |
public UndoableEdit insertString(int where, String str) throws BadLocationException { |
|
98 |
if (where >= count || where < 0) { |
|
99 |
throw new BadLocationException("Invalid location", count); |
|
100 |
} |
|
101 |
char[] chars = str.toCharArray(); |
|
102 |
replace(where, 0, chars, 0, chars.length); |
|
103 |
if (marks != null) { |
|
104 |
updateMarksForInsert(where, str.length()); |
|
105 |
} |
|
106 |
return new InsertUndo(where, str.length()); |
|
107 |
} |
|
108 |
||
109 |
/** |
|
20158
1c5d22e5b898
8025117: [cleanup] Eliminate doclint errors in javax/swing/text classes
yan
parents:
5506
diff
changeset
|
110 |
* Removes part of the content. where + nitems must be < length(). |
2 | 111 |
* |
20158
1c5d22e5b898
8025117: [cleanup] Eliminate doclint errors in javax/swing/text classes
yan
parents:
5506
diff
changeset
|
112 |
* @param where the starting position >= 0 |
1c5d22e5b898
8025117: [cleanup] Eliminate doclint errors in javax/swing/text classes
yan
parents:
5506
diff
changeset
|
113 |
* @param nitems the number of characters to remove >= 0 |
2 | 114 |
* @return an UndoableEdit object for undoing |
115 |
* @exception BadLocationException if the specified position is invalid |
|
116 |
* @see AbstractDocument.Content#remove |
|
117 |
*/ |
|
118 |
public UndoableEdit remove(int where, int nitems) throws BadLocationException { |
|
119 |
if (where + nitems >= count) { |
|
120 |
throw new BadLocationException("Invalid range", count); |
|
121 |
} |
|
122 |
String removedString = getString(where, nitems); |
|
123 |
UndoableEdit edit = new RemoveUndo(where, removedString); |
|
124 |
replace(where, nitems, empty, 0, 0); |
|
125 |
if (marks != null) { |
|
126 |
updateMarksForRemove(where, nitems); |
|
127 |
} |
|
128 |
return edit; |
|
129 |
||
130 |
} |
|
131 |
||
132 |
/** |
|
20158
1c5d22e5b898
8025117: [cleanup] Eliminate doclint errors in javax/swing/text classes
yan
parents:
5506
diff
changeset
|
133 |
* Retrieves a portion of the content. where + len must be <= length(). |
2 | 134 |
* |
20158
1c5d22e5b898
8025117: [cleanup] Eliminate doclint errors in javax/swing/text classes
yan
parents:
5506
diff
changeset
|
135 |
* @param where the starting position >= 0 |
1c5d22e5b898
8025117: [cleanup] Eliminate doclint errors in javax/swing/text classes
yan
parents:
5506
diff
changeset
|
136 |
* @param len the length to retrieve >= 0 |
2 | 137 |
* @return a string representing the content; may be empty |
138 |
* @exception BadLocationException if the specified position is invalid |
|
139 |
* @see AbstractDocument.Content#getString |
|
140 |
*/ |
|
141 |
public String getString(int where, int len) throws BadLocationException { |
|
142 |
if (where + len > count) { |
|
143 |
throw new BadLocationException("Invalid range", count); |
|
144 |
} |
|
145 |
return new String(data, where, len); |
|
146 |
} |
|
147 |
||
148 |
/** |
|
20158
1c5d22e5b898
8025117: [cleanup] Eliminate doclint errors in javax/swing/text classes
yan
parents:
5506
diff
changeset
|
149 |
* Retrieves a portion of the content. where + len must be <= length() |
2 | 150 |
* |
20158
1c5d22e5b898
8025117: [cleanup] Eliminate doclint errors in javax/swing/text classes
yan
parents:
5506
diff
changeset
|
151 |
* @param where the starting position >= 0 |
1c5d22e5b898
8025117: [cleanup] Eliminate doclint errors in javax/swing/text classes
yan
parents:
5506
diff
changeset
|
152 |
* @param len the number of characters to retrieve >= 0 |
2 | 153 |
* @param chars the Segment object to return the characters in |
154 |
* @exception BadLocationException if the specified position is invalid |
|
155 |
* @see AbstractDocument.Content#getChars |
|
156 |
*/ |
|
157 |
public void getChars(int where, int len, Segment chars) throws BadLocationException { |
|
158 |
if (where + len > count) { |
|
159 |
throw new BadLocationException("Invalid location", count); |
|
160 |
} |
|
161 |
chars.array = data; |
|
162 |
chars.offset = where; |
|
163 |
chars.count = len; |
|
164 |
} |
|
165 |
||
166 |
/** |
|
167 |
* Creates a position within the content that will |
|
168 |
* track change as the content is mutated. |
|
169 |
* |
|
20158
1c5d22e5b898
8025117: [cleanup] Eliminate doclint errors in javax/swing/text classes
yan
parents:
5506
diff
changeset
|
170 |
* @param offset the offset to create a position for >= 0 |
2 | 171 |
* @return the position |
172 |
* @exception BadLocationException if the specified position is invalid |
|
173 |
*/ |
|
174 |
public Position createPosition(int offset) throws BadLocationException { |
|
175 |
// some small documents won't have any sticky positions |
|
176 |
// at all, so the buffer is created lazily. |
|
177 |
if (marks == null) { |
|
1287
a04aca99c77a
6722802: Code improvement and warnings removing from the javax.swing.text package
rupashka
parents:
2
diff
changeset
|
178 |
marks = new Vector<PosRec>(); |
2 | 179 |
} |
180 |
return new StickyPosition(offset); |
|
181 |
} |
|
182 |
||
183 |
// --- local methods --------------------------------------- |
|
184 |
||
185 |
/** |
|
186 |
* Replaces some of the characters in the array |
|
187 |
* @param offset offset into the array to start the replace |
|
188 |
* @param length number of characters to remove |
|
189 |
* @param replArray replacement array |
|
190 |
* @param replOffset offset into the replacement array |
|
191 |
* @param replLength number of character to use from the |
|
192 |
* replacement array. |
|
193 |
*/ |
|
194 |
void replace(int offset, int length, |
|
195 |
char[] replArray, int replOffset, int replLength) { |
|
196 |
int delta = replLength - length; |
|
197 |
int src = offset + length; |
|
198 |
int nmove = count - src; |
|
199 |
int dest = src + delta; |
|
200 |
if ((count + delta) >= data.length) { |
|
201 |
// need to grow the array |
|
202 |
int newLength = Math.max(2*data.length, count + delta); |
|
203 |
char[] newData = new char[newLength]; |
|
204 |
System.arraycopy(data, 0, newData, 0, offset); |
|
205 |
System.arraycopy(replArray, replOffset, newData, offset, replLength); |
|
206 |
System.arraycopy(data, src, newData, dest, nmove); |
|
207 |
data = newData; |
|
208 |
} else { |
|
209 |
// patch the existing array |
|
210 |
System.arraycopy(data, src, data, dest, nmove); |
|
211 |
System.arraycopy(replArray, replOffset, data, offset, replLength); |
|
212 |
} |
|
213 |
count = count + delta; |
|
214 |
} |
|
215 |
||
216 |
void resize(int ncount) { |
|
217 |
char[] ndata = new char[ncount]; |
|
218 |
System.arraycopy(data, 0, ndata, 0, Math.min(ncount, count)); |
|
219 |
data = ndata; |
|
220 |
} |
|
221 |
||
222 |
synchronized void updateMarksForInsert(int offset, int length) { |
|
223 |
if (offset == 0) { |
|
224 |
// zero is a special case where we update only |
|
225 |
// marks after it. |
|
226 |
offset = 1; |
|
227 |
} |
|
228 |
int n = marks.size(); |
|
229 |
for (int i = 0; i < n; i++) { |
|
1287
a04aca99c77a
6722802: Code improvement and warnings removing from the javax.swing.text package
rupashka
parents:
2
diff
changeset
|
230 |
PosRec mark = marks.elementAt(i); |
2 | 231 |
if (mark.unused) { |
232 |
// this record is no longer used, get rid of it |
|
233 |
marks.removeElementAt(i); |
|
234 |
i -= 1; |
|
235 |
n -= 1; |
|
236 |
} else if (mark.offset >= offset) { |
|
237 |
mark.offset += length; |
|
238 |
} |
|
239 |
} |
|
240 |
} |
|
241 |
||
242 |
synchronized void updateMarksForRemove(int offset, int length) { |
|
243 |
int n = marks.size(); |
|
244 |
for (int i = 0; i < n; i++) { |
|
1287
a04aca99c77a
6722802: Code improvement and warnings removing from the javax.swing.text package
rupashka
parents:
2
diff
changeset
|
245 |
PosRec mark = marks.elementAt(i); |
2 | 246 |
if (mark.unused) { |
247 |
// this record is no longer used, get rid of it |
|
248 |
marks.removeElementAt(i); |
|
249 |
i -= 1; |
|
250 |
n -= 1; |
|
251 |
} else if (mark.offset >= (offset + length)) { |
|
252 |
mark.offset -= length; |
|
253 |
} else if (mark.offset >= offset) { |
|
254 |
mark.offset = offset; |
|
255 |
} |
|
256 |
} |
|
257 |
} |
|
258 |
||
259 |
/** |
|
260 |
* Returns a Vector containing instances of UndoPosRef for the |
|
261 |
* Positions in the range |
|
262 |
* <code>offset</code> to <code>offset</code> + <code>length</code>. |
|
263 |
* If <code>v</code> is not null the matching Positions are placed in |
|
264 |
* there. The vector with the resulting Positions are returned. |
|
265 |
* <p> |
|
266 |
* This is meant for internal usage, and is generally not of interest |
|
267 |
* to subclasses. |
|
268 |
* |
|
269 |
* @param v the Vector to use, with a new one created on null |
|
20158
1c5d22e5b898
8025117: [cleanup] Eliminate doclint errors in javax/swing/text classes
yan
parents:
5506
diff
changeset
|
270 |
* @param offset the starting offset >= 0 |
1c5d22e5b898
8025117: [cleanup] Eliminate doclint errors in javax/swing/text classes
yan
parents:
5506
diff
changeset
|
271 |
* @param length the length >= 0 |
2 | 272 |
* @return the set of instances |
273 |
*/ |
|
274 |
protected Vector getPositionsInRange(Vector v, int offset, |
|
275 |
int length) { |
|
276 |
int n = marks.size(); |
|
277 |
int end = offset + length; |
|
278 |
Vector placeIn = (v == null) ? new Vector() : v; |
|
279 |
for (int i = 0; i < n; i++) { |
|
1287
a04aca99c77a
6722802: Code improvement and warnings removing from the javax.swing.text package
rupashka
parents:
2
diff
changeset
|
280 |
PosRec mark = marks.elementAt(i); |
2 | 281 |
if (mark.unused) { |
282 |
// this record is no longer used, get rid of it |
|
283 |
marks.removeElementAt(i); |
|
284 |
i -= 1; |
|
285 |
n -= 1; |
|
286 |
} else if(mark.offset >= offset && mark.offset <= end) |
|
287 |
placeIn.addElement(new UndoPosRef(mark)); |
|
288 |
} |
|
289 |
return placeIn; |
|
290 |
} |
|
291 |
||
292 |
/** |
|
293 |
* Resets the location for all the UndoPosRef instances |
|
294 |
* in <code>positions</code>. |
|
295 |
* <p> |
|
296 |
* This is meant for internal usage, and is generally not of interest |
|
297 |
* to subclasses. |
|
298 |
* |
|
299 |
* @param positions the positions of the instances |
|
300 |
*/ |
|
301 |
protected void updateUndoPositions(Vector positions) { |
|
302 |
for(int counter = positions.size() - 1; counter >= 0; counter--) { |
|
303 |
UndoPosRef ref = (UndoPosRef)positions.elementAt(counter); |
|
304 |
// Check if the Position is still valid. |
|
305 |
if(ref.rec.unused) { |
|
306 |
positions.removeElementAt(counter); |
|
307 |
} |
|
308 |
else |
|
309 |
ref.resetLocation(); |
|
310 |
} |
|
311 |
} |
|
312 |
||
313 |
private static final char[] empty = new char[0]; |
|
314 |
private char[] data; |
|
315 |
private int count; |
|
1287
a04aca99c77a
6722802: Code improvement and warnings removing from the javax.swing.text package
rupashka
parents:
2
diff
changeset
|
316 |
transient Vector<PosRec> marks; |
2 | 317 |
|
318 |
/** |
|
319 |
* holds the data for a mark... separately from |
|
320 |
* the real mark so that the real mark can be |
|
321 |
* collected if there are no more references to |
|
322 |
* it.... the update table holds only a reference |
|
323 |
* to this grungy thing. |
|
324 |
*/ |
|
325 |
final class PosRec { |
|
326 |
||
327 |
PosRec(int offset) { |
|
328 |
this.offset = offset; |
|
329 |
} |
|
330 |
||
331 |
int offset; |
|
332 |
boolean unused; |
|
333 |
} |
|
334 |
||
335 |
/** |
|
336 |
* This really wants to be a weak reference but |
|
337 |
* in 1.1 we don't have a 100% pure solution for |
|
338 |
* this... so this class trys to hack a solution |
|
339 |
* to causing the marks to be collected. |
|
340 |
*/ |
|
341 |
final class StickyPosition implements Position { |
|
342 |
||
343 |
StickyPosition(int offset) { |
|
344 |
rec = new PosRec(offset); |
|
345 |
marks.addElement(rec); |
|
346 |
} |
|
347 |
||
348 |
public int getOffset() { |
|
349 |
return rec.offset; |
|
350 |
} |
|
351 |
||
352 |
protected void finalize() throws Throwable { |
|
353 |
// schedule the record to be removed later |
|
354 |
// on another thread. |
|
355 |
rec.unused = true; |
|
356 |
} |
|
357 |
||
358 |
public String toString() { |
|
359 |
return Integer.toString(getOffset()); |
|
360 |
} |
|
361 |
||
362 |
PosRec rec; |
|
363 |
} |
|
364 |
||
365 |
/** |
|
366 |
* Used to hold a reference to a Position that is being reset as the |
|
367 |
* result of removing from the content. |
|
368 |
*/ |
|
369 |
final class UndoPosRef { |
|
370 |
UndoPosRef(PosRec rec) { |
|
371 |
this.rec = rec; |
|
372 |
this.undoLocation = rec.offset; |
|
373 |
} |
|
374 |
||
375 |
/** |
|
376 |
* Resets the location of the Position to the offset when the |
|
377 |
* receiver was instantiated. |
|
378 |
*/ |
|
379 |
protected void resetLocation() { |
|
380 |
rec.offset = undoLocation; |
|
381 |
} |
|
382 |
||
383 |
/** Location to reset to when resetLocatino is invoked. */ |
|
384 |
protected int undoLocation; |
|
385 |
/** Position to reset offset. */ |
|
386 |
protected PosRec rec; |
|
387 |
} |
|
388 |
||
389 |
/** |
|
390 |
* UnoableEdit created for inserts. |
|
391 |
*/ |
|
392 |
class InsertUndo extends AbstractUndoableEdit { |
|
393 |
protected InsertUndo(int offset, int length) { |
|
394 |
super(); |
|
395 |
this.offset = offset; |
|
396 |
this.length = length; |
|
397 |
} |
|
398 |
||
399 |
public void undo() throws CannotUndoException { |
|
400 |
super.undo(); |
|
401 |
try { |
|
402 |
synchronized(StringContent.this) { |
|
403 |
// Get the Positions in the range being removed. |
|
404 |
if(marks != null) |
|
405 |
posRefs = getPositionsInRange(null, offset, length); |
|
406 |
string = getString(offset, length); |
|
407 |
remove(offset, length); |
|
408 |
} |
|
409 |
} catch (BadLocationException bl) { |
|
410 |
throw new CannotUndoException(); |
|
411 |
} |
|
412 |
} |
|
413 |
||
414 |
public void redo() throws CannotRedoException { |
|
415 |
super.redo(); |
|
416 |
try { |
|
417 |
synchronized(StringContent.this) { |
|
418 |
insertString(offset, string); |
|
419 |
string = null; |
|
420 |
// Update the Positions that were in the range removed. |
|
421 |
if(posRefs != null) { |
|
422 |
updateUndoPositions(posRefs); |
|
423 |
posRefs = null; |
|
424 |
} |
|
425 |
} |
|
426 |
} catch (BadLocationException bl) { |
|
427 |
throw new CannotRedoException(); |
|
428 |
} |
|
429 |
} |
|
430 |
||
431 |
// Where the string goes. |
|
432 |
protected int offset; |
|
433 |
// Length of the string. |
|
434 |
protected int length; |
|
435 |
// The string that was inserted. To cut down on space needed this |
|
436 |
// will only be valid after an undo. |
|
437 |
protected String string; |
|
438 |
// An array of instances of UndoPosRef for the Positions in the |
|
439 |
// range that was removed, valid after undo. |
|
440 |
protected Vector posRefs; |
|
441 |
} |
|
442 |
||
443 |
||
444 |
/** |
|
445 |
* UndoableEdit created for removes. |
|
446 |
*/ |
|
447 |
class RemoveUndo extends AbstractUndoableEdit { |
|
448 |
protected RemoveUndo(int offset, String string) { |
|
449 |
super(); |
|
450 |
this.offset = offset; |
|
451 |
this.string = string; |
|
452 |
this.length = string.length(); |
|
453 |
if(marks != null) |
|
454 |
posRefs = getPositionsInRange(null, offset, length); |
|
455 |
} |
|
456 |
||
457 |
public void undo() throws CannotUndoException { |
|
458 |
super.undo(); |
|
459 |
try { |
|
460 |
synchronized(StringContent.this) { |
|
461 |
insertString(offset, string); |
|
462 |
// Update the Positions that were in the range removed. |
|
463 |
if(posRefs != null) { |
|
464 |
updateUndoPositions(posRefs); |
|
465 |
posRefs = null; |
|
466 |
} |
|
467 |
string = null; |
|
468 |
} |
|
469 |
} catch (BadLocationException bl) { |
|
470 |
throw new CannotUndoException(); |
|
471 |
} |
|
472 |
} |
|
473 |
||
474 |
public void redo() throws CannotRedoException { |
|
475 |
super.redo(); |
|
476 |
try { |
|
477 |
synchronized(StringContent.this) { |
|
478 |
string = getString(offset, length); |
|
479 |
// Get the Positions in the range being removed. |
|
480 |
if(marks != null) |
|
481 |
posRefs = getPositionsInRange(null, offset, length); |
|
482 |
remove(offset, length); |
|
483 |
} |
|
484 |
} catch (BadLocationException bl) { |
|
485 |
throw new CannotRedoException(); |
|
486 |
} |
|
487 |
} |
|
488 |
||
489 |
// Where the string goes. |
|
490 |
protected int offset; |
|
491 |
// Length of the string. |
|
492 |
protected int length; |
|
493 |
// The string that was inserted. This will be null after an undo. |
|
494 |
protected String string; |
|
495 |
// An array of instances of UndoPosRef for the Positions in the |
|
496 |
// range that was removed, valid before undo. |
|
497 |
protected Vector posRefs; |
|
498 |
} |
|
499 |
} |