001: /*BEGIN_COPYRIGHT_BLOCK
002: *
003: * Copyright (c) 2001-2007, JavaPLT group at Rice University (javaplt@rice.edu)
004: * All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions are met:
008: * * Redistributions of source code must retain the above copyright
009: * notice, this list of conditions and the following disclaimer.
010: * * Redistributions in binary form must reproduce the above copyright
011: * notice, this list of conditions and the following disclaimer in the
012: * documentation and/or other materials provided with the distribution.
013: * * Neither the names of DrJava, the JavaPLT group, Rice University, nor the
014: * names of its contributors may be used to endorse or promote products
015: * derived from this software without specific prior written permission.
016: *
017: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
018: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
019: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
020: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
021: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
022: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
023: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
024: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
025: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
026: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: *
029: * This software is Open Source Initiative approved Open Source Software.
030: * Open Source Initative Approved is a trademark of the Open Source Initiative.
031: *
032: * This file is part of DrJava. Download the current version of this project
033: * from http://www.drjava.org/ or http://sourceforge.net/projects/drjava/
034: *
035: * END_COPYRIGHT_BLOCK*/
036:
037: package edu.rice.cs.util.text;
038:
039: import edu.rice.cs.util.UnexpectedException;
040: import static edu.rice.cs.util.text.AbstractDocumentInterface.*;
041:
042: import java.awt.print.Pageable;
043:
044: import javax.swing.text.DefaultStyledDocument;
045: import javax.swing.text.AttributeSet;
046: import javax.swing.text.Position;
047: import javax.swing.text.BadLocationException;
048:
049: import java.util.Hashtable;
050:
051: /** A swing implementation of the toolkit-independent EditDocumentInterface. This document must use the readers/writers
052: * locking protocol established in its superclasses.
053: * TODO: create a separate DummySwingDocument class for testing and make SwingDocument abstract.
054: * @version $Id: SwingDocument.java 4255 2007-08-28 19:17:37Z mgricken $
055: */
056: public class SwingDocument extends DefaultStyledDocument implements
057: EditDocumentInterface, AbstractDocumentInterface {
058:
059: // /** The lock state. See ReadersWritersLocking interface for documentation. */
060: // private volatile int _lockState = UNLOCKED;
061:
062: /** Maps names to attribute sets */
063: final protected Hashtable<String, AttributeSet> _styles;
064:
065: /** Determines which edits are legal on this document. */
066: protected DocumentEditCondition _condition;
067:
068: /** Lock used to protect _wrappedPosListLock in DefinitionsDocument. Placed here to ensure that it initialized before
069: * use! */
070: protected static final Object _wrappedPosListLock = new Object();
071:
072: /** Creates a new document adapter for a Swing StyledDocument. TODO: convert _styles and _condition to lazily
073: * initialized volatiles as soon as support for Java 1.4 is dropped and the double-check idiom is safe. */
074: public SwingDocument() {
075: _styles = new Hashtable<String, AttributeSet>();
076: _condition = new DocumentEditCondition();
077: }
078:
079: /** Adds the given AttributeSet as a style with the given name. It can then be used in insertString.
080: * @param name Name of the style, to be passed to insertString
081: * @param s AttributeSet to use for the style
082: */
083: public void setDocStyle(String name, AttributeSet s) {
084: _styles.put(name, s); // no locking necessary: _styles is final and Hashtable is thread-safe
085: }
086:
087: /** Returns the style with the given name, or null if no such named style exists. */
088: public AttributeSet getDocStyle(String name) {
089: return _styles.get(name); // no locking necessary: _styles is final and Hashtable is thread-safe
090: }
091:
092: /** Adds the given coloring style to the styles list. Not supported in SwingDocument. */
093: public void addColoring(int start, int end, String style) {
094: }
095:
096: /** Gets the object which can determine whether an insert or remove edit should be applied, based on the inputs.
097: * @return an Object to determine legality of inputs
098: */
099: public DocumentEditCondition getEditCondition() {
100: return _condition;
101: }
102:
103: /** Provides an object which can determine whether an insert or remove edit should be applied, based on the inputs.
104: * @param condition Object to determine legality of inputs
105: */
106: public void setEditCondition(DocumentEditCondition condition) {
107: acquireWriteLock();
108: try {
109: _condition = condition;
110: } finally {
111: releaseWriteLock();
112: }
113: }
114:
115: /* Clears the document. */
116: public void clear() {
117: acquireWriteLock();
118: try {
119: remove(0, getLength());
120: } catch (BadLocationException e) {
121: throw new UnexpectedException(e);
122: } finally {
123: releaseWriteLock();
124: }
125: }
126:
127: /** Inserts a string into the document at the given offset and style, if the edit condition allows it.
128: * @param offs Offset into the document
129: * @param str String to be inserted
130: * @param style Name of the style to use. Must have been added using addStyle.
131: * @throws EditDocumentException if the offset is illegal
132: */
133: public void insertText(int offs, String str, String style) {
134: acquireWriteLock();
135: try {
136: _insertText(offs, str, style);
137: } finally {
138: releaseWriteLock();
139: }
140: }
141:
142: public void _insertText(int offs, String str, String style) {
143: if (_condition.canInsertText(offs))
144: _forceInsertText(offs, str, style);
145: }
146:
147: /** Behaves exactly like forceInsertText except for assuming that WriteLock is already held. */
148: public void _forceInsertText(int offs, String str, String style) {
149: int len = getLength();
150: if ((offs < 0) || (offs > len)) {
151: String msg = "Offset "
152: + offs
153: + " passed to SwingDocument.forceInsertText is out of bounds [0, "
154: + len + "]";
155: throw new EditDocumentException(null, msg);
156: }
157: AttributeSet s = null;
158: if (style != null)
159: s = getDocStyle(style);
160: try {
161: super .insertString(offs, str, s);
162: } catch (BadLocationException e) {
163: throw new EditDocumentException(e);
164: }
165: }
166:
167: /** Inserts a string into the document at the given offset and style, regardless of the edit condition.
168: * @param offs Offset into the document
169: * @param str String to be inserted
170: * @param style Name of the style to use. Must have been added using addStyle.
171: * @throws EditDocumentException if the offset is illegal
172: */
173: public void forceInsertText(int offs, String str, String style) {
174: acquireWriteLock();
175: try {
176: _forceInsertText(offs, str, style);
177: } finally {
178: releaseWriteLock();
179: }
180: }
181:
182: /** Overrides superclass's insertString to impose the edit condition. The AttributeSet is ignored in the condition,
183: * which sees a null style name.
184: */
185: public void insertString(int offs, String str, AttributeSet set)
186: throws BadLocationException {
187: acquireWriteLock(); // locking is used to make the test and modification atomic
188: try {
189: if (_condition.canInsertText(offs))
190: super .insertString(offs, str, set);
191: } finally {
192: releaseWriteLock();
193: }
194: }
195:
196: /** Removes a portion of the document, if the edit condition allows it.
197: * @param offs Offset to start deleting from
198: * @param len Number of characters to remove
199: * @throws EditDocumentException if the offset or length are illegal
200: */
201: public void removeText(int offs, int len) {
202: acquireWriteLock(); // locking is used to make the test and modification atomic
203: try {
204: _removeText(offs, len);
205: } finally {
206: releaseWriteLock();
207: }
208: }
209:
210: /** Removes a portion of the document, if the edit condition allows it, as above. Assume sthat WriteLock is held */
211: public void _removeText(int offs, int len) {
212: if (_condition.canRemoveText(offs))
213: forceRemoveText(offs, len);
214: }
215:
216: /** Removes a portion of the document, regardless of the edit condition.
217: * @param offs Offset to start deleting from
218: * @param len Number of characters to remove
219: * @throws EditDocumentException if the offset or length are illegal
220: */
221: public void forceRemoveText(int offs, int len) {
222: /* Using a writeLock is unnecessary because remove is already thread-safe */
223: try {
224: super .remove(offs, len);
225: } catch (BadLocationException e) {
226: throw new EditDocumentException(e);
227: }
228: }
229:
230: /** Overrides superclass's remove to impose the edit condition. */
231: public void remove(int offs, int len) throws BadLocationException {
232: acquireWriteLock(); // locking is used to make the test and modification atomic
233: try {
234: if (_condition.canRemoveText(offs))
235: super .remove(offs, len);
236: } finally {
237: releaseWriteLock();
238: }
239: }
240:
241: // /** Returns the length of the document. */
242: // public int getDocLength() { return getLength(); } // locking is unnecessary because getLength is already thread-safe
243:
244: /** Returns a portion of the document.
245: * @param offs First offset of the desired text
246: * @param len Number of characters to return
247: * @throws EditDocumentException if the offset or length are illegal
248: */
249: public String getDocText(int offs, int len) {
250: try {
251: return getText(offs, len);
252: } // locking is unnecessary because getText is already thread-safe
253: catch (BadLocationException e) {
254: throw new EditDocumentException(e);
255: }
256: }
257:
258: /** Returns entire text of this document. */
259: public String getText() {
260: acquireReadLock();
261: try {
262: return getText(0, getLength());
263: } catch (BadLocationException e) {
264: throw new UnexpectedException(e);
265: } // impossible
266: finally {
267: releaseReadLock();
268: }
269: }
270:
271: /** Appends given string with specified attributes to end of this document. */
272: public void append(String str, AttributeSet set) {
273: acquireWriteLock();
274: try {
275: insertString(getLength(), str, set);
276: } catch (BadLocationException e) {
277: throw new UnexpectedException(e);
278: } // impossible
279: finally {
280: releaseWriteLock();
281: }
282: }
283:
284: /** Appends given string with specified named style to end of this document. */
285: public void append(String str, String style) {
286: append(str, style == null ? null : getDocStyle(style));
287: }
288:
289: /** A SwingDocument instance does not have a default style */
290: public String getDefaultStyle() {
291: return null;
292: }
293:
294: public void print() {
295: throw new UnsupportedOperationException(
296: "Printing not supported");
297: }
298:
299: public Pageable getPageable() {
300: throw new UnsupportedOperationException(
301: "Printing not supported");
302: }
303:
304: /* Locking operations */
305:
306: /* Swing-style readLock(). Must be renamed because inherited writeLock is final. */
307: public/* synchronized */void acquireReadLock() {
308: // _lockState++;
309: readLock();
310: }
311:
312: /* Swing-style readUnlock(). Must be renamed because inherited writeLock is final. */
313: public/* synchronized */void releaseReadLock() {
314: readUnlock();
315: // _lockState--;
316: }
317:
318: /** Swing-style writeLock(). Must be renamed because inherited writeLock is final. */
319: public/* synchronized */void acquireWriteLock() {
320: // _lockState = MODIFYLOCKED;
321: writeLock();
322: }
323:
324: /** Swing-style writeUnlock(). Must be renamed because inherited writeUnlock is final.*/
325: public/* synchronized*/void releaseWriteLock() {
326: writeUnlock();
327: // _lockState = UNLOCKED;
328: }
329:
330: /** Performs the default behavior for createPosition in DefaultStyledDocument. */
331: public Position createUnwrappedPosition(int offs)
332: throws BadLocationException {
333: return super .createPosition(offs);
334: }
335:
336: // public int getLockState() { return _lockState; }
337: }
|