OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [javax/] [swing/] [text/] [StringContent.java] - Blame information for rev 772

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 772 jeremybenn
/* StringContent.java --
2
   Copyright (C) 2005, 2006 Free Software Foundation, Inc.
3
 
4
This file is part of GNU Classpath.
5
 
6
GNU Classpath is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2, or (at your option)
9
any later version.
10
 
11
GNU Classpath is distributed in the hope that it will be useful, but
12
WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GNU Classpath; see the file COPYING.  If not, write to the
18
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301 USA.
20
 
21
Linking this library statically or dynamically with other modules is
22
making a combined work based on this library.  Thus, the terms and
23
conditions of the GNU General Public License cover the whole
24
combination.
25
 
26
As a special exception, the copyright holders of this library give you
27
permission to link this library with independent modules to produce an
28
executable, regardless of the license terms of these independent
29
modules, and to copy and distribute the resulting executable under
30
terms of your choice, provided that you also meet, for each linked
31
independent module, the terms and conditions of the license of that
32
module.  An independent module is a module which is not derived from
33
or based on this library.  If you modify this library, you may extend
34
this exception to your version of the library, but you are not
35
obligated to do so.  If you do not wish to do so, delete this
36
exception statement from your version. */
37
 
38
 
39
package javax.swing.text;
40
 
41
import java.io.Serializable;
42
import java.lang.ref.Reference;
43
import java.lang.ref.ReferenceQueue;
44
import java.lang.ref.WeakReference;
45
import java.util.Iterator;
46
import java.util.Vector;
47
 
48
import javax.swing.undo.AbstractUndoableEdit;
49
import javax.swing.undo.CannotRedoException;
50
import javax.swing.undo.CannotUndoException;
51
import javax.swing.undo.UndoableEdit;
52
 
53
/**
54
 * An implementation of the <code>AbstractDocument.Content</code>
55
 * interface useful for small documents or debugging. The character
56
 * content is a simple character array. It's not really efficient.
57
 *
58
 * <p>Do not use this class for large size.</p>
59
 */
60
public final class StringContent
61
  implements AbstractDocument.Content, Serializable
