📄 abstractdocument.java
字号:
* * @param key the key of the property to be fetched * * @return the property for <code>key</code> or <code>null</code> if there * is no such property stored */ public Object getProperty(Object key) { // FIXME: make me thread-safe Object value = null; if (properties != null) value = properties.get(key); return value; } /** * Returns all root elements of this <code>Document</code>. By default * this just returns the single root element returned by * {@link #getDefaultRootElement()}. <code>Document</code> implementations * that support multiple roots must override this method and return all roots * here. * * @return all root elements of this <code>Document</code> */ public Element[] getRootElements() { Element[] elements = new Element[1]; elements[0] = getDefaultRootElement(); return elements; } /** * Returns a {@link Position} which will always mark the beginning of the * <code>Document</code>. * * @return a {@link Position} which will always mark the beginning of the * <code>Document</code> */ public Position getStartPosition() { // FIXME: Properly implement this using Content.createPosition(). return new Position() { public int getOffset() { return 0; } }; } /** * Returns a piece of this <code>Document</code>'s content. * * @param offset the start offset of the content * @param length the length of the content * * @return the piece of content specified by <code>offset</code> and * <code>length</code> * * @throws BadLocationException if <code>offset</code> or <code>offset + * length</code> are invalid locations with this * <code>Document</code> */ public String getText(int offset, int length) throws BadLocationException { return content.getString(offset, length); } /** * Fetches a piece of this <code>Document</code>'s content and stores * it in the given {@link Segment}. * * @param offset the start offset of the content * @param length the length of the content * @param segment the <code>Segment</code> to store the content in * * @throws BadLocationException if <code>offset</code> or <code>offset + * length</code> are invalid locations with this * <code>Document</code> */ public void getText(int offset, int length, Segment segment) throws BadLocationException { content.getChars(offset, length, segment); } /** * Inserts a String into this <code>Document</code> at the specified * position and assigning the specified attributes to it. * * @param offset the location at which the string should be inserted * @param text the content to be inserted * @param attributes the text attributes to be assigned to that string * * @throws BadLocationException if <code>offset</code> is not a valid * location in this <code>Document</code> */ public void insertString(int offset, String text, AttributeSet attributes) throws BadLocationException { // Just return when no text to insert was given. if (text == null || text.length() == 0) return; DefaultDocumentEvent event = new DefaultDocumentEvent(offset, text.length(), DocumentEvent.EventType.INSERT); writeLock(); UndoableEdit undo = content.insertString(offset, text); insertUpdate(event, attributes); writeUnlock(); fireInsertUpdate(event); if (undo != null) fireUndoableEditUpdate(new UndoableEditEvent(this, undo)); } /** * Called to indicate that text has been inserted into this * <code>Document</code>. The default implementation does nothing. * This method is executed within a write lock. * * @param chng the <code>DefaultDocumentEvent</code> describing the change * @param attr the attributes of the changed content */ protected void insertUpdate(DefaultDocumentEvent chng, AttributeSet attr) { // Do nothing here. Subclasses may want to override this. } /** * Called after some content has been removed from this * <code>Document</code>. The default implementation does nothing. * This method is executed within a write lock. * * @param chng the <code>DefaultDocumentEvent</code> describing the change */ protected void postRemoveUpdate(DefaultDocumentEvent chng) { // Do nothing here. Subclasses may want to override this. } /** * Stores a property in this <code>Document</code>'s property list. * * @param key the key of the property to be stored * @param value the value of the property to be stored */ public void putProperty(Object key, Object value) { // FIXME: make me thread-safe if (properties == null) properties = new Hashtable(); properties.put(key, value); } /** * Blocks until a read lock can be obtained. Must block if there is * currently a writer modifying the <code>Document</code>. */ public void readLock() { if (currentWriter != null && currentWriter.equals(Thread.currentThread())) return; synchronized (documentCV) { while (currentWriter != null || numWritersWaiting > 0) { try { documentCV.wait(); } catch (InterruptedException ie) { throw new Error("interrupted trying to get a readLock"); } } numReaders++; } } /** * Releases the read lock. If this was the only reader on this * <code>Document</code>, writing may begin now. */ public void readUnlock() { // Note we could have a problem here if readUnlock was called without a // prior call to readLock but the specs simply warn users to ensure that // balance by using a finally block: // readLock() // try // { // doSomethingHere // } // finally // { // readUnlock(); // } // All that the JDK seems to check for is that you don't call unlock // more times than you've previously called lock, but it doesn't make // sure that the threads calling unlock were the same ones that called lock // FIXME: the reference implementation throws a // javax.swing.text.StateInvariantError here if (numReaders == 0) throw new IllegalStateException("document lock failure"); synchronized (documentCV) { // If currentWriter is not null, the application code probably had a // writeLock and then tried to obtain a readLock, in which case // numReaders wasn't incremented if (currentWriter == null) { numReaders --; if (numReaders == 0 && numWritersWaiting != 0) documentCV.notify(); } } } /** * Removes a piece of content from this <code>Document</code>. * * @param offset the start offset of the fragment to be removed * @param length the length of the fragment to be removed * * @throws BadLocationException if <code>offset</code> or * <code>offset + length</code> or invalid locations within this * document */ public void remove(int offset, int length) throws BadLocationException { DefaultDocumentEvent event = new DefaultDocumentEvent(offset, length, DocumentEvent.EventType.REMOVE); removeUpdate(event); boolean shouldFire = content.getString(offset, length).length() != 0; writeLock(); UndoableEdit temp = content.remove(offset, length); writeUnlock(); postRemoveUpdate(event); if (shouldFire) fireRemoveUpdate(event); } /** * Replaces a piece of content in this <code>Document</code> with * another piece of content. * * @param offset the start offset of the fragment to be removed * @param length the length of the fragment to be removed * @param text the text to replace the content with * @param attributes the text attributes to assign to the new content * * @throws BadLocationException if <code>offset</code> or * <code>offset + length</code> or invalid locations within this * document * * @since 1.4 */ public void replace(int offset, int length, String text, AttributeSet attributes) throws BadLocationException { remove(offset, length); insertString(offset, text, attributes); } /** * Adds a <code>DocumentListener</code> object to this document. * * @param listener the listener to add */ public void addDocumentListener(DocumentListener listener) { listenerList.add(DocumentListener.class, listener); } /** * Removes a <code>DocumentListener</code> object from this document. * * @param listener the listener to remove */ public void removeDocumentListener(DocumentListener listener) { listenerList.remove(DocumentListener.class, listener); } /** * Returns all registered <code>DocumentListener</code>s. * * @return all registered <code>DocumentListener</code>s */ public DocumentListener[] getDocumentListeners() { return (DocumentListener[]) getListeners(DocumentListener.class); } /** * Adds an {@link UndoableEditListener} to this <code>Document</code>. * * @param listener the listener to add */ public void addUndoableEditListener(UndoableEditListener listener) { listenerList.add(UndoableEditListener.class, listener); } /** * Removes an {@link UndoableEditListener} from this <code>Document</code>. * * @param listener the listener to remove */ public void removeUndoableEditListener(UndoableEditListener listener) { listenerList.remove(UndoableEditListener.class, listener); } /** * Returns all registered {@link UndoableEditListener}s. * * @return all registered {@link UndoableEditListener}s */ public UndoableEditListener[] getUndoableEditListeners() { return (UndoableEditListener[]) getListeners(UndoableEditListener.class); } /** * Called before some content gets removed from this <code>Document</code>. * The default implementation does nothing but may be overridden by * subclasses to modify the <code>Document</code> structure in response * to a remove request. The method is executed within a write lock. * * @param chng the <code>DefaultDocumentEvent</code> describing the change */ protected void removeUpdate(DefaultDocumentEvent chng) { // Do nothing here. Subclasses may wish to override this. } /** * Called to render this <code>Document</code> visually. It obtains a read * lock, ensuring that no changes will be made to the <code>document</code> * during the rendering process. It then calls the {@link Runnable#run()} * method on <code>runnable</code>. This method <em>must not</em> attempt * to modifiy the <code>Document</code>, since a deadlock will occur if it * tries to obtain a write lock. When the {@link Runnable#run()} method * completes (either naturally or by throwing an exception), the read lock * is released. Note that there is nothing in this method related to * the actual rendering. It could be used to execute arbitrary code within * a read lock. * * @param runnable the {@link Runnable} to execute */ public void render(Runnable runnable) { readLock(); try { runnable.run(); } finally { readUnlock(); } } /** * Sets the asynchronous loading priority for this <code>Document</code>. * A value of <code>-1</code> indicates that this <code>Document</code> * should be loaded synchronously. * * @param p the asynchronous loading priority to set */ public void setAsynchronousLoadPriority(int p) { // TODO: Implement this properly. } /** * Sets the properties of this <code>Document</code>. * * @param p the document properties to set */ public void setDocumentProperties(Dictionary p) { // FIXME: make me thread-safe properties = p; } /** * Blocks until a write lock can be obtained. Must wait if there are * readers currently reading or another thread is currently writing. */ protected void writeLock() { if (currentWriter!= null && currentWriter.equals(Thread.currentThread())) return; synchronized (documentCV) { numWritersWaiting++; while (numReaders > 0) { try { documentCV.wait(); } catch (InterruptedException ie) { throw new Error("interruped while trying to obtain write lock"); } } numWritersWaiting --; currentWriter = Thread.currentThread(); } } /** * Releases the write lock. This allows waiting readers or writers to * obtain the lock. */ protected void writeUnlock()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -