3118 lines · 108.4 KB · Java
RawDownload
     *         or an empty array if no undoable edit listeners are     *         currently registered     *     * @see #addUndoableEditListener     * @see #removeUndoableEditListener     *     * @since 1.4     */    public UndoableEditListener[] getUndoableEditListeners() {        return listenerList.getListeners(UndoableEditListener.class);    }     /**     * A convenience method for looking up a property value. It is     * equivalent to:     * <pre>     * getDocumentProperties().get(key);     * </pre>     *     * @param key the non-<code>null</code> property key     * @return the value of this property or <code>null</code>     * @see #getDocumentProperties     */    public final Object getProperty(Object key) {        return getDocumentProperties().get(key);    }      /**     * A convenience method for storing up a property value.  It is     * equivalent to:     * <pre>     * getDocumentProperties().put(key, value);     * </pre>     * If <code>value</code> is <code>null</code> this method will     * remove the property.     *     * @param key the non-<code>null</code> key     * @param value the property value     * @see #getDocumentProperties     */    public final void putProperty(Object key, Object value) {        if (value != null) {            getDocumentProperties().put(key, value);        } else {            getDocumentProperties().remove(key);        }        if( key == TextAttribute.RUN_DIRECTION            && Boolean.TRUE.equals(getProperty(I18NProperty)) )        {            //REMIND - this needs to flip on the i18n property if run dir            //is rtl and the i18n property is not already on.            writeLock();            try {                DefaultDocumentEvent e                    = new DefaultDocumentEvent(0, getLength(),                                               DocumentEvent.EventType.INSERT);                updateBidi( e );            } finally {                writeUnlock();            }        }    }     /**     * Removes some content from the document.     * Removing content causes a write lock to be held while the     * actual changes are taking place.  Observers are notified     * of the change on the thread that called this method.     * <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 offs the starting offset >= 0     * @param len the number of characters to remove >= 0     * @exception BadLocationException  the given remove position is not a valid     *   position within the document     * @see Document#remove     */    public void remove(int offs, int len) throws BadLocationException {        DocumentFilter filter = getDocumentFilter();         writeLock();        try {            if (filter != null) {                filter.remove(getFilterBypass(), offs, len);            }            else {                handleRemove(offs, len);            }        } finally {            writeUnlock();        }    }     /**     * Performs the actual work of the remove. It is assumed the caller     * will have obtained a <code>writeLock</code> before invoking this.     */    void handleRemove(int offs, int len) throws BadLocationException {        if (len > 0) {            if (offs < 0 || (offs + len) > getLength()) {                throw new BadLocationException("Invalid remove",                                               getLength() + 1);            }            DefaultDocumentEvent chng =                    new DefaultDocumentEvent(offs, len, DocumentEvent.EventType.REMOVE);             boolean isComposedTextElement;            // Check whether the position of interest is the composed text            isComposedTextElement = Utilities.isComposedTextElement(this, offs);             removeUpdate(chng);            UndoableEdit u = data.remove(offs, len);            if (u != null) {                chng.addEdit(u);            }            postRemoveUpdate(chng);            // Mark the edit as done.            chng.end();            fireRemoveUpdate(chng);            // only fire undo if Content implementation supports it            // undo for the composed text is not supported for now            if ((u != null) && !isComposedTextElement) {                fireUndoableEditUpdate(new UndoableEditEvent(this, chng));            }        }    }     /**     * Deletes the region of text from <code>offset</code> to     * <code>offset + length</code>, and replaces it with <code>text</code>.     * It is up to the implementation as to how this is implemented, some     * implementations may treat this as two distinct operations: a remove     * followed by an insert, others may treat the replace as one atomic     * operation.     *     * @param offset index of child element     * @param length length of text to delete, may be 0 indicating don't     *               delete anything     * @param text text to insert, <code>null</code> indicates no text to insert     * @param attrs AttributeSet indicating attributes of inserted text,     *              <code>null</code>     *              is legal, and typically treated as an empty attributeset,     *              but exact interpretation is left to the subclass     * @exception BadLocationException the given position is not a valid     *            position within the document     * @since 1.4     */    public void replace(int offset, int length, String text,                        AttributeSet attrs) throws BadLocationException {        if (length == 0 && (text == null || text.length() == 0)) {            return;        }        DocumentFilter filter = getDocumentFilter();         writeLock();        try {            if (filter != null) {                filter.replace(getFilterBypass(), offset, length, text,                               attrs);            }            else {                if (length > 0) {                    remove(offset, length);                }                if (text != null && text.length() > 0) {                    insertString(offset, text, attrs);                }            }        } finally {            writeUnlock();        }    }     /**     * Inserts some content into the document.     * Inserting content causes a write lock to be held while the     * actual changes are taking place, followed by notification     * to the observers on the thread that grabbed the write lock.     * <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 offs the starting offset >= 0     * @param str the string to insert; does nothing with null/empty strings     * @param a the attributes for the inserted content     * @exception BadLocationException  the given insert position is not a valid     *   position within the document     * @see Document#insertString     */    public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {        if ((str == null) || (str.length() == 0)) {            return;        }        DocumentFilter filter = getDocumentFilter();         writeLock();        try {            if (filter != null) {                filter.insertString(getFilterBypass(), offs, str, a);            }            else {                handleInsertString(offs, str, a);            }        } finally {            writeUnlock();        }    }     /**     * Performs the actual work of inserting the text; it is assumed the     * caller has obtained a write lock before invoking this.     */    void handleInsertString(int offs, String str, AttributeSet a)                         throws BadLocationException {        if ((str == null) || (str.length() == 0)) {            return;        }        UndoableEdit u = data.insertString(offs, str);        DefaultDocumentEvent e =            new DefaultDocumentEvent(offs, str.length(), DocumentEvent.EventType.INSERT);        if (u != null) {            e.addEdit(u);        }         // see if complex glyph layout support is needed        if( getProperty(I18NProperty).equals( Boolean.FALSE ) ) {            // if a default direction of right-to-left has been specified,            // we want complex layout even if the text is all left to right.            Object d = getProperty(TextAttribute.RUN_DIRECTION);            if ((d != null) && (d.equals(TextAttribute.RUN_DIRECTION_RTL))) {                putProperty( I18NProperty, Boolean.TRUE);            } else {                char[] chars = str.toCharArray();                if (SwingUtilities2.isComplexLayout(chars, 0, chars.length)) {                    putProperty( I18NProperty, Boolean.TRUE);                }            }        }         insertUpdate(e, a);        // Mark the edit as done.        e.end();        fireInsertUpdate(e);        // only fire undo if Content implementation supports it        // undo for the composed text is not supported for now        if (u != null &&            (a == null || !a.isDefined(StyleConstants.ComposedTextAttribute))) {            fireUndoableEditUpdate(new UndoableEditEvent(this, e));        }    }     /**     * Gets a sequence of text from the document.     *     * @param offset the starting offset >= 0     * @param length the number of characters to retrieve >= 0     * @return the text     * @exception BadLocationException  the range given includes a position     *   that is not a valid position within the document     * @see Document#getText     */    public String getText(int offset, int length) throws BadLocationException {        if (length < 0) {            throw new BadLocationException("Length must be positive", length);        }        String str = data.getString(offset, length);        return str;    }     /**     * Fetches the text contained within the given portion     * of the document.     * <p>     * If the partialReturn property on the txt parameter is false, the     * data returned in the Segment will be the entire length requested and     * may or may not be a copy depending upon how the data was stored.     * If the partialReturn property is true, only the amount of text that     * can be returned without creating a copy is returned.  Using partial     * returns will give better performance for situations where large     * parts of the document are being scanned.  The following is an example     * of using the partial return to access the entire document:     * <p>     * <pre>     * &nbsp; int nleft = doc.getDocumentLength();     * &nbsp; Segment text = new Segment();     * &nbsp; int offs = 0;     * &nbsp; text.setPartialReturn(true);     * &nbsp; while (nleft > 0) {     * &nbsp;     doc.getText(offs, nleft, text);     * &nbsp;     // do something with text     * &nbsp;     nleft -= text.count;     * &nbsp;     offs += text.count;     * &nbsp; }     * </pre>     *     * @param offset the starting offset >= 0     * @param length the number of characters to retrieve >= 0     * @param txt the Segment object to retrieve the text into     * @exception BadLocationException  the range given includes a position     *   that is not a valid position within the document     */    public void getText(int offset, int length, Segment txt) throws BadLocationException {        if (length < 0) {            throw new BadLocationException("Length must be positive", length);        }        data.getChars(offset, length, txt);    }     /**     * Returns a position that will track change as the document     * is altered.     * <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 offs the position in the model >= 0     * @return the position     * @exception BadLocationException  if the given position does not     *   represent a valid location in the associated document     * @see Document#createPosition     */    public synchronized Position createPosition(int offs) throws BadLocationException {        return data.createPosition(offs);    }     /**     * Returns a position that represents the start of the document.  The     * position returned can be counted on to track change and stay     * located at the beginning of the document.     *     * @return the position     */    public final Position getStartPosition() {        Position p;        try {            p = createPosition(0);        } catch (BadLocationException bl) {            p = null;        }        return p;    }     /**     * Returns a position that represents the end of the document.  The     * position returned can be counted on to track change and stay     * located at the end of the document.     *     * @return the position     */    public final Position getEndPosition() {        Position p;        try {            p = createPosition(data.length());        } catch (BadLocationException bl) {            p = null;        }        return p;    }     /**     * Gets all root elements defined.  Typically, there     * will only be one so the default implementation     * is to return the default root element.     *     * @return the root element     */    public Element[] getRootElements() {        Element[] elems = new Element[2];        elems[0] = getDefaultRootElement();        elems[1] = getBidiRootElement();        return elems;    }     /**     * Returns the root element that views should be based upon     * unless some other mechanism for assigning views to element     * structures is provided.     *     * @return the root element     * @see Document#getDefaultRootElement     */    public abstract Element getDefaultRootElement();     // ---- local methods -----------------------------------------     /**     * Returns the <code>FilterBypass</code>. This will create one if one     * does not yet exist.     */    private DocumentFilter.FilterBypass getFilterBypass() {        if (filterBypass == null) {            filterBypass = new DefaultFilterBypass();        }        return filterBypass;    }     /**     * Returns the root element of the bidirectional structure for this     * document.  Its children represent character runs with a given     * Unicode bidi level.     */    public Element getBidiRootElement() {        return bidiRoot;    }     /**     * Returns true if the text in the range <code>p0</code> to     * <code>p1</code> is left to right.     */    boolean isLeftToRight(int p0, int p1) {        if(!getProperty(I18NProperty).equals(Boolean.TRUE)) {            return true;        }        Element bidiRoot = getBidiRootElement();        int index = bidiRoot.getElementIndex(p0);        Element bidiElem = bidiRoot.getElement(index);        if(bidiElem.getEndOffset() >= p1) {            AttributeSet bidiAttrs = bidiElem.getAttributes();            return ((StyleConstants.getBidiLevel(bidiAttrs) % 2) == 0);        }        return true;    }     /**     * Get the paragraph element containing the given position.  Sub-classes     * must define for themselves what exactly constitutes a paragraph.  They     * should keep in mind however that a paragraph should at least be the     * unit of text over which to run the Unicode bidirectional algorithm.     *     * @param pos the starting offset >= 0     * @return the element */    public abstract Element getParagraphElement(int pos);      /**     * Fetches the context for managing attributes.  This     * method effectively establishes the strategy used     * for compressing AttributeSet information.     *     * @return the context     */    protected final AttributeContext getAttributeContext() {        return context;    }     /**     * Updates document structure as a result of text insertion.  This     * will happen within a write lock.  If a subclass of     * this class reimplements this method, it should delegate to the     * superclass as well.     *     * @param chng a description of the change     * @param attr the attributes for the change     */    protected void insertUpdate(DefaultDocumentEvent chng, AttributeSet attr) {        if( getProperty(I18NProperty).equals( Boolean.TRUE ) )            updateBidi( chng );         // Check if a multi byte is encountered in the inserted text.        if (chng.type == DocumentEvent.EventType.INSERT &&                        chng.getLength() > 0 &&                        !Boolean.TRUE.equals(getProperty(MultiByteProperty))) {            Segment segment = SegmentCache.getSharedSegment();            try {                getText(chng.getOffset(), chng.getLength(), segment);                segment.first();                do {                    if ((int)segment.current() > 255) {                        putProperty(MultiByteProperty, Boolean.TRUE);                        break;                    }                } while (segment.next() != Segment.DONE);            } catch (BadLocationException ble) {                // Should never happen            }            SegmentCache.releaseSharedSegment(segment);        }    }     /**     * Updates any document structure as a result of text removal.  This     * method is called before the text is actually removed from the Content.     * This will happen within a write lock. If a subclass     * of this class reimplements this method, it should delegate to the     * superclass as well.     *     * @param chng a description of the change     */    protected void removeUpdate(DefaultDocumentEvent chng) {    }     /**

Lines 501–1000 of 3118. Previous lines