001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Alexey A. Ivanov
019: * @version $Revision$
020: */package javax.swing.text;
021:
022: import java.io.IOException;
023: import java.io.ObjectInputStream;
024: import java.io.ObjectOutputStream;
025: import java.io.Serializable;
026: import java.util.Vector;
027:
028: import javax.swing.text.ContentPositions.DocumentMark;
029: import javax.swing.undo.UndoableEdit;
030:
031: import org.apache.harmony.x.swing.internal.nls.Messages;
032:
033: @SuppressWarnings("serial")
034: public class GapContent implements AbstractDocument.Content,
035: Serializable {
036:
037: private final class GapContentEdit extends
038: AbstractContentUndoableEdit implements UndoableEdit {
039:
040: public GapContentEdit(final int where, final String chars,
041: final boolean isInsertCommand)
042: throws BadLocationException {
043:
044: super (where, chars, isInsertCommand);
045: }
046:
047: @Override
048: protected Vector getPositionsInRange(final Vector positions,
049: final int where, final int length) {
050: return GapContent.this .getPositionsInRange(positions,
051: where, length);
052: }
053:
054: @Override
055: protected void updateUndoPositions(final Vector undoPos) {
056: GapContent.this .updateUndoPositions(undoPos, pos, len);
057:
058: }
059:
060: @Override
061: protected void insertItems(final int where, final String chars) {
062: try {
063: GapContent.this .insertItems(where, chars.toCharArray(),
064: len);
065: } catch (BadLocationException e) {
066: }
067:
068: }
069:
070: @Override
071: protected void removeItems(final int where, final int length) {
072: try {
073: GapContent.this .removeItems(where, length);
074: } catch (BadLocationException e) {
075: }
076: }
077: }
078:
079: private final class GapContentPositions extends ContentPositions {
080: /**
081: * Resets internal index in Position implementation to be zero if
082: * the position offset is zero. This ensures that position isn't moved
083: * any more.
084: */
085: protected void resetMarksAtZero() {
086: GapContent.this .resetMarksAtZero();
087: }
088:
089: @Override
090: protected int setOffsetForDocumentMark(final int offset) {
091: if (offset == 0 || offset < gapStart) {
092: return offset;
093: }
094: return offset + (gapEnd - gapStart);
095: }
096:
097: @Override
098: protected int getOffsetForDocumentMark(final int index) {
099: if (index == 0 || index < gapStart) {
100: return index;
101: }
102: return index - (gapEnd - gapStart);
103: }
104: }
105:
106: private static final int DEFAULT_SIZE = 10;
107: private static final int MININIMUM_SIZE = 2;
108:
109: private char[] array;
110: private int gapEnd;
111: private int gapStart;
112: private transient GapContentPositions gapContentPositions;
113:
114: private transient Segment textBuffer;
115:
116: public GapContent() {
117: this (DEFAULT_SIZE);
118: }
119:
120: public GapContent(final int initialLength) {
121: int length = initialLength;
122: if (length < MININIMUM_SIZE) {
123: length = MININIMUM_SIZE;
124: }
125: array = (char[]) allocateArray(length);
126:
127: // Put the implied character into the storage
128: array[length - 1] = '\n';
129: gapEnd = length - 1;
130:
131: initTransientFields();
132: }
133:
134: public Position createPosition(final int offset)
135: throws BadLocationException {
136:
137: return gapContentPositions.createPosition(offset);
138: }
139:
140: public void getChars(final int offset, final int length,
141: final Segment chars) throws BadLocationException {
142:
143: if (length < 0) {
144: throw new BadLocationException(Messages
145: .getString("swing.8C"), //$NON-NLS-1$
146: length);
147: }
148: if (offset < 0 || length > length() - offset) {
149: throw new BadLocationException(Messages
150: .getString("swing.8D"), offset); //$NON-NLS-1$
151: }
152:
153: if (offset + length <= gapStart) {
154: // The whole portion requested is before the gap
155: chars.array = array;
156: chars.offset = offset;
157: chars.count = length;
158: } else if (offset < gapStart) {
159: // The gap is in the middle of the portion requested
160: if (chars.isPartialReturn()) {
161: chars.array = array;
162: chars.offset = offset;
163: chars.count = gapStart - offset;
164: } else {
165: char[] result = new char[length];
166: int beforeGapLen = gapStart - offset;
167: int afterGapLen = length - beforeGapLen;
168:
169: System
170: .arraycopy(array, offset, result, 0,
171: beforeGapLen);
172: System.arraycopy(array, gapEnd, result, beforeGapLen,
173: afterGapLen);
174:
175: chars.array = result;
176: chars.offset = 0;
177: chars.count = length;
178: }
179: } else {
180: // where is somewhere in the gap or after it
181: chars.array = array;
182: chars.offset = offset + (gapEnd - gapStart);
183: chars.count = length;
184: }
185: }
186:
187: public String getString(final int offset, final int length)
188: throws BadLocationException {
189:
190: getChars(offset, length, textBuffer);
191: return textBuffer.toString();
192: }
193:
194: public UndoableEdit insertString(final int offset, final String str)
195: throws BadLocationException {
196:
197: insertItems(offset, str.toCharArray(), str.length());
198: return new GapContentEdit(offset, str, true);
199: }
200:
201: public int length() {
202: return getArrayLength() - (gapEnd - gapStart);
203: }
204:
205: public UndoableEdit remove(final int offset, final int nitems)
206: throws BadLocationException {
207:
208: GapContentEdit de = new GapContentEdit(offset, getString(
209: offset, nitems), false);
210: removeItems(offset, nitems);
211:
212: return de;
213: }
214:
215: protected Object allocateArray(final int len) {
216: return new char[len];
217: }
218:
219: protected final Object getArray() {
220: return array;
221: }
222:
223: protected int getArrayLength() {
224: return array.length;
225: }
226:
227: /**
228: * Returns the index of the first character right after the gap.
229: */
230: protected final int getGapEnd() {
231: return gapEnd;
232: }
233:
234: /**
235: * Returns the index of the first character in the gap.
236: */
237: protected final int getGapStart() {
238: return gapStart;
239: }
240:
241: /**
242: * This method returns a vector with instances of UndoPosRef (inner class)
243: * which store information to restore position offset after undo/redo.
244: */
245: protected Vector getPositionsInRange(final Vector vector,
246: final int offset, final int len) {
247:
248: return gapContentPositions.getPositionsInRange(vector, offset,
249: len);
250: }
251:
252: protected void replace(final int position, final int rmSize,
253: final Object addItems, final int addSize) {
254: try {
255: removeItems(position, rmSize);
256: insertItems(position, addItems, addSize);
257: } catch (BadLocationException e) {
258: }
259: }
260:
261: protected void resetMarksAtZero() {
262: gapContentPositions.deletePositions();
263:
264: if (gapStart > 0) {
265: return;
266: }
267:
268: for (int i = 0; i < gapContentPositions.positionList.size(); i++) {
269: DocumentMark dm = (DocumentMark) gapContentPositions.positionList
270: .get(i);
271:
272: if (dm.index <= gapEnd) {
273: dm.index = 0;
274: } else if (dm.index > gapEnd) {
275: break;
276: }
277: }
278: }
279:
280: protected void shiftEnd(final int newSize) {
281: final Object oldArray = array;
282: final int len = getArrayLength();
283: final int oldStart = gapStart;
284: final int oldEnd = gapEnd;
285: final int oldEndOff = len - oldEnd;
286:
287: array = (char[]) allocateArray((newSize << 1) + 2);
288: final int sizeDiff = array.length - len;
289:
290: gapStart = oldStart;
291: gapEnd = getArrayLength() - oldEndOff;
292:
293: System.arraycopy(oldArray, 0, array, 0, oldStart);
294: System.arraycopy(oldArray, oldEnd, array, gapEnd, oldEndOff);
295:
296: gapContentPositions.deletePositions();
297: gapContentPositions.moveMarkIndexes(oldStart, -1, sizeDiff);
298: }
299:
300: protected void shiftGap(final int newGapStart) {
301: if (newGapStart == gapStart) {
302: return;
303: }
304:
305: final int gapSize = gapEnd - gapStart;
306: final int oldGapStart = gapStart;
307: final int oldGapEnd = gapEnd;
308: final int newGapEnd = newGapStart + gapSize;
309: final int gapDiff = gapStart - newGapStart;
310:
311: // Move items affected and adjust the gap position
312: if (newGapStart < gapStart) {
313: System.arraycopy(array, newGapStart, array, gapEnd
314: - gapDiff, gapDiff);
315: } else {
316: System.arraycopy(array, gapEnd, array, gapStart, -gapDiff);
317: }
318: gapStart = newGapStart;
319: gapEnd -= gapDiff;
320:
321: gapContentPositions.deletePositions();
322: if (newGapStart < oldGapStart) { // This is shift left
323: gapContentPositions.moveMarkIndexes(newGapStart,
324: oldGapStart, gapSize);
325: } else {
326: gapContentPositions.moveMarkIndexes(oldGapEnd,
327: newGapEnd - 1, -gapSize);
328: }
329: gapContentPositions.resetMarksAtZero();
330: }
331:
332: protected void shiftGapEndUp(final int newGapEnd) {
333: gapContentPositions.deletePositions();
334: gapContentPositions
335: .setMarkIndexes(gapEnd, newGapEnd, newGapEnd);
336:
337: gapEnd = newGapEnd;
338:
339: gapContentPositions.resetMarksAtZero();
340: }
341:
342: protected void shiftGapStartDown(final int newGapStart) {
343: gapContentPositions.deletePositions();
344: gapContentPositions.setMarkIndexes(newGapStart, gapStart,
345: gapEnd);
346:
347: gapStart = newGapStart;
348:
349: gapContentPositions.resetMarksAtZero();
350: }
351:
352: /**
353: * Restores offset of positions that fall into the range. It is used by
354: * Undo/Redo implementation (DocumentEdit inner class).
355: * The <code>vector</code> parameter is the vector returned by
356: * <code>getPositionsInRange</code> method.
357: */
358: protected void updateUndoPositions(final Vector vector,
359: final int offset, final int len) {
360:
361: gapContentPositions.updateUndoPositions(vector);
362: }
363:
364: private void initTransientFields() {
365: textBuffer = new Segment();
366: gapContentPositions = new GapContentPositions();
367: }
368:
369: final void insertItems(final int where, final Object addItems,
370: final int addSize) throws BadLocationException {
371:
372: if (addSize == 0) {
373: return;
374: }
375:
376: if (where < 0 || where > length()) {
377: throw new BadLocationException(Messages
378: .getString("swing.8E"), where); //$NON-NLS-1$
379: }
380:
381: shiftGap(where);
382: ensureCapacity(addSize);
383:
384: System.arraycopy(addItems, 0, array, gapStart, addSize);
385: gapStart += addSize;
386: }
387:
388: private void ensureCapacity(final int sizeRequired) {
389: int gapSize = gapEnd - gapStart;
390: if (sizeRequired >= gapSize) {
391: shiftEnd(length() + sizeRequired);
392: }
393: }
394:
395: private void readObject(final ObjectInputStream ois)
396: throws IOException, ClassNotFoundException {
397:
398: ois.defaultReadObject();
399:
400: initTransientFields();
401: }
402:
403: final void removeItems(final int where, final int nitems)
404: throws BadLocationException {
405:
406: if (where < 0 || where + nitems >= length()) {
407:
408: throw new BadLocationException(Messages
409: .getString("swing.7F"), where); //$NON-NLS-1$
410: }
411:
412: if (nitems == 0) {
413: return;
414: }
415:
416: if (where + nitems == gapStart) {
417: shiftGapStartDown(where);
418: } else {
419: shiftGap(where);
420: shiftGapEndUp(gapEnd + nitems);
421: }
422: }
423:
424: private void writeObject(final ObjectOutputStream oos)
425: throws IOException {
426: oos.defaultWriteObject();
427: }
428: }
|