1 /* StringContent.java --
2    Copyright (C) 2005 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.util.Iterator;
43 import java.util.Vector;
44 
45 import javax.swing.undo.AbstractUndoableEdit;
46 import javax.swing.undo.CannotRedoException;
47 import javax.swing.undo.CannotUndoException;
48 import javax.swing.undo.UndoableEdit;
49 
50 /**
51  * An implementation of the <code>AbstractDocument.Content</code>
52  * interface useful for small documents or debugging. The character
53  * content is a simple character array. It's not really efficient.
54  *
55  * <p>Do not use this class for large size.</p>
56  */
57 public final class StringContent implements AbstractDocument.Content, Serializable
58 {
59   /** The serialization UID (compatible with JDK1.5). */
60   private static final long serialVersionUID = 4755994433709540381L;
61 
62   // This is package-private to avoid an accessor method.
63   char[] content;
64 
65   private int count;
66 
67   private Vector positions = new Vector();
68 
69   private class InsertUndo extends AbstractUndoableEdit
70   {
71     private int start;
72 
73     private int length;
74 
75     private String redoContent;
76 
InsertUndo(int start, int length)77     public InsertUndo(int start, int length)
78     {
79       super();
80       this.start = start;
81       this.length = length;
82     }
83 
undo()84     public void undo()
85     {
86       super.undo();
87       try
88         {
89           StringContent.this.checkLocation(this.start, this.length);
90           this.redoContent = new String(StringContent.this.content, this.start, this.length);
91           StringContent.this.remove(this.start, this.length);
92         }
93       catch (BadLocationException b)
94         {
95           throw new CannotUndoException();
96         }
97     }
98 
redo()99     public void redo()
100     {
101       super.redo();
102       try
103         {
104           StringContent.this.insertString(this.start, this.redoContent);
105         }
106       catch (BadLocationException b)
107         {
108           throw new CannotRedoException();
109         }
110     }
111   }
112 
113   private class RemoveUndo extends AbstractUndoableEdit
114   {
115     private int start;
116 
117     private String undoString;
118 
RemoveUndo(int start, String str)119     public RemoveUndo(int start, String str)
120     {
121       super();
122       this.start = start;
123       this.undoString = str;
124     }
125 
undo()126     public void undo()
127     {
128       super.undo();
129       try
130         {
131           StringContent.this.insertString(this.start, this.undoString);
132         }
133       catch (BadLocationException bad)
134         {
135           throw new CannotUndoException();
136         }
137     }
138 
redo()139     public void redo()
140     {
141       super.redo();
142       try
143         {
144           int end = this.undoString.length();
145           StringContent.this.remove(this.start, end);
146         }
147       catch (BadLocationException bad)
148         {
149           throw new CannotRedoException();
150         }
151     }
152   }
153 
154   private class StickyPosition implements Position
155   {
156     private int offset = -1;
157 
StickyPosition(int offset)158     public StickyPosition(int offset)
159     {
160       this.offset = offset;
161     }
162 
163     // This is package-private to avoid an accessor method.
setOffset(int offset)164     void setOffset(int offset)
165     {
166       this.offset = this.offset >= 0 ? offset : -1;
167     }
168 
169     /**
170      * Should be >=0.
171      */
getOffset()172     public int getOffset()
173     {
174       return offset < 0 ? 0 : offset;
175     }
176   }
177 
StringContent()178   public StringContent()
179   {
180     this(1);
181   }
182 
StringContent(int initialLength)183   public StringContent(int initialLength)
184   {
185     super();
186     if (initialLength < 1)
187       initialLength = 1;
188     this.content = new char[initialLength];
189     this.content[0] = '\n';
190     this.count = 1;
191   }
192 
getPositionsInRange(Vector v, int offset, int length)193   protected Vector getPositionsInRange(Vector v,
194                                        int offset,
195                                        int length)
196   {
197     Vector refPos = new Vector();
198     Iterator iter = this.positions.iterator();
199     while(iter.hasNext())
200       {
201         Position p = (Position)iter.next();
202         if ((offset <= p.getOffset())
203             && (p.getOffset() <= (offset + length)))
204           refPos.add(p);
205       }
206     return refPos;
207   }
208 
createPosition(int offset)209   public Position createPosition(int offset) throws BadLocationException
210   {
211     if (offset < this.count || offset > this.count)
212       checkLocation(offset, 0);
213     StickyPosition sp = new StickyPosition(offset);
214     this.positions.add(sp);
215     return sp;
216   }
217 
length()218   public int length()
219   {
220     return this.count;
221   }
222 
insertString(int where, String str)223   public UndoableEdit insertString(int where, String str)
224     throws BadLocationException
225   {
226     checkLocation(where, 0);
227     if (where == this.count)
228       throw new BadLocationException("Invalid location", 1);
229     if (str == null)
230       throw new NullPointerException();
231     char[] insert = str.toCharArray();
232     char[] temp = new char[this.content.length + insert.length];
233     this.count += insert.length;
234     // Copy array and insert the string.
235     if (where > 0)
236       System.arraycopy(this.content, 0, temp, 0, where);
237     System.arraycopy(insert, 0, temp, where, insert.length);
238     System.arraycopy(this.content, where, temp, (where + insert.length), (temp.length - where - insert.length));
239     if (this.content.length < temp.length)
240       this.content = new char[temp.length];
241     // Copy the result in the original char array.
242     System.arraycopy(temp, 0, this.content, 0, temp.length);
243     // Move all the positions.
244     Vector refPos = getPositionsInRange(this.positions, where, temp.length - where);
245     Iterator iter = refPos.iterator();
246     while (iter.hasNext())
247       {
248         StickyPosition p = (StickyPosition)iter.next();
249         p.setOffset(p.getOffset() + str.length());
250       }
251     InsertUndo iundo = new InsertUndo(where, insert.length);
252     return iundo;
253   }
254 
remove(int where, int nitems)255   public UndoableEdit remove(int where, int nitems) throws BadLocationException
256   {
257     checkLocation(where, nitems);
258     char[] temp = new char[(this.content.length - nitems)];
259     this.count = this.count - nitems;
260     RemoveUndo rundo = new RemoveUndo(where, new String(this.content, where, nitems));
261     // Copy array.
262     System.arraycopy(this.content, 0, temp, 0, where);
263     System.arraycopy(this.content, where + nitems, temp, where, this.content.length - where - nitems);
264     this.content = new char[temp.length];
265     // Then copy the result in the original char array.
266     System.arraycopy(temp, 0, this.content, 0, this.content.length);
267     // Move all the positions.
268     Vector refPos = getPositionsInRange(this.positions, where, this.content.length + nitems - where);
269     Iterator iter = refPos.iterator();
270     while (iter.hasNext())
271       {
272         StickyPosition p = (StickyPosition)iter.next();
273         int result = p.getOffset() - nitems;
274         p.setOffset(result);
275         if (result < 0)
276           this.positions.remove(p);
277       }
278     return rundo;
279   }
280 
getString(int where, int len)281   public String getString(int where, int len) throws BadLocationException
282   {
283     checkLocation(where, len);
284     return new String (this.content, where, len);
285   }
286 
getChars(int where, int len, Segment txt)287   public void getChars(int where, int len, Segment txt) throws BadLocationException
288   {
289     checkLocation(where, len);
290     if (txt != null)
291       {
292         txt.array = this.content;
293         txt.offset = where;
294         txt.count = len;
295       }
296   }
297 
298   // This is package-private to avoid an accessor method.
checkLocation(int where, int len)299   void checkLocation(int where, int len) throws BadLocationException
300   {
301     if (where < 0)
302       throw new BadLocationException("Invalid location", 1);
303     else if (where > this.count)
304       throw new BadLocationException("Invalid location", this.count);
305     else if ((where + len)>this.count)
306       throw new BadLocationException("Invalid range", this.count);
307   }
308 
309 }
310 
311