/* * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */package javax.swing.text; import java.util.*;import java.io.*;import java.awt.font.TextAttribute;import java.text.Bidi; import javax.swing.UIManager;import javax.swing.undo.*;import javax.swing.event.ChangeListener;import javax.swing.event.*;import javax.swing.tree.TreeNode; import sun.font.BidiUtils;import sun.swing.SwingUtilities2; /** * An implementation of the document interface to serve as a * basis for implementing various kinds of documents. At this * level there is very little policy, so there is a corresponding * increase in difficulty of use. * <p> * This class implements a locking mechanism for the document. It * allows multiple readers or one writer, and writers must wait until * all observers of the document have been notified of a previous * change before beginning another mutation to the document. The * read lock is acquired and released using the <code>render</code> * method. A write lock is aquired by the methods that mutate the * document, and are held for the duration of the method call. * Notification is done on the thread that produced the mutation, * and the thread has full read access to the document for the * duration of the notification, but other readers are kept out * until the notification has finished. The notification is a * beans event notification which does not allow any further * mutations until all listeners have been notified. * <p> * Any models subclassed from this class and used in conjunction * with a text component that has a look and feel implementation * that is derived from BasicTextUI may be safely updated * asynchronously, because all access to the View hierarchy * is serialized by BasicTextUI if the document is of type * <code>AbstractDocument</code>. The locking assumes that an * independent thread will access the View hierarchy only from * the DocumentListener methods, and that there will be only * one event thread active at a time. * <p> * If concurrency support is desired, there are the following * additional implications. The code path for any DocumentListener * implementation and any UndoListener implementation must be threadsafe, * and not access the component lock if trying to be safe from deadlocks. * The <code>repaint</code> and <code>revalidate</code> methods * on JComponent are safe. * <p> * AbstractDocument models an implied break at the end of the document. * Among other things this allows you to position the caret after the last * character. As a result of this, <code>getLength</code> returns one less * than the length of the Content. If you create your own Content, be * sure and initialize it to have an additional character. Refer to * StringContent and GapContent for examples of this. Another implication * of this is that Elements that model the implied end character will have * an endOffset == (getLength() + 1). For example, in DefaultStyledDocument * <code>getParagraphElement(getLength()).getEndOffset() == getLength() + 1 * </code>. * <p> * <strong>Warning:</strong> * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeans<sup><font size="-2">TM</font></sup> * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. * * @author Timothy Prinzing */public abstract class AbstractDocument implements Document, Serializable { /** * Constructs a new <code>AbstractDocument</code>, wrapped around some * specified content storage mechanism. * * @param data the content */ protected AbstractDocument(Content data) { this(data, StyleContext.getDefaultStyleContext()); } /** * Constructs a new <code>AbstractDocument</code>, wrapped around some * specified content storage mechanism. * * @param data the content * @param context the attribute context */ protected AbstractDocument(Content data, AttributeContext context) { this.data = data; this.context = context; bidiRoot = new BidiRootElement(); if (defaultI18NProperty == null) { // determine default setting for i18n support String o = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<String>() { public String run() { return System.getProperty(I18NProperty); } } ); if (o != null) { defaultI18NProperty = Boolean.valueOf(o); } else { defaultI18NProperty = Boolean.FALSE; } } putProperty( I18NProperty, defaultI18NProperty); //REMIND(bcb) This creates an initial bidi element to account for //the \n that exists by default in the content. Doing it this way //seems to expose a little too much knowledge of the content given //to us by the sub-class. Consider having the sub-class' constructor //make an initial call to insertUpdate. writeLock(); try { Element[] p = new Element[1]; p[0] = new BidiElement( bidiRoot, 0, 1, 0 ); bidiRoot.replace(0,0,p); } finally { writeUnlock(); } } /** * Supports managing a set of properties. Callers * can use the <code>documentProperties</code> dictionary * to annotate the document with document-wide properties. * * @return a non-<code>null</code> <code>Dictionary</code> * @see #setDocumentProperties */ public Dictionary<Object,Object> getDocumentProperties() { if (documentProperties == null) { documentProperties = new Hashtable<Object, Object>(2); } return documentProperties; } /** * Replaces the document properties dictionary for this document. * * @param x the new dictionary * @see #getDocumentProperties */ public void setDocumentProperties(Dictionary<Object,Object> x) { documentProperties = x; } /** * Notifies all listeners that have registered interest for * notification on this event type. The event instance * is lazily created using the parameters passed into * the fire method. * * @param e the event * @see EventListenerList */ protected void fireInsertUpdate(DocumentEvent e) { notifyingListeners = true; try { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==DocumentListener.class) { // Lazily create the event: // if (e == null) // e = new ListSelectionEvent(this, firstIndex, lastIndex); ((DocumentListener)listeners[i+1]).insertUpdate(e); } } } finally { notifyingListeners = false; } } /** * Notifies all listeners that have registered interest for * notification on this event type. The event instance * is lazily created using the parameters passed into * the fire method. * * @param e the event * @see EventListenerList */ protected void fireChangedUpdate(DocumentEvent e) { notifyingListeners = true; try { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==DocumentListener.class) { // Lazily create the event: // if (e == null) // e = new ListSelectionEvent(this, firstIndex, lastIndex); ((DocumentListener)listeners[i+1]).changedUpdate(e); } } } finally { notifyingListeners = false; } } /** * Notifies all listeners that have registered interest for * notification on this event type. The event instance * is lazily created using the parameters passed into * the fire method. * * @param e the event * @see EventListenerList */ protected void fireRemoveUpdate(DocumentEvent e) { notifyingListeners = true; try { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==DocumentListener.class) { // Lazily create the event: // if (e == null) // e = new ListSelectionEvent(this, firstIndex, lastIndex); ((DocumentListener)listeners[i+1]).removeUpdate(e); } } } finally { notifyingListeners = false; } } /** * Notifies all listeners that have registered interest for * notification on this event type. The event instance * is lazily created using the parameters passed into * the fire method. * * @param e the event * @see EventListenerList */ protected void fireUndoableEditUpdate(UndoableEditEvent e) { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==UndoableEditListener.class) { // Lazily create the event: // if (e == null) // e = new ListSelectionEvent(this, firstIndex, lastIndex); ((UndoableEditListener)listeners[i+1]).undoableEditHappened(e); } } } /** * Returns an array of all the objects currently registered * as <code><em>Foo</em>Listener</code>s * upon this document. * <code><em>Foo</em>Listener</code>s are registered using the * <code>add<em>Foo</em>Listener</code> method. * * <p> * You can specify the <code>listenerType</code> argument * with a class literal, such as * <code><em>Foo</em>Listener.class</code>. * For example, you can query a * document <code>d</code> * for its document listeners with the following code: * * <pre>DocumentListener[] mls = (DocumentListener[])(d.getListeners(DocumentListener.class));</pre> * * If no such listeners exist, this method returns an empty array. * * @param listenerType the type of listeners requested; this parameter * should specify an interface that descends from * <code>java.util.EventListener</code> * @return an array of all objects registered as * <code><em>Foo</em>Listener</code>s on this component, * or an empty array if no such * listeners have been added * @exception ClassCastException if <code>listenerType</code> * doesn't specify a class or interface that implements * <code>java.util.EventListener</code> * * @see #getDocumentListeners * @see #getUndoableEditListeners * * @since 1.3 */ public <T extends EventListener> T[] getListeners(Class<T> listenerType) { return listenerList.getListeners(listenerType); } /** * Gets the asynchronous loading priority. If less than zero, * the document should not be loaded asynchronously. * * @return the asynchronous loading priority, or <code>-1</code> * if the document should not be loaded asynchronously */ public int getAsynchronousLoadPriority() { Integer loadPriority = (Integer) getProperty(AbstractDocument.AsyncLoadPriority); if (loadPriority != null) { return loadPriority.intValue(); } return -1; } /** * Sets the asynchronous loading priority. * @param p the new asynchronous loading priority; a value * less than zero indicates that the document should not be * loaded asynchronously */ public void setAsynchronousLoadPriority(int p) { Integer loadPriority = (p >= 0) ? Integer.valueOf(p) : null; putProperty(AbstractDocument.AsyncLoadPriority, loadPriority); } /** * Sets the <code>DocumentFilter</code>. The <code>DocumentFilter</code> * is passed <code>insert</code> and <code>remove</code> to conditionally * allow inserting/deleting of the text. A <code>null</code> value * indicates that no filtering will occur. * * @param filter the <code>DocumentFilter</code> used to constrain text * @see #getDocumentFilter * @since 1.4 */ public void setDocumentFilter(DocumentFilter filter) { documentFilter = filter; } /** * Returns the <code>DocumentFilter</code> that is responsible for * filtering of insertion/removal. A <code>null</code> return value * implies no filtering is to occur. * * @since 1.4 * @see #setDocumentFilter * @return the DocumentFilter */ public DocumentFilter getDocumentFilter() { return documentFilter; } // --- Document methods ----------------------------------------- /** * This allows the model to be safely rendered in the presence * of currency, if the model supports being updated asynchronously. * The given runnable will be executed in a way that allows it * to safely read the model with no changes while the runnable * is being executed. The runnable itself may <em>not</em> * make any mutations. * <p> * This is implemented to aquire a read lock for the duration * of the runnables execution. There may be multiple runnables * executing at the same time, and all writers will be blocked * while there are active rendering runnables. If the runnable * throws an exception, its lock will be safely released. * There is no protection against a runnable that never exits, * which will effectively leave the document locked for it's * lifetime. * <p> * If the given runnable attempts to make any mutations in * this implementation, a deadlock will occur. There is * no tracking of individual rendering threads to enable * detecting this situation, but a subclass could incur * the overhead of tracking them and throwing an error. * <p> * This method is thread safe, although most Swing methods * are not. Please see * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How * to Use Threads</A> for more information. * * @param r the renderer to execute */ public void render(Runnable r) { readLock(); try { r.run(); } finally { readUnlock(); } } /** * Returns the length of the data. This is the number of * characters of content that represents the users data. * * @return the length >= 0 * @see Document#getLength */ public int getLength() { return data.length() - 1; } /** * Adds a document listener for notification of any changes. * * @param listener the <code>DocumentListener</code> to add * @see Document#addDocumentListener */ public void addDocumentListener(DocumentListener listener) { listenerList.add(DocumentListener.class, listener); } /** * Removes a document listener. * * @param listener the <code>DocumentListener</code> to remove * @see Document#removeDocumentListener */ public void removeDocumentListener(DocumentListener listener) { listenerList.remove(DocumentListener.class, listener); } /** * Returns an array of all the document listeners * registered on this document. * * @return all of this document's <code>DocumentListener</code>s * or an empty array if no document listeners are * currently registered * * @see #addDocumentListener * @see #removeDocumentListener * @since 1.4 */ public DocumentListener[] getDocumentListeners() { return listenerList.getListeners(DocumentListener.class); } /** * Adds an undo listener for notification of any changes. * Undo/Redo operations performed on the <code>UndoableEdit</code> * will cause the appropriate DocumentEvent to be fired to keep * the view(s) in sync with the model. * * @param listener the <code>UndoableEditListener</code> to add * @see Document#addUndoableEditListener */ public void addUndoableEditListener(UndoableEditListener listener) { listenerList.add(UndoableEditListener.class, listener); } /** * Removes an undo listener. * * @param listener the <code>UndoableEditListener</code> to remove * @see Document#removeDocumentListener */ public void removeUndoableEditListener(UndoableEditListener listener) { listenerList.remove(UndoableEditListener.class, listener); } /** * Returns an array of all the undoable edit listeners * registered on this document. * * @return all of this document's <code>UndoableEditListener</code>sLines 1–500 of 3118. Load more
/* * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.swing.text; import java.util.*; import java.io.*; import java.awt.font.TextAttribute; import java.text.Bidi; import javax.swing.UIManager; import javax.swing.undo.*; import javax.swing.event.ChangeListener; import javax.swing.event.*; import javax.swing.tree.TreeNode; import sun.font.BidiUtils; import sun.swing.SwingUtilities2; /** * An implementation of the document interface to serve as a * basis for implementing various kinds of documents. At this * level there is very little policy, so there is a corresponding * increase in difficulty of use. * <p> * This class implements a locking mechanism for the document. It * allows multiple readers or one writer, and writers must wait until * all observers of the document have been notified of a previous * change before beginning another mutation to the document. The * read lock is acquired and released using the <code>render</code> * method. A write lock is aquired by the methods that mutate the * document, and are held for the duration of the method call. * Notification is done on the thread that produced the mutation, * and the thread has full read access to the document for the * duration of the notification, but other readers are kept out * until the notification has finished. The notification is a * beans event notification which does not allow any further * mutations until all listeners have been notified. * <p> * Any models subclassed from this class and used in conjunction * with a text component that has a look and feel implementation * that is derived from BasicTextUI may be safely updated * asynchronously, because all access to the View hierarchy * is serialized by BasicTextUI if the document is of type * <code>AbstractDocument</code>. The locking assumes that an * independent thread will access the View hierarchy only from * the DocumentListener methods, and that there will be only * one event thread active at a time. * <p> * If concurrency support is desired, there are the following * additional implications. The code path for any DocumentListener * implementation and any UndoListener implementation must be threadsafe, * and not access the component lock if trying to be safe from deadlocks. * The <code>repaint</code> and <code>revalidate</code> methods * on JComponent are safe. * <p> * AbstractDocument models an implied break at the end of the document. * Among other things this allows you to position the caret after the last * character. As a result of this, <code>getLength</code> returns one less * than the length of the Content. If you create your own Content, be * sure and initialize it to have an additional character. Refer to * StringContent and GapContent for examples of this. Another implication * of this is that Elements that model the implied end character will have * an endOffset == (getLength() + 1). For example, in DefaultStyledDocument * <code>getParagraphElement(getLength()).getEndOffset() == getLength() + 1 * </code>. * <p> * <strong>Warning:</strong> * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeans<sup><font size="-2">TM</font></sup> * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. * * @author Timothy Prinzing */ public abstract class AbstractDocument implements Document, Serializable { /** * Constructs a new <code>AbstractDocument</code>, wrapped around some * specified content storage mechanism. * * @param data the content */ protected AbstractDocument(Content data) { this(data, StyleContext.getDefaultStyleContext()); } /** * Constructs a new <code>AbstractDocument</code>, wrapped around some * specified content storage mechanism. * * @param data the content * @param context the attribute context */ protected AbstractDocument(Content data, AttributeContext context) { this.data = data; this.context = context; bidiRoot = new BidiRootElement(); if (defaultI18NProperty == null) { // determine default setting for i18n support String o = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<String>() { public String run() { return System.getProperty(I18NProperty); } } ); if (o != null) { defaultI18NProperty = Boolean.valueOf(o); } else { defaultI18NProperty = Boolean.FALSE; } } putProperty( I18NProperty, defaultI18NProperty); //REMIND(bcb) This creates an initial bidi element to account for //the \n that exists by default in the content. Doing it this way //seems to expose a little too much knowledge of the content given //to us by the sub-class. Consider having the sub-class' constructor //make an initial call to insertUpdate. writeLock(); try { Element[] p = new Element[1]; p[0] = new BidiElement( bidiRoot, 0, 1, 0 ); bidiRoot.replace(0,0,p); } finally { writeUnlock(); } } /** * Supports managing a set of properties. Callers * can use the <code>documentProperties</code> dictionary * to annotate the document with document-wide properties. * * @return a non-<code>null</code> <code>Dictionary</code> * @see #setDocumentProperties */ public Dictionary<Object,Object> getDocumentProperties() { if (documentProperties == null) { documentProperties = new Hashtable<Object, Object>(2); } return documentProperties; } /** * Replaces the document properties dictionary for this document. * * @param x the new dictionary * @see #getDocumentProperties */ public void setDocumentProperties(Dictionary<Object,Object> x) { documentProperties = x; } /** * Notifies all listeners that have registered interest for * notification on this event type. The event instance * is lazily created using the parameters passed into * the fire method. * * @param e the event * @see EventListenerList */ protected void fireInsertUpdate(DocumentEvent e) { notifyingListeners = true; try { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==DocumentListener.class) { // Lazily create the event: // if (e == null) // e = new ListSelectionEvent(this, firstIndex, lastIndex); ((DocumentListener)listeners[i+1]).insertUpdate(e); } } } finally { notifyingListeners = false; } } /** * Notifies all listeners that have registered interest for * notification on this event type. The event instance * is lazily created using the parameters passed into * the fire method. * * @param e the event * @see EventListenerList */ protected void fireChangedUpdate(DocumentEvent e) { notifyingListeners = true; try { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==DocumentListener.class) { // Lazily create the event: // if (e == null) // e = new ListSelectionEvent(this, firstIndex, lastIndex); ((DocumentListener)listeners[i+1]).changedUpdate(e); } } } finally { notifyingListeners = false; } } /** * Notifies all listeners that have registered interest for * notification on this event type. The event instance * is lazily created using the parameters passed into * the fire method. * * @param e the event * @see EventListenerList */ protected void fireRemoveUpdate(DocumentEvent e) { notifyingListeners = true; try { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==DocumentListener.class) { // Lazily create the event: // if (e == null) // e = new ListSelectionEvent(this, firstIndex, lastIndex); ((DocumentListener)listeners[i+1]).removeUpdate(e); } } } finally { notifyingListeners = false; } } /** * Notifies all listeners that have registered interest for * notification on this event type. The event instance * is lazily created using the parameters passed into * the fire method. * * @param e the event * @see EventListenerList */ protected void fireUndoableEditUpdate(UndoableEditEvent e) { // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length-2; i>=0; i-=2) { if (listeners[i]==UndoableEditListener.class) { // Lazily create the event: // if (e == null) // e = new ListSelectionEvent(this, firstIndex, lastIndex); ((UndoableEditListener)listeners[i+1]).undoableEditHappened(e); } } } /** * Returns an array of all the objects currently registered * as <code><em>Foo</em>Listener</code>s * upon this document. * <code><em>Foo</em>Listener</code>s are registered using the * <code>add<em>Foo</em>Listener</code> method. * * <p> * You can specify the <code>listenerType</code> argument * with a class literal, such as * <code><em>Foo</em>Listener.class</code>. * For example, you can query a * document <code>d</code> * for its document listeners with the following code: * * <pre>DocumentListener[] mls = (DocumentListener[])(d.getListeners(DocumentListener.class));</pre> * * If no such listeners exist, this method returns an empty array. * * @param listenerType the type of listeners requested; this parameter * should specify an interface that descends from * <code>java.util.EventListener</code> * @return an array of all objects registered as * <code><em>Foo</em>Listener</code>s on this component, * or an empty array if no such * listeners have been added * @exception ClassCastException if <code>listenerType</code> * doesn't specify a class or interface that implements * <code>java.util.EventListener</code> * * @see #getDocumentListeners * @see #getUndoableEditListeners * * @since 1.3 */ public <T extends EventListener> T[] getListeners(Class<T> listenerType) { return listenerList.getListeners(listenerType); } /** * Gets the asynchronous loading priority. If less than zero, * the document should not be loaded asynchronously. * * @return the asynchronous loading priority, or <code>-1</code> * if the document should not be loaded asynchronously */ public int getAsynchronousLoadPriority() { Integer loadPriority = (Integer) getProperty(AbstractDocument.AsyncLoadPriority); if (loadPriority != null) { return loadPriority.intValue(); } return -1; } /** * Sets the asynchronous loading priority. * @param p the new asynchronous loading priority; a value * less than zero indicates that the document should not be * loaded asynchronously */ public void setAsynchronousLoadPriority(int p) { Integer loadPriority = (p >= 0) ? Integer.valueOf(p) : null; putProperty(AbstractDocument.AsyncLoadPriority, loadPriority); } /** * Sets the <code>DocumentFilter</code>. The <code>DocumentFilter</code> * is passed <code>insert</code> and <code>remove</code> to conditionally * allow inserting/deleting of the text. A <code>null</code> value * indicates that no filtering will occur. * * @param filter the <code>DocumentFilter</code> used to constrain text * @see #getDocumentFilter * @since 1.4 */ public void setDocumentFilter(DocumentFilter filter) { documentFilter = filter; } /** * Returns the <code>DocumentFilter</code> that is responsible for * filtering of insertion/removal. A <code>null</code> return value * implies no filtering is to occur. * * @since 1.4 * @see #setDocumentFilter * @return the DocumentFilter */ public DocumentFilter getDocumentFilter() { return documentFilter; } // --- Document methods ----------------------------------------- /** * This allows the model to be safely rendered in the presence * of currency, if the model supports being updated asynchronously. * The given runnable will be executed in a way that allows it * to safely read the model with no changes while the runnable * is being executed. The runnable itself may <em>not</em> * make any mutations. * <p> * This is implemented to aquire a read lock for the duration * of the runnables execution. There may be multiple runnables * executing at the same time, and all writers will be blocked * while there are active rendering runnables. If the runnable * throws an exception, its lock will be safely released. * There is no protection against a runnable that never exits, * which will effectively leave the document locked for it's * lifetime. * <p> * If the given runnable attempts to make any mutations in * this implementation, a deadlock will occur. There is * no tracking of individual rendering threads to enable * detecting this situation, but a subclass could incur * the overhead of tracking them and throwing an error. * <p> * This method is thread safe, although most Swing methods * are not. Please see * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How * to Use Threads</A> for more information. * * @param r the renderer to execute */ public void render(Runnable r) { readLock(); try { r.run(); } finally { readUnlock(); } } /** * Returns the length of the data. This is the number of * characters of content that represents the users data. * * @return the length >= 0 * @see Document#getLength */ public int getLength() { return data.length() - 1; } /** * Adds a document listener for notification of any changes. * * @param listener the <code>DocumentListener</code> to add * @see Document#addDocumentListener */ public void addDocumentListener(DocumentListener listener) { listenerList.add(DocumentListener.class, listener); } /** * Removes a document listener. * * @param listener the <code>DocumentListener</code> to remove * @see Document#removeDocumentListener */ public void removeDocumentListener(DocumentListener listener) { listenerList.remove(DocumentListener.class, listener); } /** * Returns an array of all the document listeners * registered on this document. * * @return all of this document's <code>DocumentListener</code>s * or an empty array if no document listeners are * currently registered * * @see #addDocumentListener * @see #removeDocumentListener * @since 1.4 */ public DocumentListener[] getDocumentListeners() { return listenerList.getListeners(DocumentListener.class); } /** * Adds an undo listener for notification of any changes. * Undo/Redo operations performed on the <code>UndoableEdit</code> * will cause the appropriate DocumentEvent to be fired to keep * the view(s) in sync with the model. * * @param listener the <code>UndoableEditListener</code> to add * @see Document#addUndoableEditListener */ public void addUndoableEditListener(UndoableEditListener listener) { listenerList.add(UndoableEditListener.class, listener); } /** * Removes an undo listener. * * @param listener the <code>UndoableEditListener</code> to remove * @see Document#removeDocumentListener */ public void removeUndoableEditListener(UndoableEditListener listener) { listenerList.remove(UndoableEditListener.class, listener); } /** * Returns an array of all the undoable edit listeners * registered on this document. * * @return all of this document's <code>UndoableEditListener</code>s