62
{
63
  /**
64
   * Stores a reference to a mark that can be resetted to the original value
65
   * after a mark has been moved. This is used for undoing actions.
66
   */
67
  private class UndoPosRef
68
  {
69
    /**
70
     * The mark that might need to be reset.
71
     */
72
    private Mark mark;
73
 
74
    /**
75
     * The original offset to reset the mark to.
76
     */
77
    private int undoOffset;
78
 
79
    /**
80
     * Creates a new UndoPosRef.
81
     *
82
     * @param m the mark
83
     */
84
    UndoPosRef(Mark m)
85
    {
86
      mark = m;
87
      undoOffset = mark.mark;
88
    }
89
 
90
    /**
91
     * Resets the position of the mark to the value that it had when
92
     * creating this UndoPosRef.
93
     */
94
    void reset()
95
    {
96
      mark.mark = undoOffset;
97
    }
98
  }
99
 
100
  /**
101
   * Holds a mark into the buffer that is used by StickyPosition to find
102
   * the actual offset of the position. This is pulled out of the
103
   * GapContentPosition object so that the mark and position can be handled
104
   * independently, and most important, so that the StickyPosition can
105
   * be garbage collected while we still hold a reference to the Mark object.
106
   */
107
  private class Mark
108
  {
109
    /**
110
     * The actual mark into the buffer.
111
     */
112
    int mark;
113
 
114
 
115
    /**
116
     * The number of GapContentPosition object that reference this mark. If
117
     * it reaches zero, it get's deleted by
118
     * {@link StringContent#garbageCollect()}.
119
     */
120
    int refCount;
121
 
122
    /**
123
     * Creates a new Mark object for the specified offset.
124
     *
125
     * @param offset the offset
126
     */
127
    Mark(int offset)
128
    {
129
      mark = offset;
130
    }
131
  }
132
 
133
  /** The serialization UID (compatible with JDK1.5). */
134
  private static final long serialVersionUID = 4755994433709540381L;
135
 
136
  // This is package-private to avoid an accessor method.
137
  char[] content;
138
 
139
  private int count;
140
 
141
  /**
142
   * Holds the marks for the positions.
143
   *
144
   * This is package private to avoid accessor methods.
145
   */
146
  Vector marks;
147
 
148
  private class InsertUndo extends AbstractUndoableEdit
149
  {
150
    private int start;
151
 
152
    private int length;
153
 
154
    private String redoContent;
155
 
156
    private Vector positions;
157
 
158
    public InsertUndo(int start, int length)
159
    {
160
      super();
161
      this.start = start;
162
      this.length = length;
163
    }
164
 
165
    public void undo()
166
    {
167
      super.undo();
168
      try
169
        {
170
          if (marks != null)
171
            positions = getPositionsInRange(null, start, length);
172
          redoContent = getString(start, length);
173
          remove(start, length);
174
        }
175
      catch (BadLocationException b)
176
        {
177
          throw new CannotUndoException();
178
        }
179
    }
180
 
181
    public void redo()
182
    {
183
      super.redo();
184
      try
185
        {
186
          insertString(start, redoContent);
187
          redoContent = null;
188
          if (positions != null)
189
            {
190
              updateUndoPositions(positions);
191
              positions = null;
192
            }
193
        }
194
      catch (BadLocationException b)
195
        {
196
          throw new CannotRedoException();
197
        }
198
    }
199
  }
200
 
201
  private class RemoveUndo extends AbstractUndoableEdit
202
  {
203
    private int start;
204
    private int len;
205
    private String undoString;
206
 
207
    Vector positions;
208
 
209
    public RemoveUndo(int start, String str)
210
    {
211
      super();
212
      this.start = start;
213
      len = str.length();
214
      this.undoString = str;
215
      if (marks != null)
216
        positions = getPositionsInRange(null, start, str.length());
217
    }
218
 
219
    public void undo()
220
    {
221
      super.undo();
222
      try
223
        {
224
          StringContent.this.insertString(this.start, this.undoString);
225
          if (positions != null)
226
            {
227
              updateUndoPositions(positions);
228
              positions = null;
229
            }
230
          undoString = null;
231
        }
232
      catch (BadLocationException bad)
233
        {
234
          throw new CannotUndoException();
235
        }
236
    }
237
 
238
    public void redo()
239
    {
240
      super.redo();
241
      try
242
        {
243
          undoString = getString(start, len);
244
          if (marks != null)
245
            positions = getPositionsInRange(null, start, len);
246
          remove(this.start, len);
247
        }
248
      catch (BadLocationException bad)
249
        {
250
          throw new CannotRedoException();
251
        }
252
    }
253
  }
254
 
255
  private class StickyPosition implements Position
256
  {
257
    Mark mark;
258
 
259
    public StickyPosition(int offset)
260
    {
261
      // Try to make space.
262
      garbageCollect();
263
 
264
      mark = new Mark(offset);
265
      mark.refCount++;
266
      marks.add(mark);
267
 
268
      new WeakReference(this, queueOfDeath);
269
    }
270
 
271
    /**
272
     * Should be >=0.
273
     */
274
    public int getOffset()
275
    {
276
      return mark.mark;
277
    }
278
  }
279
 
280
  /**
281
   * Used in {@link #remove(int,int)}.
282
   */
283
  private static final char[] EMPTY = new char[0];
284
 
285
  /**
286
   * Queues all references to GapContentPositions that are about to be
287
   * GC'ed. This is used to remove the corresponding marks from the
288
   * positionMarks array if the number of references to that mark reaches zero.
289
   *
290
   * This is package private to avoid accessor synthetic methods.
291
   */
292
  ReferenceQueue queueOfDeath;
293
 
294
  /**
295
   * Creates a new instance containing the string "\n".  This is equivalent
296
   * to calling {@link #StringContent(int)} with an <code>initialLength</code>
297
   * of 10.
298
   */
299
  public StringContent()
300
  {
301
    this(10);
302
  }
303
 
304
  /**
305
   * Creates a new instance containing the string "\n".
306
   *
307
   * @param initialLength  the initial length of the underlying character
308
   *                       array used to store the content.
309
   */
310
  public StringContent(int initialLength)
311
  {
312
    super();
313
    queueOfDeath = new ReferenceQueue();
314
    if (initialLength < 1)
315
      initialLength = 1;
316
    this.content = new char[initialLength];
317
    this.content[0] = '\n';
318
    this.count = 1;
319
  }
320
 
321
  protected Vector getPositionsInRange(Vector v,
322
                                       int offset,
323
                                       int length)
324
  {
325
    Vector refPos = v == null ? new Vector() : v;
326
    Iterator iter = marks.iterator();
327
    while(iter.hasNext())
328
      {
329
        Mark m = (Mark) iter.next();
330
        if (offset <= m.mark && m.mark <= offset + length)
331
          refPos.add(new UndoPosRef(m));
332
      }
333
    return refPos;
334
  }
335
 
336
  /**
337
   * Creates a position reference for the character at the given offset.  The
338
   * position offset will be automatically updated when new characters are
339
   * inserted into or removed from the content.
340
   *
341
   * @param offset  the character offset.
342
   *
343
   * @throws BadLocationException if offset is outside the bounds of the
344
   *         content.
345
   */
346
  public Position createPosition(int offset) throws BadLocationException
347
  {
348
    // Lazily create marks vector.
349
    if (marks == null)
350
      marks = new Vector();
351
    StickyPosition sp = new StickyPosition(offset);
352
    return sp;
353
  }
354
 
355
  /**
356
   * Returns the length of the string content, including the '\n' character at
357
   * the end.
358
   *
359
   * @return The length of the string content.
360
   */
361
  public int length()
362
  {
363
    return count;
364
  }
365
 
366
  /**
367
   * Inserts <code>str</code> at the given position and returns an
368
   * {@link UndoableEdit} that enables undo/redo support.
369
   *
370
   * @param where  the insertion point (must be less than
371
   *               <code>length()</code>).
372
   * @param str  the string to insert (<code>null</code> not permitted).
373
   *
374
   * @return An object that can undo the insertion.
375
   */
376
  public UndoableEdit insertString(int where, String str)
377
    throws BadLocationException
378
  {
379
    checkLocation(where, 0);
380
    if (where == this.count)
381
      throw new BadLocationException("Invalid location", 1);
382
    if (str == null)
383
      throw new NullPointerException();
384
    char[] insert = str.toCharArray();
385
    replace(where, 0, insert);
386
 
387
    // Move all the positions.
388
    if (marks != null)
389
      {
390
        Iterator iter = marks.iterator();
391
        int start = where;
392
        if (start == 0)
393
          start = 1;
394
        while (iter.hasNext())
395
          {
396
            Mark m = (Mark) iter.next();
397
            if (m.mark >= start)
398
              m.mark += str.length();
399
          }
400
      }
401
 
402
    InsertUndo iundo = new InsertUndo(where, insert.length);
403
    return iundo;
404
  }
405
 
406
  /**
407
   * Removes the specified range of characters and returns an
408
   * {@link UndoableEdit} that enables undo/redo support.
409
   *
410
   * @param where  the starting index.
411
   * @param nitems  the number of characters.
412
   *
413
   * @return An object that can undo the removal.
414
   *
415
   * @throws BadLocationException if the character range extends outside the
416
   *         bounds of the content OR includes the last character.
417
   */
418
  public UndoableEdit remove(int where, int nitems) throws BadLocationException
419
  {
420
    checkLocation(where, nitems + 1);
421
    RemoveUndo rundo = new RemoveUndo(where, new String(this.content, where,
422
        nitems));
423
 
424
    replace(where, nitems, EMPTY);
425
    // Move all the positions.
426
    if (marks != null)
427
      {
428
        Iterator iter = marks.iterator();
429
        while (iter.hasNext())
430
          {
431
            Mark m = (Mark) iter.next();
432
            if (m.mark >= where + nitems)
433
              m.mark -= nitems;
434
            else if (m.mark >= where)
435
              m.mark = where;
436
          }
437
      }
438
    return rundo;
439
  }
440
 
441
  private void replace(int offs, int numRemove, char[] insert)
442
  {
443
    int insertLength = insert.length;
444
    int delta = insertLength - numRemove;
445
    int src = offs + numRemove;
446
    int numMove = count - src;
447
    int dest = src + delta;
448
    if (count + delta >= content.length)
449
      {
450
        // Grow data array.
451
        int newLength = Math.max(2 * content.length, count + delta);
452
        char[] newContent = new char[newLength];
453
        System.arraycopy(content, 0, newContent, 0, offs);
454
        System.arraycopy(insert, 0, newContent, offs, insertLength);
455
        System.arraycopy(content, src, newContent, dest, numMove);
456
        content = newContent;
457
      }
458
    else
459
      {
460
        System.arraycopy(content, src, content, dest, numMove);
461
        System.arraycopy(insert, 0, content, offs, insertLength);
462
      }
463
    count += delta;
464
  }
465
 
466
  /**
467
   * Returns a new <code>String</code> containing the characters in the
468
   * specified range.
469
   *
470
   * @param where  the start index.
471
   * @param len  the number of characters.
472
   *
473
   * @return A string.
474
   *
475
   * @throws BadLocationException if the requested range of characters extends
476
   *         outside the bounds of the content.
477
   */
478
  public String getString(int where, int len) throws BadLocationException
479
  {
480
    // The RI throws a StringIndexOutOfBoundsException here, which
481
    // smells like a bug. We throw a BadLocationException instead.
482
    checkLocation(where, len);
483
    return new String(this.content, where, len);
484
  }
485
 
486
  /**
487
   * Updates <code>txt</code> to contain a direct reference to the underlying
488
   * character array.
489
   *
490
   * @param where  the index of the first character.
491
   * @param len  the number of characters.
492
   * @param txt  a carrier for the return result (<code>null</code> not
493
   *             permitted).
494
   *
495
   * @throws BadLocationException if the requested character range is not
496
   *                              within the bounds of the content.
497
   * @throws NullPointerException if <code>txt</code> is <code>null</code>.
498
   */
499
  public void getChars(int where, int len, Segment txt)
500
    throws BadLocationException
501
  {
502
    if (where + len > count)
503
      throw new BadLocationException("Invalid location", where + len);
504
    txt.array = content;
505
    txt.offset = where;
506
    txt.count = len;
507
  }
508
 
509
 
510
  /**
511
   * Resets the positions in the specified vector to their original offset
512
   * after a undo operation is performed. For example, after removing some
513
   * content, the positions in the removed range will all be set to one
514
   * offset. This method restores the positions to their original offsets
515
   * after an undo.
516
   */
517
  protected void updateUndoPositions(Vector positions)
518
  {
519
    for (Iterator i = positions.iterator(); i.hasNext();)
520
      {
521
        UndoPosRef pos = (UndoPosRef) i.next();
522
        pos.reset();
523
      }
524
  }
525
 
526
  /**
527
   * A utility method that checks the validity of the specified character
528
   * range.
529
   *
530
   * @param where  the first character in the range.
531
   * @param len  the number of characters in the range.
532
   *
533
   * @throws BadLocationException if the specified range is not within the
534
   *         bounds of the content.
535
   */
536
  void checkLocation(int where, int len) throws BadLocationException
537
  {
538
    if (where < 0)
539
      throw new BadLocationException("Invalid location", 1);
540
    else if (where > this.count)
541
      throw new BadLocationException("Invalid location", this.count);
542
    else if ((where + len) > this.count)
543
      throw new BadLocationException("Invalid range", this.count);
544
  }
545
 
546
  /**
547
   * Polls the queue of death for GapContentPositions, updates the
548
   * corresponding reference count and removes the corresponding mark
549
   * if the refcount reaches zero.
550
   *
551
   * This is package private to avoid accessor synthetic methods.
552
   */
553
  void garbageCollect()
554
  {
555
    Reference ref = queueOfDeath.poll();
556
    while (ref != null)
557
      {
558
        if (ref != null)
559
          {
560
            StickyPosition pos = (StickyPosition) ref.get();
561
            Mark m = pos.mark;
562
            m.refCount--;
563
            if (m.refCount == 0)
564
              marks.remove(m);
565
          }
566
        ref = queueOfDeath.poll();
567
      }
568
  }
569
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.