diff options
Diffstat (limited to 'libjava/classpath/javax/swing/text')
25 files changed, 3559 insertions, 556 deletions
diff --git a/libjava/classpath/javax/swing/text/AbstractDocument.java b/libjava/classpath/javax/swing/text/AbstractDocument.java index c3a3d70ae37..3c9a4d497a5 100644 --- a/libjava/classpath/javax/swing/text/AbstractDocument.java +++ b/libjava/classpath/javax/swing/text/AbstractDocument.java @@ -56,70 +56,193 @@ import javax.swing.undo.AbstractUndoableEdit; import javax.swing.undo.CompoundEdit; import javax.swing.undo.UndoableEdit; +/** + * An abstract base implementation for the {@link Document} interface. + * This class provides some common functionality for all <code>Element</code>s, + * most notably it implements a locking mechanism to make document modification + * thread-safe. + * + * @author original author unknown + * @author Roman Kennke (roman@kennke.org) + */ public abstract class AbstractDocument implements Document, Serializable { + /** The serial version UID for this class as of JDK1.4. */ private static final long serialVersionUID = -116069779446114664L; - + + /** + * Standard error message to indicate a bad location. + */ protected static final String BAD_LOCATION = "document location failure"; - + + /** + * Standard name for unidirectional <code>Element</code>s. + */ public static final String BidiElementName = "bidi level"; + + /** + * Standard name for content <code>Element</code>s. These are usually + * {@link LeafElement}s. + */ public static final String ContentElementName = "content"; + + /** + * Standard name for paragraph <code>Element</code>s. These are usually + * {@link BranchElement}s. + */ public static final String ParagraphElementName = "paragraph"; + + /** + * Standard name for section <code>Element</code>s. These are usually + * {@link DefaultStyledDocument.SectionElement}s. + */ public static final String SectionElementName = "section"; + + /** + * Attribute key for storing the element name. + */ public static final String ElementNameAttribute = "$ename"; + /** + * The actual content model of this <code>Document</code>. + */ Content content; + + /** + * The AttributeContext for this <code>Document</code>. + */ AttributeContext context; + + /** + * The currently installed <code>DocumentFilter</code>. + */ DocumentFilter documentFilter; - /** The documents properties. */ + /** + * The documents properties. + */ Dictionary properties; + /** + * Manages event listeners for this <code>Document</code>. + */ protected EventListenerList listenerList = new EventListenerList(); + /** + * Creates a new <code>AbstractDocument</code> with the specified + * {@link Content} model. + * + * @param doc the <code>Content</code> model to be used in this + * <code>Document<code> + * + * @see GapContent + * @see StringContent + */ protected AbstractDocument(Content doc) { this(doc, StyleContext.getDefaultStyleContext()); } + /** + * Creates a new <code>AbstractDocument</code> with the specified + * {@link Content} model and {@link AttributeContext}. + * + * @param doc the <code>Content</code> model to be used in this + * <code>Document<code> + * @param ctx the <code>AttributeContext</code> to use + * + * @see GapContent + * @see StringContent + */ protected AbstractDocument(Content doc, AttributeContext ctx) { content = doc; context = ctx; } - // These still need to be implemented by a derived class: + /** + * Returns the paragraph {@link Element} that holds the specified position. + * + * @param pos the position for which to get the paragraph element + * + * @return the paragraph {@link Element} that holds the specified position + */ public abstract Element getParagraphElement(int pos); + /** + * Returns the default root {@link Element} of this <code>Document</code>. + * Usual <code>Document</code>s only have one root element and return this. + * However, there may be <code>Document</code> implementations that + * support multiple root elements, they have to return a default root element + * here. + * + * @return the default root {@link Element} of this <code>Document</code> + */ public abstract Element getDefaultRootElement(); + /** + * Creates and returns a branch element with the specified + * <code>parent</code> and <code>attributes</code>. Note that the new + * <code>Element</code> is linked to the parent <code>Element</code> + * through {@link Element#getParentElement}, but it is not yet added + * to the parent <code>Element</code> as child. + * + * @param parent the parent <code>Element</code> for the new branch element + * @param attributes the text attributes to be installed in the new element + * + * @return the new branch <code>Element</code> + * + * @see BranchElement + */ protected Element createBranchElement(Element parent, AttributeSet attributes) { return new BranchElement(parent, attributes); } + /** + * Creates and returns a leaf element with the specified + * <code>parent</code> and <code>attributes</code>. Note that the new + * <code>Element</code> is linked to the parent <code>Element</code> + * through {@link Element#getParentElement}, but it is not yet added + * to the parent <code>Element</code> as child. + * + * @param parent the parent <code>Element</code> for the new branch element + * @param attributes the text attributes to be installed in the new element + * + * @return the new branch <code>Element</code> + * + * @see LeafElement + */ protected Element createLeafElement(Element parent, AttributeSet attributes, int start, int end) { return new LeafElement(parent, attributes, start, end); } + /** + * Creates a {@link Position} that keeps track of the location at the + * specified <code>offset</code>. + * + * @param offset the location in the document to keep track by the new + * <code>Position</code> + * + * @return the newly created <code>Position</code> + * + * @throws BadLocationException if <code>offset</code> is not a valid + * location in the documents content model + */ public Position createPosition(final int offset) throws BadLocationException { - if (offset < 0 || offset > getLength()) - throw new BadLocationException(getText(0, getLength()), offset); - - return new Position() - { - public int getOffset() - { - return offset; - } - }; + return content.createPosition(offset); } + /** + * Notifies all registered listeners when the document model changes. + * + * @param event the <code>DocumentEvent</code> to be fired + */ protected void fireChangedUpdate(DocumentEvent event) { DocumentListener[] listeners = getDocumentListeners(); @@ -128,6 +251,12 @@ public abstract class AbstractDocument listeners[index].changedUpdate(event); } + /** + * Notifies all registered listeners when content is inserted in the document + * model. + * + * @param event the <code>DocumentEvent</code> to be fired + */ protected void fireInsertUpdate(DocumentEvent event) { DocumentListener[] listeners = getDocumentListeners(); @@ -136,6 +265,12 @@ public abstract class AbstractDocument listeners[index].insertUpdate(event); } + /** + * Notifies all registered listeners when content is removed from the + * document model. + * + * @param event the <code>DocumentEvent</code> to be fired + */ protected void fireRemoveUpdate(DocumentEvent event) { DocumentListener[] listeners = getDocumentListeners(); @@ -144,6 +279,12 @@ public abstract class AbstractDocument listeners[index].removeUpdate(event); } + /** + * Notifies all registered listeners when an <code>UndoableEdit</code> has + * been performed on this <code>Document</code>. + * + * @param event the <code>UndoableEditEvent</code> to be fired + */ protected void fireUndoableEditUpdate(UndoableEditEvent event) { UndoableEditListener[] listeners = getUndoableEditListeners(); @@ -152,31 +293,70 @@ public abstract class AbstractDocument listeners[index].undoableEditHappened(event); } + /** + * Returns the asynchronous loading priority. Returns <code>-1</code> if this + * document should not be loaded asynchronously. + * + * @return the asynchronous loading priority + */ public int getAsynchronousLoadPriority() { return 0; } + /** + * Returns the {@link AttributeContext} used in this <code>Document</code>. + * + * @return the {@link AttributeContext} used in this <code>Document</code> + */ protected AttributeContext getAttributeContext() { return context; } + /** + * Returns the root element for bidirectional content. + * + * @return the root element for bidirectional content + */ public Element getBidiRootElement() { return null; } + /** + * Returns the {@link Content} model for this <code>Document</code> + * + * @return the {@link Content} model for this <code>Document</code> + * + * @see GapContent + * @see StringContent + */ protected Content getContent() { return content; } + /** + * Returns the thread that currently modifies this <code>Document</code> + * if there is one, otherwise <code>null</code>. This can be used to + * distinguish between a method call that is part of an ongoing modification + * or if it is a separate modification for which a new lock must be aquired. + * + * @return the thread that currently modifies this <code>Document</code> + * if there is one, otherwise <code>null</code> + */ protected Thread getCurrentWriter() { + // FIXME: Implement locking! return null; } + /** + * Returns the properties of this <code>Document</code>. + * + * @return the properties of this <code>Document</code> + */ public Dictionary getDocumentProperties() { // FIXME: make me thread-safe @@ -186,8 +366,16 @@ public abstract class AbstractDocument return properties; } + /** + * Returns a {@link Position} which will always mark the end of the + * <code>Document</code>. + * + * @return a {@link Position} which will always mark the end of the + * <code>Document</code> + */ public Position getEndPosition() { + // FIXME: Properly implement this by calling Content.createPosition(). return new Position() { public int getOffset() @@ -197,16 +385,39 @@ public abstract class AbstractDocument }; } + /** + * Returns the length of this <code>Document</code>'s content. + * + * @return the length of this <code>Document</code>'s content + */ public int getLength() { + // We return Content.getLength() -1 here because there is always an + // implicit \n at the end of the Content which does count in Content + // but not in Document. return content.length() - 1; } + /** + * Returns all registered listeners of a given listener type. + * + * @param listenerType the type of the listeners to be queried + * + * @return all registered listeners of the specified type + */ public EventListener[] getListeners(Class listenerType) { return listenerList.getListeners(listenerType); } + /** + * Returns a property from this <code>Document</code>'s property list. + * + * @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 @@ -217,6 +428,15 @@ public abstract class AbstractDocument 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]; @@ -224,8 +444,16 @@ public abstract class AbstractDocument 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() @@ -235,17 +463,53 @@ public abstract class AbstractDocument }; } + /** + * 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 { @@ -261,14 +525,37 @@ public abstract class AbstractDocument fireInsertUpdate(event); } + /** + * 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 @@ -278,14 +565,31 @@ public abstract class AbstractDocument properties.put(key, value); } + /** + * Blocks until a read lock can be obtained. + */ public void readLock() { } + /** + * Releases the read lock. If this was the only reader on this + * <code>Document</code>, writing may begin now. + */ public void readUnlock() { } + /** + * 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 = @@ -298,7 +602,17 @@ public abstract class AbstractDocument } /** - * Replaces some text in the document. + * 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 */ @@ -331,9 +645,9 @@ public abstract class AbstractDocument } /** - * Returns add added <code>DocumentListener</code> objects. + * Returns all registered <code>DocumentListener</code>s. * - * @return an array of listeners + * @return all registered <code>DocumentListener</code>s */ public DocumentListener[] getDocumentListeners() { @@ -341,7 +655,7 @@ public abstract class AbstractDocument } /** - * Adds a <code>UndoableEditListener</code> object to this document. + * Adds an {@link UndoableEditListener} to this <code>Document</code>. * * @param listener the listener to add */ @@ -351,7 +665,7 @@ public abstract class AbstractDocument } /** - * Removes a <code>UndoableEditListener</code> object from this document. + * Removes an {@link UndoableEditListener} from this <code>Document</code>. * * @param listener the listener to remove */ @@ -361,42 +675,93 @@ public abstract class AbstractDocument } /** - * Returns add added <code>UndoableEditListener</code> objects. + * Returns all registered {@link UndoableEditListener}s. * - * @return an array of listeners + * @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. } - public void render(Runnable r) + /** + * 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) { + // FIXME: Implement me! } + /** + * 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) { } - public void setDocumentProperties(Dictionary x) + /** + * 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 = x; + properties = p; } + /** + * Blocks until a write lock can be obtained. + */ protected void writeLock() { + // FIXME: Implement me. } + /** + * Releases the write lock. This allows waiting readers or writers to + * obtain the lock. + */ protected void writeUnlock() { + // FIXME: Implement me. } /** + * Returns the currently installed {@link DocumentFilter} for this + * <code>Document</code>. + * + * @return the currently installed {@link DocumentFilter} for this + * <code>Document</code> + * * @since 1.4 */ public DocumentFilter getDocumentFilter() @@ -405,6 +770,10 @@ public abstract class AbstractDocument } /** + * Sets the {@link DocumentFilter} for this <code>Document</code>. + * + * @param filter the <code>DocumentFilter</code> to set + * * @since 1.4 */ public void setDocumentFilter(DocumentFilter filter) @@ -412,209 +781,592 @@ public abstract class AbstractDocument this.documentFilter = filter; } + /** + * Dumps diagnostic information to the specified <code>PrintStream</code>. + * + * @param out the stream to write the diagnostic information to + */ public void dump(PrintStream out) { ((AbstractElement) getDefaultRootElement()).dump(out, 0); } + /** + * Defines a set of methods for managing text attributes for one or more + * <code>Document</code>s. + * + * Replicating {@link AttributeSet}s throughout a <code>Document</code> can + * be very expensive. Implementations of this interface are intended to + * provide intelligent management of <code>AttributeSet</code>s, eliminating + * costly duplication. + * + * @see StyleContext + */ public interface AttributeContext { + /** + * Returns an {@link AttributeSet} that contains the attributes + * of <code>old</code> plus the new attribute specified by + * <code>name</code> and <code>value</code>. + * + * @param old the attribute set to be merged with the new attribute + * @param name the name of the attribute to be added + * @param value the value of the attribute to be added + * + * @return the old attributes plus the new attribute + */ AttributeSet addAttribute(AttributeSet old, Object name, Object value); + /** + * Returns an {@link AttributeSet} that contains the attributes + * of <code>old</code> plus the new attributes in <code>attributes</code>. + * + * @param old the set of attributes where to add the new attributes + * @param attributes the attributes to be added + * + * @return an {@link AttributeSet} that contains the attributes + * of <code>old</code> plus the new attributes in + * <code>attributes</code> + */ AttributeSet addAttributes(AttributeSet old, AttributeSet attributes); + /** + * Returns an empty {@link AttributeSet}. + * + * @return an empty {@link AttributeSet} + */ AttributeSet getEmptySet(); + /** + * Called to indicate that the attributes in <code>attributes</code> are + * no longer used. + * + * @param attributes the attributes are no longer used + */ void reclaim(AttributeSet attributes); + /** + * Returns a {@link AttributeSet} that has the attribute with the specified + * <code>name</code> removed from <code>old</code>. + * + * @param old the attribute set from which an attribute is removed + * @param name the name of the attribute to be removed + * + * @return the attributes of <code>old</code> minus the attribute + * specified by <code>name</code> + */ AttributeSet removeAttribute(AttributeSet old, Object name); + /** + * Removes all attributes in <code>attributes</code> from <code>old</code> + * and returns the resulting <code>AttributeSet</code>. + * + * @param old the set of attributes from which to remove attributes + * @param attributes the attributes to be removed from <code>old</code> + * + * @return the attributes of <code>old</code> minus the attributes in + * <code>attributes</code> + */ AttributeSet removeAttributes(AttributeSet old, AttributeSet attributes); + /** + * Removes all attributes specified by <code>names</code> from + * <code>old</code> and returns the resulting <code>AttributeSet</code>. + * + * @param old the set of attributes from which to remove attributes + * @param names the names of the attributes to be removed from + * <code>old</code> + * + * @return the attributes of <code>old</code> minus the attributes in + * <code>attributes</code> + */ AttributeSet removeAttributes(AttributeSet old, Enumeration names); } + /** + * A sequence of data that can be edited. This is were the actual content + * in <code>AbstractDocument</code>'s is stored. + */ public interface Content { + /** + * Creates a {@link Position} that keeps track of the location at + * <code>offset</code>. + * + * @return a {@link Position} that keeps track of the location at + * <code>offset</code>. + * + * @throw BadLocationException if <code>offset</code> is not a valid + * location in this <code>Content</code> model + */ Position createPosition(int offset) throws BadLocationException; + /** + * Returns the length of the content. + * + * @return the length of the content + */ int length(); + /** + * Inserts a string into the content model. + * + * @param where the offset at which to insert the string + * @param str the string to be inserted + * + * @return an <code>UndoableEdit</code> or <code>null</code> if undo is + * not supported by this <code>Content</code> model + * + * @throws BadLocationException if <code>where</code> is not a valid + * location in this <code>Content</code> model + */ UndoableEdit insertString(int where, String str) throws BadLocationException; + /** + * Removes a piece of content from the content model. + * + * @param where the offset at which to remove content + * @param nitems the number of characters to be removed + * + * @return an <code>UndoableEdit</code> or <code>null</code> if undo is + * not supported by this <code>Content</code> model + * + * @throws BadLocationException if <code>where</code> is not a valid + * location in this <code>Content</code> model + */ UndoableEdit remove(int where, int nitems) throws BadLocationException; + /** + * Returns a piece of content. + * + * @param where the start offset of the requested fragment + * @param len the length of the requested fragment + * + * @return the requested fragment + * @throws BadLocationException if <code>offset</code> or + * <code>offset + len</code>is not a valid + * location in this <code>Content</code> model + */ String getString(int where, int len) throws BadLocationException; + /** + * Fetches a piece of content and stores it in <code>txt</code>. + * + * @param where the start offset of the requested fragment + * @param len the length of the requested fragment + * @param txt the <code>Segment</code> where to fragment is stored into + * + * @throws BadLocationException if <code>offset</code> or + * <code>offset + len</code>is not a valid + * location in this <code>Content</code> model + */ void getChars(int where, int len, Segment txt) throws BadLocationException; } + /** + * An abstract base implementation of the {@link Element} interface. + */ public abstract class AbstractElement implements Element, MutableAttributeSet, TreeNode, Serializable { + /** The serial version UID for AbstractElement. */ private static final long serialVersionUID = 1265312733007397733L; + + /** The number of characters that this Element spans. */ int count; + + /** The starting offset of this Element. */ int offset; + /** The attributes of this Element. */ AttributeSet attributes; + /** The parent element. */ Element element_parent; + /** The parent in the TreeNode interface. */ TreeNode tree_parent; + + /** The children of this element. */ Vector tree_children; + /** + * Creates a new instance of <code>AbstractElement</code> with a + * specified parent <code>Element</code> and <code>AttributeSet</code>. + * + * @param p the parent of this <code>AbstractElement</code> + * @param s the attributes to be assigned to this + * <code>AbstractElement</code> + */ public AbstractElement(Element p, AttributeSet s) { element_parent = p; - attributes = s; + AttributeContext ctx = getAttributeContext(); + attributes = ctx.getEmptySet(); + if (s != null) + attributes = ctx.addAttributes(attributes, s); } - // TreeNode implementation - + /** + * Returns the child nodes of this <code>Element</code> as an + * <code>Enumeration</code> of {@link TreeNode}s. + * + * @return the child nodes of this <code>Element</code> as an + * <code>Enumeration</code> of {@link TreeNode}s + */ public abstract Enumeration children(); - + + /** + * Returns <code>true</code> if this <code>AbstractElement</code> + * allows children. + * + * @return <code>true</code> if this <code>AbstractElement</code> + * allows children + */ public abstract boolean getAllowsChildren(); - + + /** + * Returns the child of this <code>AbstractElement</code> at + * <code>index</code>. + * + * @param index the position in the child list of the child element to + * be returned + * + * @return the child of this <code>AbstractElement</code> at + * <code>index</code> + */ public TreeNode getChildAt(int index) { return (TreeNode) tree_children.get(index); } - + + /** + * Returns the number of children of this <code>AbstractElement</code>. + * + * @return the number of children of this <code>AbstractElement</code> + */ public int getChildCount() { return tree_children.size(); } - + + /** + * Returns the index of a given child <code>TreeNode</code> or + * <code>-1</code> if <code>node</code> is not a child of this + * <code>AbstractElement</code>. + * + * @param node the node for which the index is requested + * + * @return the index of a given child <code>TreeNode</code> or + * <code>-1</code> if <code>node</code> is not a child of this + * <code>AbstractElement</code> + */ public int getIndex(TreeNode node) { return tree_children.indexOf(node); } + /** + * Returns the parent <code>TreeNode</code> of this + * <code>AbstractElement</code> or <code>null</code> if this element + * has no parent. + * + * @return the parent <code>TreeNode</code> of this + * <code>AbstractElement</code> or <code>null</code> if this + * element has no parent + */ public TreeNode getParent() { return tree_parent; } + /** + * Returns <code>true</code> if this <code>AbstractElement</code> is a + * leaf element, <code>false</code> otherwise. + * + * @return <code>true</code> if this <code>AbstractElement</code> is a + * leaf element, <code>false</code> otherwise + */ public abstract boolean isLeaf(); - - // MutableAttributeSet support - + /** + * Adds an attribute to this element. + * + * @param name the name of the attribute to be added + * @param value the value of the attribute to be added + */ public void addAttribute(Object name, Object value) { attributes = getAttributeContext().addAttribute(attributes, name, value); } + /** + * Adds a set of attributes to this element. + * + * @param attrs the attributes to be added to this element + */ public void addAttributes(AttributeSet attrs) { attributes = getAttributeContext().addAttributes(attributes, attrs); } + /** + * Removes an attribute from this element. + * + * @param name the name of the attribute to be removed + */ public void removeAttribute(Object name) { attributes = getAttributeContext().removeAttribute(attributes, name); } + /** + * Removes a set of attributes from this element. + * + * @param attrs the attributes to be removed + */ public void removeAttributes(AttributeSet attrs) { attributes = getAttributeContext().removeAttributes(attributes, attrs); } + /** + * Removes a set of attribute from this element. + * + * @param names the names of the attributes to be removed + */ public void removeAttributes(Enumeration names) { attributes = getAttributeContext().removeAttributes(attributes, names); } + /** + * Sets the parent attribute set against which the element can resolve + * attributes that are not defined in itself. + * + * @param parent the resolve parent to set + */ public void setResolveParent(AttributeSet parent) { - attributes = getAttributeContext().addAttribute(attributes, ResolveAttribute, parent); + attributes = getAttributeContext().addAttribute(attributes, + ResolveAttribute, + parent); } - - // AttributeSet interface support - + /** + * Returns <code>true</code> if this element contains the specified + * attribute. + * + * @param name the name of the attribute to check + * @param value the value of the attribute to check + * + * @return <code>true</code> if this element contains the specified + * attribute + */ public boolean containsAttribute(Object name, Object value) { return attributes.containsAttribute(name, value); } + /** + * Returns <code>true</code> if this element contains all of the + * specified attributes. + * + * @param attrs the attributes to check + * + * @return <code>true</code> if this element contains all of the + * specified attributes + */ public boolean containsAttributes(AttributeSet attrs) { return attributes.containsAttributes(attrs); } + /** + * Returns a copy of the attributes of this element. + * + * @return a copy of the attributes of this element + */ public AttributeSet copyAttributes() { return attributes.copyAttributes(); } + /** + * Returns the attribute value with the specified key. If this attribute + * is not defined in this element and this element has a resolving + * parent, the search goes upward to the resolve parent chain. + * + * @param key the key of the requested attribute + * + * @return the attribute value for <code>key</code> of <code>null</code> + * if <code>key</code> is not found locally and cannot be resolved + * in this element's resolve parents + */ public Object getAttribute(Object key) { return attributes.getAttribute(key); } + /** + * Returns the number of defined attributes in this element. + * + * @return the number of defined attributes in this element + */ public int getAttributeCount() { return attributes.getAttributeCount(); } - + + /** + * Returns the names of the attributes of this element. + * + * @return the names of the attributes of this element + */ public Enumeration getAttributeNames() { return attributes.getAttributeNames(); } - + + /** + * Returns the resolve parent of this element. + * + * @return the resolve parent of this element + * + * @see #setResolveParent(AttributeSet) + */ public AttributeSet getResolveParent() { return attributes.getResolveParent(); } + /** + * Returns <code>true</code> if an attribute with the specified name + * is defined in this element, <code>false</code> otherwise. + * + * @param attrName the name of the requested attributes + * + * @return <code>true</code> if an attribute with the specified name + * is defined in this element, <code>false</code> otherwise + */ public boolean isDefined(Object attrName) { return attributes.isDefined(attrName); } - + + /** + * Returns <code>true</code> if the specified <code>AttributeSet</code> + * is equal to this element's <code>AttributeSet</code>, <code>false</code> + * otherwise. + * + * @param attrs the attributes to compare this element to + * + * @return <code>true</code> if the specified <code>AttributeSet</code> + * is equal to this element's <code>AttributeSet</code>, + * <code>false</code> otherwise + */ public boolean isEqual(AttributeSet attrs) { return attributes.isEqual(attrs); } - // Element interface support - + /** + * Returns the attributes of this element. + * + * @return the attributes of this element + */ public AttributeSet getAttributes() { - return attributes; + return this; } + /** + * Returns the {@link Document} to which this element belongs. + * + * @return the {@link Document} to which this element belongs + */ public Document getDocument() { return AbstractDocument.this; } - + + /** + * Returns the child element at the specified <code>index</code>. + * + * @param index the index of the requested child element + * + * @return the requested element + */ public abstract Element getElement(int index); - + + /** + * Returns the name of this element. + * + * @return the name of this element + */ public String getName() { return (String) getAttribute(NameAttribute); } - + + /** + * Returns the parent element of this element. + * + * @return the parent element of this element + */ public Element getParentElement() { return element_parent; } - + + /** + * Returns the offset inside the document model that is after the last + * character of this element. + * + * @return the offset inside the document model that is after the last + * character of this element + */ public abstract int getEndOffset(); - + + /** + * Returns the number of child elements of this element. + * + * @return the number of child elements of this element + */ public abstract int getElementCount(); - + + /** + * Returns the index of the child element that spans the specified + * offset in the document model. + * + * @param offset the offset for which the responsible element is searched + * + * @return the index of the child element that spans the specified + * offset in the document model + */ public abstract int getElementIndex(int offset); - + + /** + * Returns the start offset if this element inside the document model. + * + * @return the start offset if this element inside the document model + */ public abstract int getStartOffset(); - private void dumpElement(PrintStream stream, String indent, Element element) + /** + * Prints diagnostic information to the specified stream. + * + * @param stream the stream to dump to + * @param indent the indentation level + * @param element the element to be dumped + */ + private void dumpElement(PrintStream stream, String indent, + Element element) { + // FIXME: Should the method be removed? System.out.println(indent + "<" + element.getName() +">"); - + if (element.isLeaf()) { int start = element.getStartOffset(); @@ -626,6 +1378,12 @@ public abstract class AbstractDocument } catch (BadLocationException e) { + AssertionError error = + new AssertionError("BadLocationException should not be " + + "thrown here. start = " + start + + ", end = " + end); + error.initCause(e); + throw error; } System.out.println(indent + " [" + start + "," @@ -638,7 +1396,13 @@ public abstract class AbstractDocument dumpElement(stream, indent + " ", element.getElement(i)); } } - + + /** + * Prints diagnostic output to the specified stream. + * + * @param stream the stream to write to + * @param indent the indentation level + */ public void dump(PrintStream stream, int indent) { String indentStr = ""; @@ -648,17 +1412,36 @@ public abstract class AbstractDocument } } + /** + * An implementation of {@link Element} to represent composite + * <code>Element</code>s that contain other <code>Element</code>s. + */ public class BranchElement extends AbstractElement { + /** The serial version UID for BranchElement. */ private static final long serialVersionUID = -8595176318868717313L; - + + /** The child elements of this BranchElement. */ private Element[] children = new Element[0]; + /** + * Creates a new <code>BranchElement</code> with the specified + * parent and attributes. + * + * @param parent the parent element of this <code>BranchElement</code> + * @param attributes the attributes to set on this + * <code>BranchElement</code> + */ public BranchElement(Element parent, AttributeSet attributes) { super(parent, attributes); } + /** + * Returns the children of this <code>BranchElement</code>. + * + * @return the children of this <code>BranchElement</code> + */ public Enumeration children() { if (children.length == 0) @@ -672,11 +1455,25 @@ public abstract class AbstractDocument return tmp.elements(); } + /** + * Returns <code>true</code> since <code>BranchElements</code> allow + * child elements. + * + * @return <code>true</code> since <code>BranchElements</code> allow + * child elements + */ public boolean getAllowsChildren() { return true; } + /** + * Returns the child element at the specified <code>index</code>. + * + * @param index the index of the requested child element + * + * @return the requested element + */ public Element getElement(int index) { if (index < 0 || index >= children.length) @@ -685,47 +1482,113 @@ public abstract class AbstractDocument return children[index]; } + /** + * Returns the number of child elements of this element. + * + * @return the number of child elements of this element + */ public int getElementCount() { return children.length; } + /** + * Returns the index of the child element that spans the specified + * offset in the document model. + * + * @param offset the offset for which the responsible element is searched + * + * @return the index of the child element that spans the specified + * offset in the document model + */ public int getElementIndex(int offset) { + // If we have no children, return -1. + if (getElementCount() == 0) + return - 1; + // XXX: There is surely a better algorithm // as beginning from first element each time. for (int index = 0; index < children.length; ++index) { - Element elem = children[index]; + Element elem = children[index]; - if ((elem.getStartOffset() <= offset) - && (offset < elem.getEndOffset())) - return index; + if ((elem.getStartOffset() <= offset) + && (offset < elem.getEndOffset())) + return index; } - return 0; + // If offset is greater than the index of the last element, return + // the index of the last element. + return getElementCount() - 1; } + /** + * Returns the offset inside the document model that is after the last + * character of this element. + * This is the end offset of the last child element. If this element + * has no children, this method throws a <code>NullPointerException</code>. + * + * @return the offset inside the document model that is after the last + * character of this element + * + * @throws NullPointerException if this branch element has no children + */ public int getEndOffset() { + if (getElementCount() == 0) + throw new NullPointerException("This BranchElement has no children."); return children[children.length - 1].getEndOffset(); } + /** + * Returns the name of this element. This is {@link #ParagraphElementName} + * in this case. + * + * @return the name of this element + */ public String getName() { return ParagraphElementName; } + /** + * Returns the start offset of this element inside the document model. + * This is the start offset of the first child element. If this element + * has no children, this method throws a <code>NullPointerException</code>. + * + * @return the start offset of this element inside the document model + * + * @throws NullPointerException if this branch element has no children + */ public int getStartOffset() { + if (getElementCount() == 0) + throw new NullPointerException("This BranchElement has no children."); return children[0].getStartOffset(); } + /** + * Returns <code>false</code> since <code>BranchElement</code> are no + * leafes. + * + * @return <code>false</code> since <code>BranchElement</code> are no + * leafes + */ public boolean isLeaf() { return false; } + /** + * Returns the <code>Element</code> at the specified <code>Document</code> + * offset. + * + * @return the <code>Element</code> at the specified <code>Document</code> + * offset + * + * @see #getElementIndex(int) + */ public Element positionToElement(int position) { // XXX: There is surely a better algorithm @@ -742,6 +1605,13 @@ public abstract class AbstractDocument return null; } + /** + * Replaces a set of child elements with a new set of child elemens. + * + * @param offset the start index of the elements to be removed + * @param length the number of elements to be removed + * @param elements the new elements to be inserted + */ public void replace(int offset, int length, Element[] elements) { Element[] target = new Element[children.length - length @@ -754,6 +1624,11 @@ public abstract class AbstractDocument children = target; } + /** + * Returns a string representation of this element. + * + * @return a string representation of this element + */ public String toString() { return ("BranchElement(" + getName() + ") " @@ -761,59 +1636,157 @@ public abstract class AbstractDocument } } + /** + * Stores the changes when a <code>Document</code> is beeing modified. + */ public class DefaultDocumentEvent extends CompoundEdit implements DocumentEvent { + /** The serial version UID of DefaultDocumentEvent. */ private static final long serialVersionUID = -7406103236022413522L; - + + /** The starting offset of the change. */ private int offset; + + /** The length of the change. */ private int length; + + /** The type of change. */ private DocumentEvent.EventType type; + /** + * Maps <code>Element</code> to their change records. + */ + Hashtable changes; + + /** + * Creates a new <code>DefaultDocumentEvent</code>. + * + * @param offset the starting offset of the change + * @param length the length of the change + * @param type the type of change + */ public DefaultDocumentEvent(int offset, int length, DocumentEvent.EventType type) { this.offset = offset; this.length = length; this.type = type; + changes = new Hashtable(); } + /** + * Adds an UndoableEdit to this <code>DocumentEvent</code>. If this + * edit is an instance of {@link ElementEdit}, then this record can + * later be fetched by calling {@link #getChange}. + * + * @param edit the undoable edit to add + */ + public boolean addEdit(UndoableEdit edit) + { + // XXX - Fully qualify ElementChange to work around gcj bug #2499. + if (edit instanceof DocumentEvent.ElementChange) + { + DocumentEvent.ElementChange elEdit = + (DocumentEvent.ElementChange) edit; + changes.put(elEdit.getElement(), elEdit); + } + return super.addEdit(edit); + } + + /** + * Returns the document that has been modified. + * + * @return the document that has been modified + */ public Document getDocument() { return AbstractDocument.this; } + /** + * Returns the length of the modification. + * + * @return the length of the modification + */ public int getLength() { return length; } + /** + * Returns the start offset of the modification. + * + * @return the start offset of the modification + */ public int getOffset() { return offset; } + /** + * Returns the type of the modification. + * + * @return the type of the modification + */ public DocumentEvent.EventType getType() { return type; } + /** + * Returns the changes for an element. + * + * @param elem the element for which the changes are requested + * + * @return the changes for <code>elem</code> or <code>null</code> if + * <code>elem</code> has not been changed + */ public DocumentEvent.ElementChange getChange(Element elem) { - return null; + // XXX - Fully qualify ElementChange to work around gcj bug #2499. + return (DocumentEvent.ElementChange) changes.get(elem); } } + /** + * An implementation of {@link DocumentEvent.ElementChange} to be added + * to {@link DefaultDocumentEvent}s. + */ public static class ElementEdit extends AbstractUndoableEdit implements DocumentEvent.ElementChange { + /** The serial version UID of ElementEdit. */ private static final long serialVersionUID = -1216620962142928304L; + /** + * The changed element. + */ private Element elem; + + /** + * The index of the change. + */ private int index; + + /** + * The removed elements. + */ private Element[] removed; + + /** + * The added elements. + */ private Element[] added; + /** + * Creates a new <code>ElementEdit</code>. + * + * @param elem the changed element + * @param index the index of the change + * @param removed the removed elements + * @param added the added elements + */ public ElementEdit(Element elem, int index, Element[] removed, Element[] added) { @@ -823,86 +1796,211 @@ public abstract class AbstractDocument this.added = added; } + /** + * Returns the added elements. + * + * @return the added elements + */ public Element[] getChildrenAdded() { return added; } - + + /** + * Returns the removed elements. + * + * @return the removed elements + */ public Element[] getChildrenRemoved() { return removed; } + /** + * Returns the changed element. + * + * @return the changed element + */ public Element getElement() { return elem; } + /** + * Returns the index of the change. + * + * @return the index of the change + */ public int getIndex() { return index; } } + /** + * An implementation of {@link Element} that represents a leaf in the + * document structure. This is used to actually store content. + */ public class LeafElement extends AbstractElement { + /** The serial version UID of LeafElement. */ private static final long serialVersionUID = 5115368706941283802L; - int start; - int end; + /** Manages the start offset of this element. */ + Position startPos; + + /** Manages the end offset of this element. */ + Position endPos; + + /** + * Creates a new <code>LeafElement</code>. + * + * @param parent the parent of this <code>LeafElement</code> + * @param attributes the attributes to be set + * @param start the start index of this element inside the document model + * @param end the end index of this element inside the document model + */ public LeafElement(Element parent, AttributeSet attributes, int start, int end) { super(parent, attributes); - this.start = start; - this.end = end; + { + try + { + if (parent != null) + { + startPos = parent.getDocument().createPosition(start); + endPos = parent.getDocument().createPosition(end); + } + else + { + startPos = createPosition(start); + endPos = createPosition(end); + } + } + catch (BadLocationException ex) + { + AssertionError as; + as = new AssertionError("BadLocationException thrown " + + "here. start=" + start + + ", end=" + end + + ", length=" + getLength()); + as.initCause(ex); + throw as; + } + } } + /** + * Returns <code>null</code> since <code>LeafElement</code>s cannot have + * children. + * + * @return <code>null</code> since <code>LeafElement</code>s cannot have + * children + */ public Enumeration children() { return null; } + /** + * Returns <code>false</code> since <code>LeafElement</code>s cannot have + * children. + * + * @return <code>false</code> since <code>LeafElement</code>s cannot have + * children + */ public boolean getAllowsChildren() { return false; } + /** + * Returns <code>null</code> since <code>LeafElement</code>s cannot have + * children. + * + * @return <code>null</code> since <code>LeafElement</code>s cannot have + * children + */ public Element getElement(int index) { return null; } + /** + * Returns <code>0</code> since <code>LeafElement</code>s cannot have + * children. + * + * @return <code>0</code> since <code>LeafElement</code>s cannot have + * children + */ public int getElementCount() { return 0; } + /** + * Returns <code>-1</code> since <code>LeafElement</code>s cannot have + * children. + * + * @return <code>-1</code> since <code>LeafElement</code>s cannot have + * children + */ public int getElementIndex(int offset) { return -1; } + /** + * Returns the end offset of this <code>Element</code> inside the + * document. + * + * @return the end offset of this <code>Element</code> inside the + * document + */ public int getEndOffset() { - return end; + return endPos.getOffset(); } + /** + * Returns the name of this <code>Element</code>. This is + * {@link #ContentElementName} in this case. + * + * @return the name of this <code>Element</code> + */ public String getName() { return ContentElementName; } + /** + * Returns the start offset of this <code>Element</code> inside the + * document. + * + * @return the start offset of this <code>Element</code> inside the + * document + */ public int getStartOffset() { - return start; + return startPos.getOffset(); } + /** + * Returns <code>true</code>. + * + * @return <code>true</code> + */ public boolean isLeaf() { return true; } + /** + * Returns a string representation of this <code>Element</code>. + * + * @return a string representation of this <code>Element</code> + */ public String toString() { return ("LeafElement(" + getName() + ") " diff --git a/libjava/classpath/javax/swing/text/AttributeSet.java b/libjava/classpath/javax/swing/text/AttributeSet.java index 87e7b98af22..2f1f1890bae 100644 --- a/libjava/classpath/javax/swing/text/AttributeSet.java +++ b/libjava/classpath/javax/swing/text/AttributeSet.java @@ -1,5 +1,5 @@ /* AttributeSet.java -- - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -39,34 +39,153 @@ package javax.swing.text; import java.util.Enumeration; +/** + * A set of attributes. An attribute has a key and a value. They typically + * describe features of a piece of text that make up its graphical + * representation. + * + * An <code>AttributeSet</code> may have a resolving parent, + * that is another <code>AttributeSet</code> that is searched for attribute + * keys that are not stored locally in this <code>AttributeSet</code>. + * + * @author original author unknown + * @author Roman Kennke (roman@kennke.org) + */ public interface AttributeSet { + /** + * Used as keys to identify character-run attributes. + */ static interface CharacterAttribute { } + /** + * Used as keys to identify color attributes. + */ static interface ColorAttribute { } + /** + * Used as keys to identify font attributes. + */ static interface FontAttribute { } + /** + * Used as keys to identify paragraph level attributes. + */ static interface ParagraphAttribute { } + /** + * Key of the attribute that is used to describe the name of an + * <code>AttributeSet</code>. + */ Object NameAttribute = StyleConstants.NameAttribute; + + /** + * Key of the attribute that is used to identify the resolving parent of + * an <code>AttributeSet</code>. + */ Object ResolveAttribute = StyleConstants.ResolveAttribute; + /** + * Returns <code>true</code> if this <code>AttributeSet</code> contains + * an attribute with the specified <code>name</code> and <code>value</code>, + * <code>false</code> otherwise. + * + * @param name the name of the requested attribute + * @param the value of the requested attribute + * + * @return <code>true</code> if this <code>AttributeSet</code> contains + * an attribute with the specified <code>name</code> and + * <code>value</code>, <code>false</code> otherwise + */ boolean containsAttribute(Object name, Object value); + + /** + * Returns <code>true</code> of this <code>AttributeSet</code> contains all + * of the specified <code>attributes</code>. + * + * @param attributes the requested attributes + * + * @return <code>true</code> of this <code>AttributeSet</code> contains all + * of the specified <code>attributes</code> + */ boolean containsAttributes(AttributeSet attributes); + + /** + * Creates and returns a copy of this <code>AttributeSet</code>. + * + * @return a copy of this <code>AttributeSet</code> + */ AttributeSet copyAttributes(); + + /** + * Returns the attribute with the specified <code>key</code> or + * <code>null</code> if no such attribute is defined in this + * <code>AttributeSet</code> and its resolving parents. + * + * @param key the key of the attribute that is looked up + * + * @return the attribute with the specified <code>key</code> or + * <code>null</code> if no such attribute is defined in this + * <code>AttributeSet</code> and its resolving parents + */ Object getAttribute(Object key); + + /** + * Returns the number of attributes that are stored locally in this + * <code>AttributeSet</code>. + * + * @return the number of attributes that are stored locally in this + * <code>AttributeSet</code> + */ int getAttributeCount(); + + /** + * Returns the names of the attributes that are stored in this + * <code>AttributeSet</code>. + * + * @return the names of the attributes that are stored in this + * <code>AttributeSet</code> + */ Enumeration getAttributeNames(); + + /** + * Returns the resolving parent of this <code>AttributeSet</code>. + * If a key is not stored locally, then a {@link #getAttribute(Object)} + * request is resolved up in the resolving parent of this + * <code>AttributeSet</code>. + * + * @return the resolving parent of this <code>AttributeSet</code> + */ AttributeSet getResolveParent(); + + /** + * Returns <code>true</code> if an attribute with the specified name is + * defined locally in this <code>AttributeSet</code>, without resolving + * through the resolving parents. + * + * @return <code>true</code> if an attribute with the specified name is + * defined locally in this <code>AttributeSet</code> + */ boolean isDefined(Object attrName); + + /** + * Returns <code>true</code> if all of the attributes in <code>attr</code> + * are equal to the attributes in this <code>AttributeSet</code>, + * <code>false</code> otherwise. + * + * @param attr the attributes to be compared to <code>this</code> + * + * @return <code>true</code> if all of the attributes in <code>attr</code> + * are equal to the attributes in this <code>AttributeSet</code>, + * <code>false</code> otherwise + */ boolean isEqual(AttributeSet attr); } diff --git a/libjava/classpath/javax/swing/text/BadLocationException.java b/libjava/classpath/javax/swing/text/BadLocationException.java index e1a2ebcc604..70591402cac 100644 --- a/libjava/classpath/javax/swing/text/BadLocationException.java +++ b/libjava/classpath/javax/swing/text/BadLocationException.java @@ -1,5 +1,5 @@ /* BadLocationException.java -- - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -37,17 +37,28 @@ exception statement from your version. */ package javax.swing.text; +/** + * Indicates that an invalid location within a <code>Document</code> has been + * accessed. + * + * @author original author unknown + * @author Roman Kennke (roman@kennke.org) + */ public class BadLocationException extends Exception { + /** The serial version UID for BadLocationException. */ private static final long serialVersionUID = -7712259886815656766L; - + + /** + * The invalid location. + */ int offset; /** * Constructs a <code>BadLocationException</code> * - * @param str A string indicating what was wrong with the arguments - * @param offset Offset within the document that was requested >= 0 + * @param str a string indicating what was wrong with the arguments + * @param offset offset within the document that was requested >= 0 */ public BadLocationException(String str, int offset) { @@ -56,7 +67,9 @@ public class BadLocationException extends Exception } /** - * Returns the offset into the document that was not legal + * Returns the offset into the document that was not legal. + * + * @return the offset into the document that was not legal */ public int offsetRequested() { diff --git a/libjava/classpath/javax/swing/text/Caret.java b/libjava/classpath/javax/swing/text/Caret.java index 46072ef19c5..d6411905dda 100644 --- a/libjava/classpath/javax/swing/text/Caret.java +++ b/libjava/classpath/javax/swing/text/Caret.java @@ -1,5 +1,5 @@ /* Caret.java -- - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -43,39 +43,165 @@ import java.awt.Point; import javax.swing.event.ChangeListener; +/** + * Defines the method to be implemented by a caret that can be used in Swing + * text components. + * + * @author original author unknown + * @author Roman Kennke (roman@kennke.org) + */ public interface Caret { + /** + * Registers a {@link ChangeListener} that is notified whenever that state + * of this <code>Caret</code> changes. + * + * @param l the listener to register to this caret + */ void addChangeListener(ChangeListener l); + + /** + * Removes a {@link ChangeListener} from the list of registered listeners. + * + * @param l the listener to remove + */ + void removeChangeListener(ChangeListener l); + + /** + * Installs this <code>Caret</code> on the specified text component. This + * usually involves setting up listeners. + * + * This method is called by {@link JTextComponent#setCaret(Caret)} after + * this caret has been set on the text component. + * + * @param c the text component to install this caret to + */ + void install(JTextComponent c); + /** + * Deinstalls this <code>Caret</code> from the specified text component. + * This usually involves removing listeners from the text component. + * + * This method is called by {@link JTextComponent#setCaret(Caret)} before + * this caret is removed from the text component. + * + * @param c the text component to deinstall this caret from + */ void deinstall(JTextComponent c); - + + /** + * Returns the blink rate of this <code>Caret</code> in milliseconds. + * A value of <code>0</code> means that the caret does not blink. + * + * @return the blink rate of this <code>Caret</code> or <code>0</code> if + * this caret does not blink + */ int getBlinkRate(); + + /** + * Sets the blink rate of this <code>Caret</code> in milliseconds. + * A value of <code>0</code> means that the caret does not blink. + * + * @param rate the new blink rate to set + */ + void setBlinkRate(int rate); + /** + * Returns the current position of this <code>Caret</code> within the + * <code>Document</code>. + * + * @return the current position of this <code>Caret</code> within the + * <code>Document</code> + */ int getDot(); + + /** + * Sets the current position of this <code>Caret</code> within the + * <code>Document</code>. This also sets the <code>mark</code> to the + * new location. + * + * @param dot the new position to be set + * + * @see #moveDot(int) + */ + void setDot(int dot); - Point getMagicCaretPosition(); - - int getMark(); - - void install(JTextComponent c); - - boolean isSelectionVisible(); - - boolean isVisible(); - + /** + * Moves the <code>dot</code> location without touching the + * <code>mark</code>. This is used when making a selection. + * + * @param dot the location where to move the dot + * + * @see #setDot(int) + */ void moveDot(int dot); - void paint(Graphics g); - - void removeChangeListener(ChangeListener l); - - void setBlinkRate(int rate); - - void setDot(int dot); + /** + * Returns the current position of the <code>mark</code>. The + * <code>mark</code> marks the location in the <code>Document</code> that + * is the end of a selection. If there is no selection, the <code>mark</code> + * is the same as the <code>dot</code>. + * + * @return the current position of the mark + */ + int getMark(); + /** + * Returns the current visual position of this <code>Caret</code>. + * + * @return the current visual position of this <code>Caret</code> + * + * @see #setMagicCaretPosition + */ + Point getMagicCaretPosition(); + + /** + * Sets the current visual position of this <code>Caret</code>. + * + * @param p the Point to use for the saved location. May be <code>null</code> + * to indicate that there is no visual location + */ void setMagicCaretPosition(Point p); - + + /** + * Returns <code>true</code> if the selection is currently visible, + * <code>false</code> otherwise. + * + * @return <code>true</code> if the selection is currently visible, + * <code>false</code> otherwise + */ + boolean isSelectionVisible(); + + /** + * Sets the visiblity state of the selection. + * + * @param v <code>true</code> if the selection should be visible, + * <code>false</code> otherwise + */ void setSelectionVisible(boolean v); - + + /** + * Returns <code>true</code> if this <code>Caret</code> is currently visible, + * and <code>false</code> if it is not. + * + * @return <code>true</code> if this <code>Caret</code> is currently visible, + * and <code>false</code> if it is not + */ + boolean isVisible(); + + /** + * Sets the visibility state of the caret. <code>true</code> shows the + * <code>Caret</code>, <code>false</code> hides it. + * + * @param v the visibility to set + */ void setVisible(boolean v); + + /** + * Paints this <code>Caret</code> to the specified <code>Graphics</code> + * context. + * + * @param g the graphics context to render to + */ + void paint(Graphics g); } diff --git a/libjava/classpath/javax/swing/text/ComponentView.java b/libjava/classpath/javax/swing/text/ComponentView.java index 744d537aec6..f6feda21513 100644 --- a/libjava/classpath/javax/swing/text/ComponentView.java +++ b/libjava/classpath/javax/swing/text/ComponentView.java @@ -100,4 +100,22 @@ public class ComponentView extends View { return 0; } + + /** + * Maps coordinates from the <code>View</code>'s space into a position + * in the document model. + * + * @param x the x coordinate in the view space + * @param y the y coordinate in the view space + * @param a the allocation of this <code>View</code> + * @param b the bias to use + * + * @return the position in the document that corresponds to the screen + * coordinates <code>x, y</code> + */ + public int viewToModel(float x, float y, Shape a, Position.Bias b) + { + // FIXME: Implement this properly. + return 0; + } } diff --git a/libjava/classpath/javax/swing/text/DateFormatter.java b/libjava/classpath/javax/swing/text/DateFormatter.java index 0e20b771b45..869f9a0900f 100644 --- a/libjava/classpath/javax/swing/text/DateFormatter.java +++ b/libjava/classpath/javax/swing/text/DateFormatter.java @@ -54,7 +54,7 @@ public class DateFormatter extends InternationalFormatter /** * Creates a new instance using the default {@link DateFormat} object - * returned by {@link DateFormat#getDateInstance}. + * returned by {@link DateFormat#getDateInstance()}. */ public DateFormatter() { diff --git a/libjava/classpath/javax/swing/text/DefaultCaret.java b/libjava/classpath/javax/swing/text/DefaultCaret.java index b57b3656384..33c3ae3bf28 100644 --- a/libjava/classpath/javax/swing/text/DefaultCaret.java +++ b/libjava/classpath/javax/swing/text/DefaultCaret.java @@ -1,5 +1,5 @@ /* DefaultCaret.java -- - Copyright (C) 2002, 2004 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -51,69 +51,203 @@ import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.EventListenerList; - +/** + * The default implementation of the {@link Caret} interface. + * + * @author orgininal author unknown + * @author Roman Kennke (roman@kennke.org) + */ public class DefaultCaret extends Rectangle implements Caret, FocusListener, MouseListener, MouseMotionListener { + /** + * The serial version UID for DefaultCaret. + */ private static final long serialVersionUID = 228155774675466193L; - + + /** + * The <code>ChangeEvent</code> that is fired by {@link #fireStateChanged()}. + */ protected ChangeEvent changeEvent = new ChangeEvent(this); + + /** + * Stores all registered event listeners. + */ protected EventListenerList listenerList = new EventListenerList(); - + + /** + * The text component in which this caret is installed. + */ private JTextComponent textComponent; - + + /** + * Indicates if the selection should be visible or not. + */ private boolean selectionVisible = true; + + /** + * The blink rate of this <code>Caret</code>. + */ private int blinkRate = 500; + + /** + * The current dot position. + */ private int dot = 0; + + /** + * The current mark position. + */ private int mark = 0; + + /** + * The current visual caret position. + */ private Point magicCaretPosition = null; + + /** + * Indicates if this <code>Caret</code> is currently visible or not. + */ private boolean visible = true; + + /** + * The current highlight entry. + */ private Object highlightEntry; + /** + * Moves the caret position when the mouse is dragged over the text + * component, modifying the selection accordingly. + * + * @param event the <code>MouseEvent</code> describing the drag operation + */ public void mouseDragged(MouseEvent event) { + // FIXME: Implement this properly. } + /** + * Indicates a mouse movement over the text component. Does nothing here. + * + * @param event the <code>MouseEvent</code> describing the mouse operation + */ public void mouseMoved(MouseEvent event) { - } - + // Nothing to do here. + } + + /** + * When the click is received from Button 1 then the following actions + * are performed here: + * + * <ul> + * <li>If we receive a double click, the caret position (dot) is set + * to the position associated to the mouse click and the word at + * this location is selected.</li> + * <li>If we receive a triple click, the caret position (dot) is set + * to the position associated to the mouse click and the line at + * this location is selected.</li> + * </ul> + * + * @param event the <code>MouseEvent</code> describing the click operation + */ public void mouseClicked(MouseEvent event) { + // FIXME: Implement this properly. } + /** + * Indicates that the mouse has entered the text component. Nothing is done + * here. + * + * @param event the <code>MouseEvent</code> describing the mouse operation + */ public void mouseEntered(MouseEvent event) { + // Nothing to do here. } + /** + * Indicates that the mouse has exited the text component. Nothing is done + * here. + * + * @param event the <code>MouseEvent</code> describing the mouse operation + */ public void mouseExited(MouseEvent event) { } + /** + * If the button 1 is pressed, the caret position is updated to the + * position of the mouse click and the text component requests the input + * focus if it is enabled. If the SHIFT key is held down, the caret will + * be moved, which might select the text between the old and new location. + * + * @param event the <code>MouseEvent</code> describing the press operation + */ public void mousePressed(MouseEvent event) { + // FIXME: Implement this properly. } + /** + * Indicates that a mouse button has been released on the text component. + * Nothing is done here. + * + * @param event the <code>MouseEvent</code> describing the mouse operation + */ public void mouseReleased(MouseEvent event) { + // Nothing to do here. } + /** + * Sets the caret to <code>visible</code> if the text component is editable. + * + * @param event the <code>FocusEvent</code> + */ public void focusGained(FocusEvent event) { } + /** + * Sets the caret to <code>invisible</code>. + * + * @param event the <code>FocusEvent</code> + */ public void focusLost(FocusEvent event) { } + /** + * Moves the caret to the position specified in the <code>MouseEvent</code>. + * This will cause a selection if the dot and mark are different. + * + * @param event the <code>MouseEvent</code> from which to fetch the position + */ protected void moveCaret(MouseEvent event) { + // FIXME: Implement this properly. } + /** + * Repositions the caret to the position specified in the + * <code>MouseEvent</code>. + * + * @param event the <code>MouseEvent</code> from which to fetch the position + */ protected void positionCaret(MouseEvent event) { + // FIXME: Implement this properly. } + /** + * Deinstalls this <code>Caret</code> from the specified + * <code>JTextComponent</code>. This removes any listeners that have been + * registered by this <code>Caret</code>. + * + * @param c the text component from which to install this caret + */ public void deinstall(JTextComponent c) { textComponent.removeFocusListener(this); @@ -122,6 +256,13 @@ public class DefaultCaret extends Rectangle textComponent = null; } + /** + * Installs this <code>Caret</code> on the specified + * <code>JTextComponent</code>. This registers a couple of listeners + * on the text component. + * + * @param c the text component on which to install this caret + */ public void install(JTextComponent c) { textComponent = c; @@ -131,16 +272,37 @@ public class DefaultCaret extends Rectangle repaint(); } + /** + * Sets the current visual position of this <code>Caret</code>. + * + * @param p the Point to use for the saved location. May be <code>null</code> + * to indicate that there is no visual location + */ public void setMagicCaretPosition(Point p) { magicCaretPosition = p; } + /** + * Returns the current visual position of this <code>Caret</code>. + * + * @return the current visual position of this <code>Caret</code> + * + * @see #setMagicCaretPosition + */ public Point getMagicCaretPosition() { return magicCaretPosition; } + /** + * Returns the current position of the <code>mark</code>. The + * <code>mark</code> marks the location in the <code>Document</code> that + * is the end of a selection. If there is no selection, the <code>mark</code> + * is the same as the <code>dot</code>. + * + * @return the current position of the mark + */ public int getMark() { return mark; @@ -181,6 +343,12 @@ public class DefaultCaret extends Rectangle } } + /** + * Sets the visiblity state of the selection. + * + * @param v <code>true</code> if the selection should be visible, + * <code>false</code> otherwise + */ public void setSelectionVisible(boolean v) { if (selectionVisible == v) @@ -191,17 +359,35 @@ public class DefaultCaret extends Rectangle repaint(); } + /** + * Returns <code>true</code> if the selection is currently visible, + * <code>false</code> otherwise. + * + * @return <code>true</code> if the selection is currently visible, + * <code>false</code> otherwise + */ public boolean isSelectionVisible() { return selectionVisible; } + /** + * Causes the <code>Caret</code> to repaint itself. + */ protected final void repaint() { + // FIXME: Is this good? This possibly causes alot of the component + // hierarchy to be repainted on every caret blink. if (textComponent != null) textComponent.repaint(); } + /** + * Paints this <code>Caret</code> using the specified <code>Graphics</code> + * context. + * + * @param g the graphics context to use + */ public void paint(Graphics g) { if (textComponent == null) @@ -234,26 +420,53 @@ public class DefaultCaret extends Rectangle } } + /** + * Returns all registered event listeners of the specified type. + * + * @param listenerType the type of listener to return + * + * @return all registered event listeners of the specified type + */ public EventListener[] getListeners(Class listenerType) { return listenerList.getListeners(listenerType); } + /** + * Registers a {@link ChangeListener} that is notified whenever that state + * of this <code>Caret</code> changes. + * + * @param listener the listener to register to this caret + */ public void addChangeListener(ChangeListener listener) { listenerList.add(ChangeListener.class, listener); } + /** + * Removes a {@link ChangeListener} from the list of registered listeners. + * + * @param listener the listener to remove + */ public void removeChangeListener(ChangeListener listener) { listenerList.remove(ChangeListener.class, listener); } + /** + * Returns all registered {@link ChangeListener}s of this <code>Caret</code>. + * + * @return all registered {@link ChangeListener}s of this <code>Caret</code> + */ public ChangeListener[] getChangeListeners() { return (ChangeListener[]) getListeners(ChangeListener.class); } + /** + * Notifies all registered {@link ChangeListener}s that the state + * of this <code>Caret</code> has changed. + */ protected void fireStateChanged() { ChangeListener[] listeners = getChangeListeners(); @@ -262,26 +475,61 @@ public class DefaultCaret extends Rectangle listeners[index].stateChanged(changeEvent); } + /** + * Returns the <code>JTextComponent</code> on which this <code>Caret</code> + * is installed. + * + * @return the <code>JTextComponent</code> on which this <code>Caret</code> + * is installed + */ protected final JTextComponent getComponent() { return textComponent; } - + + /** + * Returns the blink rate of this <code>Caret</code> in milliseconds. + * A value of <code>0</code> means that the caret does not blink. + * + * @return the blink rate of this <code>Caret</code> or <code>0</code> if + * this caret does not blink + */ public int getBlinkRate() { return blinkRate; } + /** + * Sets the blink rate of this <code>Caret</code> in milliseconds. + * A value of <code>0</code> means that the caret does not blink. + * + * @param rate the new blink rate to set + */ public void setBlinkRate(int rate) { blinkRate = rate; } + /** + * Returns the current position of this <code>Caret</code> within the + * <code>Document</code>. + * + * @return the current position of this <code>Caret</code> within the + * <code>Document</code> + */ public int getDot() { return dot; } + /** + * Moves the <code>dot</code> location without touching the + * <code>mark</code>. This is used when making a selection. + * + * @param dot the location where to move the dot + * + * @see #setDot(int) + */ public void moveDot(int dot) { this.dot = dot; @@ -289,6 +537,15 @@ public class DefaultCaret extends Rectangle repaint(); } + /** + * Sets the current position of this <code>Caret</code> within the + * <code>Document</code>. This also sets the <code>mark</code> to the + * new location. + * + * @param dot the new position to be set + * + * @see #moveDot(int) + */ public void setDot(int dot) { this.dot = dot; @@ -297,17 +554,37 @@ public class DefaultCaret extends Rectangle repaint(); } + /** + * Returns <code>true</code> if this <code>Caret</code> is currently visible, + * and <code>false</code> if it is not. + * + * @return <code>true</code> if this <code>Caret</code> is currently visible, + * and <code>false</code> if it is not + */ public boolean isVisible() { return visible; } + /** + * Sets the visibility state of the caret. <code>true</code> shows the + * <code>Caret</code>, <code>false</code> hides it. + * + * @param v the visibility to set + */ public void setVisible(boolean v) { visible = v; repaint(); } + /** + * Returns the {@link Highlighter.HighlightPainter} that should be used + * to paint the selection. + * + * @return the {@link Highlighter.HighlightPainter} that should be used + * to paint the selection + */ protected Highlighter.HighlightPainter getSelectionPainter() { return DefaultHighlighter.DefaultPainter; diff --git a/libjava/classpath/javax/swing/text/DefaultEditorKit.java b/libjava/classpath/javax/swing/text/DefaultEditorKit.java index aa2fbe8509a..a14f3ff4fe0 100644 --- a/libjava/classpath/javax/swing/text/DefaultEditorKit.java +++ b/libjava/classpath/javax/swing/text/DefaultEditorKit.java @@ -51,44 +51,135 @@ import java.io.Writer; import javax.swing.Action; +/** + * The default implementation of {@link EditorKit}. This <code>EditorKit</code> + * a plain text <code>Document</code> and several commands that together + * make up a basic editor, like cut / copy + paste. + * + * @author original author unknown + * @author Roman Kennke (roman@kennke.org) + */ public class DefaultEditorKit extends EditorKit { + /** + * Creates a beep on the PC speaker. + * + * @see Toolkit#beep() + */ public static class BeepAction extends TextAction { + /** + * Creates a new <code>BeepAction</code>. + */ public BeepAction() { super(beepAction); } + /** + * Performs the <code>Action</code>. + * + * @param event the action event describing the user action + */ public void actionPerformed(ActionEvent event) { Toolkit.getDefaultToolkit().beep(); } } + /** + * Copies the selected content into the system clipboard. + * + * @see Toolkit#getSystemClipboard() + * @see CutAction + * @see PasteAction + */ public static class CopyAction extends TextAction { + + /** + * Create a new <code>CopyAction</code>. + */ public CopyAction() { super(copyAction); } + + /** + * Performs the <code>Action</code>. + * + * @param event the action event describing the user action + */ public void actionPerformed(ActionEvent event) { + // FIXME: Implement me. Tookit.getSystemClipboard should be used + // for that. } } + + /** + * Copies the selected content into the system clipboard and deletes the + * selection. + * + * @see Toolkit#getSystemClipboard() + * @see CopyAction + * @see PasteAction + */ public static class CutAction extends TextAction { + + /** + * Create a new <code>CutAction</code>. + */ public CutAction() { super(cutAction); } + /** + * Performs the <code>Action</code>. + * + * @param event the action event describing the user action + */ public void actionPerformed(ActionEvent event) { + // FIXME: Implement me. Tookit.getSystemClipboard should be used + // for that. + } + } + + /** + * Copies content from the system clipboard into the editor. + * + * @see Toolkit#getSystemClipboard() + * @see CopyAction + * @see CutAction + */ + public static class PasteAction + extends TextAction + { + + /** + * Create a new <code>PasteAction</code>. + */ + public PasteAction() + { + super(pasteAction); + } + + /** + * Performs the <code>Action</code>. + * + * @param event the action event describing the user action + */ + public void actionPerformed(ActionEvent event) + { + // FIXME: Implement me. Tookit.getSystemClipboard should be used + // for that. } } @@ -99,17 +190,26 @@ public class DefaultEditorKit extends EditorKit * the control characters and characters with the ALT-modifier. * * If an event does not get filtered, it is inserted into the document - * of the text component. If there is some text selected in the text component, - * this text will be replaced. + * of the text component. If there is some text selected in the text + * component, this text will be replaced. */ public static class DefaultKeyTypedAction extends TextAction { + + /** + * Creates a new <code>DefaultKeyTypedAction</code>. + */ public DefaultKeyTypedAction() { super(defaultKeyTypedAction); } + /** + * Performs the <code>Action</code>. + * + * @param event the action event describing the user action + */ public void actionPerformed(ActionEvent event) { // first we filter the following events: @@ -124,9 +224,11 @@ public class DefaultEditorKit extends EditorKit { try { - t.getDocument().insertString(t.getCaret().getDot(), event.getActionCommand(), null); + t.getDocument().insertString(t.getCaret().getDot(), + event.getActionCommand(), null); t.getCaret().setDot(Math.min(t.getCaret().getDot() + 1, - t.getDocument().getEndPosition().getOffset())); + t.getDocument().getEndPosition() + .getOffset())); } catch (BadLocationException be) { @@ -144,11 +246,20 @@ public class DefaultEditorKit extends EditorKit public static class InsertBreakAction extends TextAction { + + /** + * Creates a new <code>InsertBreakAction</code>. + */ public InsertBreakAction() { super(insertBreakAction); } + /** + * Performs the <code>Action</code>. + * + * @param event the action event describing the user action + */ public void actionPerformed(ActionEvent event) { JTextComponent t = getTextComponent(event); @@ -156,101 +267,446 @@ public class DefaultEditorKit extends EditorKit } } + /** + * Places content into the associated editor. If there currently is a + * selection, this selection is replaced. + */ + // FIXME: Figure out what this Action is supposed to do. Obviously text + // that is entered by the user is inserted through DefaultKeyTypedAction. public static class InsertContentAction extends TextAction { + + /** + * Creates a new <code>InsertContentAction</code>. + */ public InsertContentAction() { super(insertContentAction); } + + /** + * Performs the <code>Action</code>. + * + * @param event the action event describing the user action + */ public void actionPerformed(ActionEvent event) { } } + /** + * Inserts a TAB character into the text editor. + */ public static class InsertTabAction extends TextAction { + + /** + * Creates a new <code>TabAction</code>. + */ public InsertTabAction() { super(insertTabAction); } + /** + * Performs the <code>Action</code>. + * + * @param event the action event describing the user action + */ public void actionPerformed(ActionEvent event) { + // FIXME: Implement this. } } - public static class PasteAction - extends TextAction - { - public PasteAction() - { - super(pasteAction); - } - - public void actionPerformed(ActionEvent event) - { - } - } - + /** + * The serial version of DefaultEditorKit. + */ private static final long serialVersionUID = 9017245433028523428L; - + + /** + * The name of the <code>Action</code> that moves the caret one character + * backwards. + * + * @see #getActions() + */ public static final String backwardAction = "caret-backward"; + + /** + * The name of the <code>Action</code> that creates a beep in the speaker. + * + * @see #getActions() + */ public static final String beepAction = "beep"; + + /** + * The name of the <code>Action</code> that moves the caret to the beginning + * of the <code>Document</code>. + * + * @see #getActions() + */ public static final String beginAction = "caret-begin"; + + /** + * The name of the <code>Action</code> that moves the caret to the beginning + * of the current line. + * + * @see #getActions() + */ public static final String beginLineAction = "caret-begin-line"; + + /** + * The name of the <code>Action</code> that moves the caret to the beginning + * of the current paragraph. + * + * @see #getActions() + */ public static final String beginParagraphAction = "caret-begin-paragraph"; + + /** + * The name of the <code>Action</code> that moves the caret to the beginning + * of the current word. + * + * @see #getActions() + */ public static final String beginWordAction = "caret-begin-word"; + + /** + * The name of the <code>Action</code> that copies the selected content + * into the system clipboard. + * + * @see #getActions() + */ public static final String copyAction = "copy-to-clipboard"; + + /** + * The name of the <code>Action</code> that copies the selected content + * into the system clipboard and removes the selection. + * + * @see #getActions() + */ public static final String cutAction = "cut-to-clipboard"; + + /** + * The name of the <code>Action</code> that is performed by default if + * a key is typed and there is no keymap entry. + * + * @see #getActions() + */ public static final String defaultKeyTypedAction = "default-typed"; + + /** + * The name of the <code>Action</code> that deletes the character that + * follows the current caret position. + * + * @see #getActions() + */ public static final String deleteNextCharAction = "delete-next"; + + /** + * The name of the <code>Action</code> that deletes the character that + * precedes the current caret position. + * + * @see #getActions() + */ public static final String deletePrevCharAction = "delete-previous"; + + /** + * The name of the <code>Action</code> that moves the caret one line down. + * + * @see #getActions() + */ public static final String downAction = "caret-down"; + + /** + * The name of the <code>Action</code> that moves the caret to the end + * of the <code>Document</code>. + * + * @see #getActions() + */ public static final String endAction = "caret-end"; + + /** + * The name of the <code>Action</code> that moves the caret to the end + * of the current line. + * + * @see #getActions() + */ public static final String endLineAction = "caret-end-line"; + + /** + * When a document is read and an CRLF is encountered, then we add a property + * with this name and a value of "\r\n". + */ public static final String EndOfLineStringProperty = "__EndOfLine__"; + + /** + * The name of the <code>Action</code> that moves the caret to the end + * of the current paragraph. + * + * @see #getActions() + */ public static final String endParagraphAction = "caret-end-paragraph"; + + /** + * The name of the <code>Action</code> that moves the caret to the end + * of the current word. + * + * @see #getActions() + */ public static final String endWordAction = "caret-end-word"; + + /** + * The name of the <code>Action</code> that moves the caret one character + * forward. + * + * @see #getActions() + */ public static final String forwardAction = "caret-forward"; + + /** + * The name of the <code>Action</code> that inserts a line break. + * + * @see #getActions() + */ public static final String insertBreakAction = "insert-break"; + + /** + * The name of the <code>Action</code> that inserts some content. + * + * @see #getActions() + */ public static final String insertContentAction = "insert-content"; + + /** + * The name of the <code>Action</code> that inserts a TAB. + * + * @see #getActions() + */ public static final String insertTabAction = "insert-tab"; + + /** + * The name of the <code>Action</code> that moves the caret to the beginning + * of the next word. + * + * @see #getActions() + */ public static final String nextWordAction = "caret-next-word"; + + /** + * The name of the <code>Action</code> that moves the caret one page down. + * + * @see #getActions() + */ public static final String pageDownAction = "page-down"; + + /** + * The name of the <code>Action</code> that moves the caret one page up. + * + * @see #getActions() + */ public static final String pageUpAction = "page-up"; + + /** + * The name of the <code>Action</code> that copies content from the system + * clipboard into the document. + * + * @see #getActions() + */ public static final String pasteAction = "paste-from-clipboard"; + + /** + * The name of the <code>Action</code> that moves the caret to the beginning + * of the previous word. + * + * @see #getActions() + */ public static final String previousWordAction = "caret-previous-word"; + + /** + * The name of the <code>Action</code> that sets the editor in read only + * mode. + * + * @see #getActions() + */ public static final String readOnlyAction = "set-read-only"; + + /** + * The name of the <code>Action</code> that selects the whole document. + * + * @see #getActions() + */ public static final String selectAllAction = "select-all"; + + /** + * The name of the <code>Action</code> that moves the caret one character + * backwards, possibly extending the current selection. + * + * @see #getActions() + */ public static final String selectionBackwardAction = "selection-backward"; + + /** + * The name of the <code>Action</code> that moves the caret to the beginning + * of the document, possibly extending the current selection. + * + * @see #getActions() + */ public static final String selectionBeginAction = "selection-begin"; + + /** + * The name of the <code>Action</code> that moves the caret to the beginning + * of the current line, possibly extending the current selection. + * + * @see #getActions() + */ public static final String selectionBeginLineAction = "selection-begin-line"; + + /** + * The name of the <code>Action</code> that moves the caret to the beginning + * of the current paragraph, possibly extending the current selection. + * + * @see #getActions() + */ public static final String selectionBeginParagraphAction = "selection-begin-paragraph"; + + /** + * The name of the <code>Action</code> that moves the caret to the beginning + * of the current word, possibly extending the current selection. + * + * @see #getActions() + */ public static final String selectionBeginWordAction = "selection-begin-word"; + + /** + * The name of the <code>Action</code> that moves the caret one line down, + * possibly extending the current selection. + * + * @see #getActions() + */ public static final String selectionDownAction = "selection-down"; + + /** + * The name of the <code>Action</code> that moves the caret to the end + * of the document, possibly extending the current selection. + * + * @see #getActions() + */ public static final String selectionEndAction = "selection-end"; + + /** + * The name of the <code>Action</code> that moves the caret to the end + * of the current line, possibly extending the current selection. + * + * @see #getActions() + */ public static final String selectionEndLineAction = "selection-end-line"; + + /** + * The name of the <code>Action</code> that moves the caret to the end + * of the current paragraph, possibly extending the current selection. + * + * @see #getActions() + */ public static final String selectionEndParagraphAction = "selection-end-paragraph"; + + /** + * The name of the <code>Action</code> that moves the caret to the end + * of the current word, possibly extending the current selection. + * + * @see #getActions() + */ public static final String selectionEndWordAction = "selection-end-word"; + + /** + * The name of the <code>Action</code> that moves the caret one character + * forwards, possibly extending the current selection. + * + * @see #getActions() + */ public static final String selectionForwardAction = "selection-forward"; + + /** + * The name of the <code>Action</code> that moves the caret to the beginning + * of the next word, possibly extending the current selection. + * + * @see #getActions() + */ public static final String selectionNextWordAction = "selection-next-word"; + + /** + * The name of the <code>Action</code> that moves the caret to the beginning + * of the previous word, possibly extending the current selection. + * + * @see #getActions() + */ public static final String selectionPreviousWordAction = "selection-previous-word"; + + /** + * The name of the <code>Action</code> that moves the caret one line up, + * possibly extending the current selection. + * + * @see #getActions() + */ public static final String selectionUpAction = "selection-up"; + + /** + * The name of the <code>Action</code> that selects the line around the + * caret. + * + * @see #getActions() + */ public static final String selectLineAction = "select-line"; + + /** + * The name of the <code>Action</code> that selects the paragraph around the + * caret. + * + * @see #getActions() + */ public static final String selectParagraphAction = "select-paragraph"; + + /** + * The name of the <code>Action</code> that selects the word around the + * caret. + * + * @see #getActions() + */ public static final String selectWordAction = "select-word"; + + /** + * The name of the <code>Action</code> that moves the caret one line up. + * + * @see #getActions() + */ public static final String upAction = "caret-up"; + + /** + * The name of the <code>Action</code> that sets the editor in read-write + * mode. + * + * @see #getActions() + */ public static final String writableAction = "set-writable"; + /** + * Creates a new <code>DefaultEditorKit</code>. + */ public DefaultEditorKit() { } + /** + * The <code>Action</code>s that are supported by the + * <code>DefaultEditorKit</code>. + */ + // TODO: All these inner classes look ugly. Maybe work out a better way + // to handle this. private static Action[] defaultActions = new Action[] { new BeepAction(), @@ -356,37 +812,98 @@ public class DefaultEditorKit extends EditorKit }, }; + /** + * Creates the <code>Caret</code> for this <code>EditorKit</code>. This + * returns a {@link DefaultCaret} in this case. + * + * @return the <code>Caret</code> for this <code>EditorKit</code> + */ public Caret createCaret() { return new DefaultCaret(); } + /** + * Creates the default {@link Document} that this <code>EditorKit</code> + * supports. This is a {@link PlainDocument} in this case. + * + * @return the default {@link Document} that this <code>EditorKit</code> + * supports + */ public Document createDefaultDocument() { return new PlainDocument(); } - + + /** + * Returns the <code>Action</code>s supported by this <code>EditorKit</code>. + * + * @return the <code>Action</code>s supported by this <code>EditorKit</code> + */ public Action[] getActions() { return defaultActions; } + /** + * Returns the content type that this <code>EditorKit</code> supports. + * The <code>DefaultEditorKit</code> supports the content type + * <code>text/plain</code>. + * + * @return the content type that this <code>EditorKit</code> supports + */ public String getContentType() { return "text/plain"; } - + + /** + * Returns a {@link ViewFactory} that is able to create {@link View}s for + * the <code>Element</code>s that are used in this <code>EditorKit</code>'s + * model. This returns null which lets the UI of the text component supply + * <code>View</code>s. + * + * @return a {@link ViewFactory} that is able to create {@link View}s for + * the <code>Element</code>s that are used in this + * <code>EditorKit</code>'s model + */ public ViewFactory getViewFactory() { return null; } + /** + * Reads a document of the supported content type from an {@link InputStream} + * into the actual {@link Document} object. + * + * @param in the stream from which to read the document + * @param document the document model into which the content is read + * @param offset the offset inside to document where the content is inserted + * + * @throws BadLocationException if <code>offset</code> is an invalid location + * inside <code>document</code> + * @throws IOException if something goes wrong while reading from + * <code>in</code> + */ public void read(InputStream in, Document document, int offset) throws BadLocationException, IOException { read(new InputStreamReader(in), document, offset); } + /** + * Reads a document of the supported content type from a {@link Reader} + * into the actual {@link Document} object. + * + * @param in the reader from which to read the document + * @param document the document model into which the content is read + * @param offset the offset inside to document where the content is inserted + * + * @throws BadLocationException if <code>offset</code> is an invalid location + * inside <code>document</code> + * @throws IOException if something goes wrong while reading from + * <code>in</code> + */ public void read(Reader in, Document document, int offset) throws BadLocationException, IOException { @@ -405,14 +922,47 @@ public class DefaultEditorKit extends EditorKit SimpleAttributeSet.EMPTY); } + /** + * Writes the <code>Document</code> (or a fragment of the + * <code>Document</code>) to an {@link OutputStream} in the + * supported content type format. + * + * @param out the stream to write to + * @param document the document that should be written out + * @param offset the beginning offset from where to write + * @param len the length of the fragment to write + * + * @throws BadLocationException if <code>offset</code> or + * <code>offset + len</code>is an invalid location inside + * <code>document</code> + * @throws IOException if something goes wrong while writing to + * <code>out</code> + */ public void write(OutputStream out, Document document, int offset, int len) throws BadLocationException, IOException { write(new OutputStreamWriter(out), document, offset, len); } + /** + * Writes the <code>Document</code> (or a fragment of the + * <code>Document</code>) to a {@link Writer} in the + * supported content type format. + * + * @param out the writer to write to + * @param document the document that should be written out + * @param offset the beginning offset from where to write + * @param len the length of the fragment to write + * + * @throws BadLocationException if <code>offset</code> or + * <code>offset + len</code>is an invalid location inside + * <code>document</code> + * @throws IOException if something goes wrong while writing to + * <code>out</code> + */ public void write(Writer out, Document document, int offset, int len) throws BadLocationException, IOException { + // TODO: Implement this properly. } } diff --git a/libjava/classpath/javax/swing/text/DefaultStyledDocument.java b/libjava/classpath/javax/swing/text/DefaultStyledDocument.java index 6fe206a8453..3545e52c453 100644 --- a/libjava/classpath/javax/swing/text/DefaultStyledDocument.java +++ b/libjava/classpath/javax/swing/text/DefaultStyledDocument.java @@ -42,42 +42,174 @@ import java.awt.Color; import java.awt.Font; import java.io.Serializable; +import javax.swing.event.DocumentEvent; + /** + * The default implementation of {@link StyledDocument}. + * + * The document is modeled as an {@link Element} tree, which has + * a {@link SectionElement} as single root, which has one or more + * {@link AbstractDocument.BranchElement}s as paragraph nodes + * and each paragraph node having one or more + * {@link AbstractDocument.LeafElement}s as content nodes. + * * @author Michael Koch (konqueror@gmx.de) + * @author Roman Kennke (roman@kennke.org) */ public class DefaultStyledDocument extends AbstractDocument implements StyledDocument { + /** + * Performs all <em>structural</code> changes to the <code>Element</code> + * hierarchy. + */ public class ElementBuffer implements Serializable { + /** The root element of the hierarchy. */ private Element root; - + + /** Holds the offset for structural changes. */ + private int offset; + + /** Holds the length of structural changes. */ + private int length; + + /** + * Creates a new <code>ElementBuffer</code> for the specified + * <code>root</code> element. + * + * @param root the root element for this <code>ElementBuffer</code> + */ public ElementBuffer(Element root) { this.root = root; } + /** + * Returns the root element of this <code>ElementBuffer</code>. + * + * @return the root element of this <code>ElementBuffer</code> + */ public Element getRootElement() { return root; } + + /** + * Modifies the element structure so that the specified interval starts + * and ends at an element boundary. Content and paragraph elements + * are split and created as necessary. + * + * This also updates the <code>DefaultDocumentEvent</code> to reflect the + * structural changes. + * + * The bulk work is delegated to {@link #changeUpdate()}. + * + * @param offset the start index of the interval to be changed + * @param length the length of the interval to be changed + * @param ev the <code>DefaultDocumentEvent</code> describing the change + */ + public void change(int offset, int length, DefaultDocumentEvent ev) + { + this.offset = offset; + this.length = length; + changeUpdate(); + } + + /** + * Performs the actual work for {@link #change}. + * The elements at the interval boundaries are split up (if necessary) + * so that the interval boundaries are located at element boundaries. + */ + protected void changeUpdate() + { + // Split up the element at the start offset if necessary. + Element el = getCharacterElement(offset); + split(el, offset); + + int endOffset = offset + length; + el = getCharacterElement(endOffset); + split(el, endOffset); + } + + /** + * Splits an element if <code>offset</code> is not alread at its boundary. + * + * @param el the Element to possibly split + * @param offset the offset at which to possibly split + */ + void split(Element el, int offset) + { + if (el instanceof AbstractElement) + { + AbstractElement ael = (AbstractElement) el; + int startOffset = ael.getStartOffset(); + int endOffset = ael.getEndOffset(); + int len = endOffset - startOffset; + if (startOffset != offset && endOffset != offset) + { + Element paragraph = ael.getParentElement(); + if (paragraph instanceof BranchElement) + { + BranchElement par = (BranchElement) paragraph; + Element child1 = createLeafElement(par, ael, startOffset, + offset); + Element child2 = createLeafElement(par, ael, offset, + endOffset); + int index = par.getElementIndex(startOffset); + par.replace(index, 1, new Element[]{ child1, child2 }); + } + else + throw new AssertionError("paragraph elements are expected to " + + "be instances of " + + "javax.swing.text.AbstractDocument.BranchElement"); + } + } + else + throw new AssertionError("content elements are expected to be " + + "instances of " + + "javax.swing.text.AbstractDocument.AbstractElement"); + } } - + + /** + * The default size to use for new content buffers. + */ public static final int BUFFER_SIZE_DEFAULT = 4096; + /** + * The <code>EditorBuffer</code> that is used to manage to + * <code>Element</code> hierarchy. + */ protected DefaultStyledDocument.ElementBuffer buffer; - + + /** + * Creates a new <code>DefaultStyledDocument</code>. + */ public DefaultStyledDocument() { this(new GapContent(BUFFER_SIZE_DEFAULT), new StyleContext()); } + /** + * Creates a new <code>DefaultStyledDocument</code> that uses the + * specified {@link StyleContext}. + * + * @param context the <code>StyleContext</code> to use + */ public DefaultStyledDocument(StyleContext context) { this(new GapContent(BUFFER_SIZE_DEFAULT), context); } + /** + * Creates a new <code>DefaultStyledDocument</code> that uses the + * specified {@link StyleContext} and {@link Content} buffer. + * + * @param content the <code>Content</code> buffer to use + * @param context the <code>StyleContext</code> to use + */ public DefaultStyledDocument(AbstractDocument.Content content, StyleContext context) { @@ -86,15 +218,38 @@ public class DefaultStyledDocument extends AbstractDocument setLogicalStyle(0, context.getStyle(StyleContext.DEFAULT_STYLE)); } + /** + * Adds a style into the style hierarchy. Unspecified style attributes + * can be resolved in the <code>parent</code> style, if one is specified. + * + * While it is legal to add nameless styles (<code>nm == null</code), + * you must be aware that the client application is then responsible + * for managing the style hierarchy, since unnamed styles cannot be + * looked up by their name. + * + * @param nm the name of the style or <code>null</code> if the style should + * be unnamed + * @param parent the parent in which unspecified style attributes are + * resolved, or <code>null</code> if that is not necessary + * + * @return the newly created <code>Style</code> + */ public Style addStyle(String nm, Style parent) { StyleContext context = (StyleContext) getAttributeContext(); return context.addStyle(nm, parent); } - + + /** + * Create the default root element for this kind of <code>Document</code>. + * + * @return the default root element for this kind of <code>Document</code> + */ protected AbstractDocument.AbstractElement createDefaultRoot() { Element[] tmp; + // FIXME: Create a SecionElement here instead of a BranchElement. + // Use createBranchElement() and createLeafElement instead. BranchElement section = new BranchElement(null, null); BranchElement paragraph = new BranchElement(section, null); @@ -109,7 +264,17 @@ public class DefaultStyledDocument extends AbstractDocument return section; } - + + /** + * Returns the <code>Element</code> that corresponds to the character + * at the specified position. + * + * @param position the position of which we query the corresponding + * <code>Element</code> + * + * @return the <code>Element</code> that corresponds to the character + * at the specified position + */ public Element getCharacterElement(int position) { Element element = getDefaultRootElement(); @@ -122,63 +287,172 @@ public class DefaultStyledDocument extends AbstractDocument return element; } - + + /** + * Extracts a background color from a set of attributes. + * + * @param attributes the attributes from which to get a background color + * + * @return the background color that correspond to the attributes + */ public Color getBackground(AttributeSet attributes) { StyleContext context = (StyleContext) getAttributeContext(); return context.getBackground(attributes); } - + + /** + * Returns the default root element. + * + * @return the default root element + */ public Element getDefaultRootElement() { return buffer.getRootElement(); } - + + /** + * Extracts a font from a set of attributes. + * + * @param attributes the attributes from which to get a font + * + * @return the font that correspond to the attributes + */ public Font getFont(AttributeSet attributes) { StyleContext context = (StyleContext) getAttributeContext(); return context.getFont(attributes); } + /** + * Extracts a foreground color from a set of attributes. + * + * @param attributes the attributes from which to get a foreground color + * + * @return the foreground color that correspond to the attributes + */ public Color getForeground(AttributeSet attributes) { StyleContext context = (StyleContext) getAttributeContext(); return context.getForeground(attributes); } - + + /** + * Returns the logical <code>Style</code> for the specified position. + * + * @param position the position from which to query to logical style + * + * @return the logical <code>Style</code> for the specified position + */ public Style getLogicalStyle(int position) { Element paragraph = getParagraphElement(position); AttributeSet attributes = paragraph.getAttributes(); return (Style) attributes.getResolveParent(); } - + + /** + * Returns the paragraph element for the specified position. + * + * @param position the position for which to query the paragraph element + * + * @return the paragraph element for the specified position + */ public Element getParagraphElement(int position) { Element element = getCharacterElement(position); return element.getParentElement(); } + /** + * Looks up and returns a named <code>Style</code>. + * + * @param nm the name of the <code>Style</code> + * + * @return the found <code>Style</code> of <code>null</code> if no such + * <code>Style</code> exists + */ public Style getStyle(String nm) { StyleContext context = (StyleContext) getAttributeContext(); return context.getStyle(nm); } + /** + * Removes a named <code>Style</code> from the style hierarchy. + * + * @param nm the name of the <code>Style</code> to be removed + */ public void removeStyle(String nm) { StyleContext context = (StyleContext) getAttributeContext(); context.removeStyle(nm); } + /** + * Sets text attributes for the fragment specified by <code>offset</code> + * and <code>length</code>. + * + * @param offset the start offset of the fragment + * @param length the length of the fragment + * @param attributes the text attributes to set + * @param replace if <code>true</code>, the attributes of the current + * selection are overridden, otherwise they are merged + */ public void setCharacterAttributes(int offset, int length, AttributeSet attributes, boolean replace) { - // FIXME: Implement me. - throw new Error("not implemented"); + DefaultDocumentEvent ev = + new DefaultDocumentEvent(offset, length, + DocumentEvent.EventType.CHANGE); + + // Modify the element structure so that the interval begins at an element + // start and ends at an element end. + buffer.change(offset, length, ev); + + Element root = getDefaultRootElement(); + // Visit all paragraph elements within the specified interval + int paragraphCount = root.getElementCount(); + for (int pindex = 0; pindex < paragraphCount; pindex++) + { + Element paragraph = root.getElement(pindex); + // Skip paragraphs that lie outside the interval. + if ((paragraph.getStartOffset() > offset + length) + || (paragraph.getEndOffset() < offset)) + continue; + + // Visit content elements within this paragraph + int contentCount = paragraph.getElementCount(); + for (int cindex = 0; cindex < contentCount; cindex++) + { + Element content = paragraph.getElement(cindex); + // Skip content that lies outside the interval. + if ((content.getStartOffset() > offset + length) + || (content.getEndOffset() < offset)) + continue; + + if (content instanceof AbstractElement) + { + AbstractElement el = (AbstractElement) content; + if (replace) + el.removeAttributes(el); + el.addAttributes(attributes); + } + else + throw new AssertionError("content elements are expected to be" + + "instances of " + + "javax.swing.text.AbstractDocument.AbstractElement"); + } + } } + /** + * Sets the logical style for the paragraph at the specified position. + * + * @param position the position at which the logical style is added + * @param style the style to set for the current paragraph + */ public void setLogicalStyle(int position, Style style) { Element el = getParagraphElement(position); @@ -192,6 +466,15 @@ public class DefaultStyledDocument extends AbstractDocument + "instances of javax.swing.text.AbstractDocument.AbstractElement"); } + /** + * Sets text attributes for the paragraph at the specified fragment. + * + * @param offset the beginning of the fragment + * @param length the length of the fragment + * @param attributes the text attributes to set + * @param replace if <code>true</code>, the attributes of the current + * selection are overridden, otherwise they are merged + */ public void setParagraphAttributes(int offset, int length, AttributeSet attributes, boolean replace) diff --git a/libjava/classpath/javax/swing/text/FieldView.java b/libjava/classpath/javax/swing/text/FieldView.java index 4d5c51cebb4..e2e04d7c495 100644 --- a/libjava/classpath/javax/swing/text/FieldView.java +++ b/libjava/classpath/javax/swing/text/FieldView.java @@ -173,4 +173,9 @@ public class FieldView extends PlainView super.removeUpdate(ev, newAlloc, vf); } + public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) + { + return super.viewToModel(fx, fy, a, bias); + } + } diff --git a/libjava/classpath/javax/swing/text/GapContent.java b/libjava/classpath/javax/swing/text/GapContent.java index 1bbef8f93d6..1dd46c4b0f4 100644 --- a/libjava/classpath/javax/swing/text/GapContent.java +++ b/libjava/classpath/javax/swing/text/GapContent.java @@ -39,29 +39,93 @@ exception statement from your version. */ package javax.swing.text; import java.io.Serializable; +import java.util.Collections; +import java.util.LinkedList; +import java.util.ListIterator; import javax.swing.undo.UndoableEdit; /** - * This implementation of {@link AbstractDocument.Content} uses a gapped - * buffer. This takes advantage of the fact that text area content is - * mostly inserted sequentially. The buffer is a char array that maintains - * a gap at the current insertion point. If characters a inserted at - * gap boundaries, the cost is minimal (simple array access). The array only - * has to be shifted around when the insertion point moves (then the gap also - * moves and one array copy is necessary) or when the gap is filled up and - * the buffer has to be enlarged. - * + * This implementation of {@link AbstractDocument.Content} uses a gapped buffer. + * This takes advantage of the fact that text area content is mostly inserted + * sequentially. The buffer is a char array that maintains a gap at the current + * insertion point. If characters a inserted at gap boundaries, the cost is + * minimal (simple array access). The array only has to be shifted around when + * the insertion point moves (then the gap also moves and one array copy is + * necessary) or when the gap is filled up and the buffer has to be enlarged. + * * TODO: Implement UndoableEdit support stuff */ public class GapContent - implements AbstractDocument.Content, Serializable + implements AbstractDocument.Content, Serializable { + + /** + * A {@link Position} implementation for <code>GapContent</code>. + */ + class GapContentPosition + implements Position, Comparable + { + + /** The index within the buffer array. */ + int mark; + + /** + * Creates a new GapContentPosition object. + * + * @param mark the mark of this Position + */ + GapContentPosition(int mark) + { + this.mark = mark; + } + + /** + * Comparable interface implementation. This is used to store all + * positions in an ordered fashion. + * + * @param o the object to be compared to this + * + * @return a negative integer if this is less than <code>o</code>, zero + * if both are equal or a positive integer if this is greater than + * <code>o</code> + * + * @throws ClassCastException if <code>o</code> is not a + * GapContentPosition or Integer object + */ + public int compareTo(Object o) + { + if (o instanceof Integer) + { + int otherMark = ((Integer) o).intValue(); + return mark - otherMark; + } + else + { + GapContentPosition other = (GapContentPosition) o; + return mark - other.mark; + } + } + + /** + * Returns the current offset of this Position within the content. + * + * @return the current offset of this Position within the content. + */ + public int getOffset() + { + if (mark <= gapStart) + return mark; + else + return mark - (gapEnd - gapStart); + } + } + private static final long serialVersionUID = 8374645204155842629L; /** - * This is the default buffer size and the amount of bytes that - * a buffer is extended if it is full. + * This is the default buffer size and the amount of bytes that a buffer is + * extended if it is full. */ static final int DEFAULT_BUFSIZE = 64; @@ -81,6 +145,12 @@ public class GapContent int gapEnd; /** + * The positions generated by this GapContent. They are kept in an ordered + * fashion, so they can be looked up easily. + */ + LinkedList positions; + + /** * Creates a new GapContent object. */ public GapContent() @@ -90,7 +160,7 @@ public class GapContent /** * Creates a new GapContent object with a specified initial size. - * + * * @param size the initial size of the buffer */ public GapContent(int size) @@ -99,14 +169,15 @@ public class GapContent gapStart = 0; gapEnd = size - 1; buffer[size - 1] = '\n'; + positions = new LinkedList(); } /** * Allocates an array of the specified length that can then be used as * buffer. - * + * * @param size the size of the array to be allocated - * + * * @return the allocated array */ protected Object allocateArray(int size) @@ -116,7 +187,7 @@ public class GapContent /** * Returns the length of the allocated buffer array. - * + * * @return the length of the allocated buffer array */ protected int getArrayLength() @@ -126,7 +197,7 @@ public class GapContent /** * Returns the length of the content. - * + * * @return the length of the content */ public int length() @@ -136,18 +207,18 @@ public class GapContent /** * Inserts a string at the specified position. - * + * * @param where the position where the string is inserted * @param str the string that is to be inserted - * + * * @return an UndoableEdit object (currently not supported, so * <code>null</code> is returned) - * - * @throws BadLocationException if <code>where</code> is not a valid location - * in the buffer + * + * @throws BadLocationException if <code>where</code> is not a valid + * location in the buffer */ public UndoableEdit insertString(int where, String str) - throws BadLocationException + throws BadLocationException { // check arguments int length = length(); @@ -155,190 +226,230 @@ public class GapContent if (where >= length) throw new BadLocationException("the where argument cannot be greater" - + " than the content length", where); - - // check if the gap is big enough to hold the string - if ((gapEnd - gapStart) < strLen) - // make room for this string and some more - shiftEnd(strLen + DEFAULT_BUFSIZE); + + " than the content length", where); - // are we at the gap boundary? - if (where != gapStart) - shiftGap(where); + replace(where, 0, str.toCharArray(), str.length()); - // now we can simple copy the string into the gap and adjust the - // gap boundaries - System.arraycopy(str.toCharArray(), 0, buffer, gapStart, strLen); - gapStart += strLen; return null; } /** * Removes a piece of content at th specified position. - * + * * @param where the position where the content is to be removed * @param nitems number of characters to be removed - * + * * @return an UndoableEdit object (currently not supported, so * <code>null</code> is returned) - * - * @throws BadLocationException if <code>where</code> is not a valid location - * in the buffer + * + * @throws BadLocationException if <code>where</code> is not a valid + * location in the buffer */ - public UndoableEdit remove(int where, int nitems) - throws BadLocationException + public UndoableEdit remove(int where, int nitems) throws BadLocationException { // check arguments int length = length(); if (where >= length) throw new BadLocationException("the where argument cannot be greater" - + " than the content length", where); + + " than the content length", where); if ((where + nitems) > length) throw new BadLocationException("where + nitems cannot be greater" - + " than the content length", - where + nitems); + + " than the content length", where + nitems); - // check if we are at the gap boundary - if (where != gapStart) - shiftGap(where); + replace(where, nitems, null, 0); - // now we simply have to enlarge the gap - gapEnd += nitems; return null; } /** * Returns a piece of content as String. - * + * * @param where the start location of the fragment * @param len the length of the fragment - * + * * @throws BadLocationException if <code>where</code> or * <code>where + len</code> are no valid locations in the buffer */ public String getString(int where, int len) throws BadLocationException { Segment seg = new Segment(); - getChars(where, len, seg); - return new String(seg.array, seg.offset, seg.count); + try + { + getChars(where, len, seg); + return new String(seg.array, seg.offset, seg.count); + } + catch (StringIndexOutOfBoundsException ex) + { + int invalid = 0; + if (seg.offset < 0 || seg.offset >= seg.array.length) + invalid = seg.offset; + else + invalid = seg.offset + seg.count; + throw new BadLocationException("Illegal location: array.length = " + + seg.array.length + ", offset = " + + seg.offset + ", count = " + + seg.count, invalid); + } } /** * Fetches a piece of content and stores it in a {@link Segment} object. - * - * If the requested piece of text spans the gap, the content is copied - * into a new array. If it doesn't then it is contiguous and the - * actual content store is returned. - * + * + * If the requested piece of text spans the gap, the content is copied into a + * new array. If it doesn't then it is contiguous and the actual content + * store is returned. + * * @param where the start location of the fragment * @param len the length of the fragment * @param txt the Segment object to store the fragment in - * + * * @throws BadLocationException if <code>where</code> or * <code>where + len</code> are no valid locations in the buffer */ public void getChars(int where, int len, Segment txt) - throws BadLocationException + throws BadLocationException { // check arguments int length = length(); if (where >= length) throw new BadLocationException("the where argument cannot be greater" - + " than the content length", where); + + " than the content length", where); if ((where + len) > length) throw new BadLocationException("len plus where cannot be greater" - + " than the content length", - len + where); + + " than the content length", len + where); // check if requested segment is contiguous if ((where < gapStart) && ((gapStart - where) < len)) - { - // requested segment is not contiguous -> copy the pieces together - char[] copy = new char[len]; - int lenFirst = gapStart - where; // the length of the first segment - System.arraycopy(buffer, where, copy, 0, lenFirst); - System.arraycopy(buffer, gapEnd, copy, lenFirst, len - lenFirst); - txt.array = copy; - txt.offset = 0; - txt.count = len; - } + { + // requested segment is not contiguous -> copy the pieces together + char[] copy = new char[len]; + int lenFirst = gapStart - where; // the length of the first segment + System.arraycopy(buffer, where, copy, 0, lenFirst); + System.arraycopy(buffer, gapEnd, copy, lenFirst, len - lenFirst); + txt.array = copy; + txt.offset = 0; + txt.count = len; + } else - { - // requested segment is contiguous -> we can simply return the - // actual content - txt.array = buffer; - if (where < gapStart) - txt.offset = where; - else - txt.offset = where + (gapEnd - gapStart); - txt.count = len; - } + { + // requested segment is contiguous -> we can simply return the + // actual content + txt.array = buffer; + if (where < gapStart) + txt.offset = where; + else + txt.offset = where + (gapEnd - gapStart); + txt.count = len; + } } /** * Creates and returns a mark at the specified position. - * + * * @param offset the position at which to create the mark - * + * * @return the create Position object for the mark - * - * @throws BadLocationException if the offset is not a valid position in - * the buffer + * + * @throws BadLocationException if the offset is not a valid position in the + * buffer */ public Position createPosition(final int offset) throws BadLocationException { - return new Position() - { - int off = offset; - - public int getOffset() - { - return off; - } - }; + if (offset < 0 || offset > length()) + throw new BadLocationException("The offset was out of the bounds of this" + + " buffer", offset); + + // We store the actual array index in the GapContentPosition. The real + // offset is then calculated in the GapContentPosition. + int mark = offset; + if (offset > gapStart) + mark += gapEnd - gapStart; + GapContentPosition pos = new GapContentPosition(mark); + + // Add this into our list in a sorted fashion. + int index = Collections.binarySearch(positions, pos); + if (index < 0) + index = -(index + 1); + positions.add(index, pos); + + return pos; } /** * Enlarges the gap. This allocates a new bigger buffer array, copy the - * segment before the gap as it is and the segment after the gap at - * the end of the new buffer array. This does change the gapEnd mark - * but not the gapStart mark. - * + * segment before the gap as it is and the segment after the gap at the end + * of the new buffer array. This does change the gapEnd mark but not the + * gapStart mark. + * * @param newSize the new size of the gap */ protected void shiftEnd(int newSize) { + int delta = (gapEnd - gapStart) - newSize; char[] newBuf = (char[]) allocateArray(length() + newSize); System.arraycopy(buffer, 0, newBuf, 0, gapStart); - System.arraycopy(buffer, gapEnd, newBuf, gapStart + newSize, - buffer.length - gapEnd); + System.arraycopy(buffer, gapEnd, newBuf, gapStart + newSize, buffer.length + - gapEnd); gapEnd = gapStart + newSize; buffer = newBuf; + + // Update the marks after the gapEnd. + int index = Collections.binarySearch(positions, new GapContentPosition( + gapEnd)); + if (index < 0) + { + index = -(index + 1); + } + for (ListIterator i = positions.listIterator(index); i.hasNext();) + { + GapContentPosition p = (GapContentPosition) i.next(); + p.mark += delta; + } } /** * Shifts the gap to the specified position. - * + * * @param newGapStart the new start position of the gap */ protected void shiftGap(int newGapStart) { int newGapEnd = newGapStart + (gapEnd - gapStart); + // Update the positions between newGapEnd and (old) gapEnd. The marks + // must be shifted by (gapEnd - newGapEnd). + int index1 = Collections.binarySearch(positions, + new GapContentPosition(gapEnd)); + int index2 = Collections.binarySearch(positions, + new GapContentPosition(newGapEnd)); + if (index1 > 0 && index2 > 0) + { + int i1 = Math.min(index1, index2); + int i2 = Math.max(index1, index2); + for (ListIterator i = positions.listIterator(i1); i.hasNext();) + { + if (i.nextIndex() > i2) + break; + + GapContentPosition p = (GapContentPosition) i.next(); + p.mark += gapEnd - newGapEnd; + } + } + if (newGapStart == gapStart) return; else if (newGapStart < gapStart) { - System.arraycopy(buffer, newGapStart, buffer, newGapEnd, - gapStart - newGapStart); + System.arraycopy(buffer, newGapStart, buffer, newGapEnd, gapStart + - newGapStart); gapStart = newGapStart; gapEnd = newGapEnd; } else { - System.arraycopy(buffer, gapEnd, buffer, gapStart, - newGapStart - gapStart); + System.arraycopy(buffer, gapEnd, buffer, gapStart, newGapStart + - gapStart); gapStart = newGapStart; gapEnd = newGapEnd; } @@ -346,11 +457,38 @@ public class GapContent /** * Returns the allocated buffer array. - * + * * @return the allocated buffer array */ protected Object getArray() { return buffer; } + + /** + * Replaces a portion of the storage with the specified items. + * + * @param position the position at which to remove items + * @param rmSize the number of items to remove + * @param addItems the items to add at location + * @param addSize the number of items to add + */ + protected void replace(int position, int rmSize, Object addItems, + int addSize) + { + // Remove content + shiftGap(position); + gapEnd += rmSize; + + // If gap is too small, enlarge the gap. + if ((gapEnd - gapStart) < addSize) + shiftEnd(addSize); + + // Add new items to the buffer. + if (addItems != null) + { + System.arraycopy(addItems, 0, buffer, gapStart, addSize); + gapStart += addSize; + } + } } diff --git a/libjava/classpath/javax/swing/text/InternationalFormatter.java b/libjava/classpath/javax/swing/text/InternationalFormatter.java index 531a4c1aa10..cedaf59feeb 100644 --- a/libjava/classpath/javax/swing/text/InternationalFormatter.java +++ b/libjava/classpath/javax/swing/text/InternationalFormatter.java @@ -214,7 +214,7 @@ public class InternationalFormatter /** * Converts a value object into a String. This is done by invoking - * {@link Format#format} on the specified <code>Format</code> object. + * {@link Format#format(Object)} on the specified <code>Format</code> object. * If no format is set, then {@link DefaultFormatter#valueToString(Object)} * is called as a fallback. * diff --git a/libjava/classpath/javax/swing/text/JTextComponent.java b/libjava/classpath/javax/swing/text/JTextComponent.java index f2ef4d77ffe..b3fad79124c 100644 --- a/libjava/classpath/javax/swing/text/JTextComponent.java +++ b/libjava/classpath/javax/swing/text/JTextComponent.java @@ -96,7 +96,6 @@ public abstract class JTextComponent extends JComponent /** * Constructor AccessibleJTextComponent - * @param component TODO */ public AccessibleJTextComponent() { @@ -712,8 +711,8 @@ public abstract class JTextComponent extends JComponent * @return A Keymap associated with the provided name, or * <code>null</code> if no such Keymap exists * - * @see #addKeymap() - * @see #removeKeymap() + * @see #addKeymap + * @see #removeKeymap * @see #keymaps */ public static Keymap getKeymap(String n) @@ -728,7 +727,7 @@ public abstract class JTextComponent extends JComponent * * @return The keymap removed from the global table * - * @see #addKeymap() + * @see #addKeymap * @see #getKeymap() * @see #keymaps */ @@ -751,7 +750,7 @@ public abstract class JTextComponent extends JComponent * * @return The newly created Keymap * - * @see #removeKeymap() + * @see #removeKeymap * @see #getKeymap() * @see #keymaps */ @@ -769,7 +768,7 @@ public abstract class JTextComponent extends JComponent * * @return The component's current Keymap * - * @see #setKeymap() + * @see #setKeymap * @see #keymap */ public Keymap getKeymap() @@ -901,8 +900,8 @@ public abstract class JTextComponent extends JComponent * @param actions The set of actions to resolve binding names against * * @see Action#NAME - * @see Action#getValue() - * @see KeyBinding#ActionName + * @see Action#getValue + * @see KeyBinding#actionName */ public static void loadKeymap(Keymap map, JTextComponent.KeyBinding[] bindings, @@ -921,12 +920,12 @@ public abstract class JTextComponent extends JComponent * editor can run. Equivalent to calling * <code>getUI().getEditorKit().getActions()</code>. This set of Actions * is a reasonable value to provide as a parameter to {@link - * #loadKeymap()}, when resolving a set of {@link #KeyBinding} objects + * #loadKeymap}, when resolving a set of {@link KeyBinding} objects * against this component. * * @return The set of available Actions on this component's {@link EditorKit} * - * @see TextUI#getEditorKit() + * @see TextUI#getEditorKit * @see EditorKit#getActions() */ public Action[] getActions() @@ -1122,7 +1121,7 @@ public abstract class JTextComponent extends JComponent /** * This method sets the label's UI delegate. * - * @param ui The label's UI delegate. + * @param newUI The label's UI delegate. */ public void setUI(TextUI newUI) { @@ -1360,7 +1359,7 @@ public abstract class JTextComponent extends JComponent /** * Selects the text from the given postion to the selection end position. * - * @param end the start positon of the selected text. + * @param start the start positon of the selected text. */ public void setSelectionStart(int start) { @@ -1391,7 +1390,7 @@ public abstract class JTextComponent extends JComponent * Selects a part of the content of the text component. * * @param start the start position of the selected text - * @param ent the end position of the selected text + * @param end the end position of the selected text */ public void select(int start, int end) { @@ -1635,7 +1634,7 @@ public abstract class JTextComponent extends JComponent * * @throws IOException if the reader throws it. * - * @see getDocument() + * @see #getDocument() * @see Document#getProperty(Object) */ public void read(Reader input, Object streamDescription) diff --git a/libjava/classpath/javax/swing/text/PasswordView.java b/libjava/classpath/javax/swing/text/PasswordView.java index 229fd2b508d..c3aa66cbe17 100644 --- a/libjava/classpath/javax/swing/text/PasswordView.java +++ b/libjava/classpath/javax/swing/text/PasswordView.java @@ -1,56 +1,59 @@ /* PasswordView.java -- - Copyright (C) 2004 Free Software Foundation, Inc. - -This file is part of GNU Classpath. - -GNU Classpath is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GNU Classpath 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 for more details. - -You should have received a copy of the GNU General Public License -along with GNU Classpath; see the file COPYING. If not, write to the -Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -02110-1301 USA. - -Linking this library statically or dynamically with other modules is -making a combined work based on this library. Thus, the terms and -conditions of the GNU General Public License cover the whole -combination. - -As a special exception, the copyright holders of this library give you -permission to link this library with independent modules to produce an -executable, regardless of the license terms of these independent -modules, and to copy and distribute the resulting executable under -terms of your choice, provided that you also meet, for each linked -independent module, the terms and conditions of the license of that -module. An independent module is a module which is not derived from -or based on this library. If you modify this library, you may extend -this exception to your version of the library, but you are not -obligated to do so. If you do not wish to do so, delete this -exception statement from your version. */ + Copyright (C) 2004 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath 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 for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ package javax.swing.text; import java.awt.Color; +import java.awt.FontMetrics; import java.awt.Graphics; +import java.awt.Shape; import javax.swing.JPasswordField; -public class PasswordView extends FieldView +public class PasswordView + extends FieldView { /** * Buffer for putting the echo char into it and * then using it to draw it into the view. */ private char[] oneCharBuffer = new char[1]; - + public PasswordView(Element elem) { super(elem); @@ -70,7 +73,7 @@ public class PasswordView extends FieldView { // Update font metrics. updateMetrics(); - + // Draw character. oneCharBuffer[0] = ch; g.drawChars(oneCharBuffer, 0, 1, x, y); @@ -82,7 +85,7 @@ public class PasswordView extends FieldView private char getEchoChar() { char ch = ((JPasswordField) getContainer()).getEchoChar(); - + if (ch == 0) ch = '*'; @@ -107,10 +110,10 @@ public class PasswordView extends FieldView // Update font metrics. updateMetrics(); - + // Get echo character. char ch = getEchoChar(); - + // Set color for selected text. g.setColor(selectedColor); g.setColor(Color.BLACK); @@ -120,7 +123,7 @@ public class PasswordView extends FieldView char[] buffer = new char[len]; for (int index = 0; index < len; ++index) buffer[index] = ch; - + // Draw echo charaters. g.drawChars(buffer, 0, len, x, y); @@ -146,25 +149,96 @@ public class PasswordView extends FieldView // Update font metrics. updateMetrics(); - + // Get echo character. char ch = getEchoChar(); - + Segment segment = new Segment(); + // Set color for unselected text. g.setColor(unselectedColor); g.setColor(Color.BLACK); // Initialize buffer for faster drawing of all characters. - int len = p1 - p0; + p1--; + getDocument().getText(p0, p1 - p0, segment); + int len = segment.toString().length(); + char[] buffer = new char[len]; for (int index = 0; index < len; ++index) buffer[index] = ch; + y += getPreferredSpan(Y_AXIS)/2; + // Draw echo charaters. g.drawChars(buffer, 0, len, x, y); - + // Return new x position right of all drawn characters. - return x + len * metrics.charWidth(ch); + return x + (len * metrics.charWidth(ch)); + } + + /** + * Determines the preferred span for this view along an axis. + * + * @param axis to get the preferred span of + * @return the preferred span of the axis + */ + public float getPreferredSpan(int axis) + { + if (axis != X_AXIS && axis != Y_AXIS) + throw new IllegalArgumentException(); + + FontMetrics fm = getFontMetrics(); + + if (axis == Y_AXIS) + return fm.getHeight(); + + String text; + Element elem = getElement(); + + try + { + text = elem.getDocument().getText(elem.getStartOffset(), + elem.getEndOffset()); + } + catch (BadLocationException e) + { + // This should never happen. + text = ""; + } + return fm.stringWidth(text); } -} + /** + * Provides a mapping from the document model coordinate space to the + * coordinate space of the view mapped to it. + * + * @param pos - the position to convert >= 0 + * @param a - the allocated region to render into + * @param b - typesafe enumeration to indicate bias to a position in the model. + * @return the bounding box of the given position + * @throws BadLocationException if the given position does not + * represent a valid location in the associated document + */ + public Shape modelToView(int pos, Shape a, Position.Bias b) + throws BadLocationException + { + return super.modelToView(pos, a, b); + } + + /** + * Provides a mapping from the view coordinate space to the logical + * coordinate space of the model. + * + * @param fx - the X coordinate >= 0.0f + * @param fy - the Y coordinate >= 0.0f + * @param a - the allocated region to render into + * @param bias - typesafe enumeration to indicate bias to a position in the model. + * @return the location within the model that best represents + * the given point in the view + * + */ + public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) + { + return super.viewToModel(fx, fy, a, bias); + } +} diff --git a/libjava/classpath/javax/swing/text/PlainDocument.java b/libjava/classpath/javax/swing/text/PlainDocument.java index c3f59e436cb..71070e92da7 100644 --- a/libjava/classpath/javax/swing/text/PlainDocument.java +++ b/libjava/classpath/javax/swing/text/PlainDocument.java @@ -135,22 +135,6 @@ public class PlainDocument extends AbstractDocument start, end - len); rootElement.replace(i1, i2 - i1, new Element[]{ newEl }); } - else - { - // otherwise only adjust indices of the element - LeafElement el1 = (LeafElement) rootElement.getElement(i1); - el1.end -= len; - } - - // reindex remaining elements - for (int i = rootElement.getElementIndex(p0) + 1; - i < rootElement.getElementCount(); i++) - { - LeafElement el = (LeafElement) rootElement.getElement(i); - el.start -= len; - el.end -= len; - } - } public Element getDefaultRootElement() diff --git a/libjava/classpath/javax/swing/text/PlainView.java b/libjava/classpath/javax/swing/text/PlainView.java index 5d1fab00032..91d7547e77c 100644 --- a/libjava/classpath/javax/swing/text/PlainView.java +++ b/libjava/classpath/javax/swing/text/PlainView.java @@ -237,5 +237,23 @@ public class PlainView extends View return span; } + + /** + * Maps coordinates from the <code>View</code>'s space into a position + * in the document model. + * + * @param x the x coordinate in the view space + * @param y the y coordinate in the view space + * @param a the allocation of this <code>View</code> + * @param b the bias to use + * + * @return the position in the document that corresponds to the screen + * coordinates <code>x, y</code> + */ + public int viewToModel(float x, float y, Shape a, Position.Bias[] b) + { + // FIXME: not implemented + return 0; + } } diff --git a/libjava/classpath/javax/swing/text/StyledEditorKit.java b/libjava/classpath/javax/swing/text/StyledEditorKit.java index 459f2438679..89c4cf18ee4 100644 --- a/libjava/classpath/javax/swing/text/StyledEditorKit.java +++ b/libjava/classpath/javax/swing/text/StyledEditorKit.java @@ -46,458 +46,663 @@ import java.io.Serializable; import javax.swing.Action; import javax.swing.JEditorPane; +import javax.swing.JTextPane; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; /** - * StyledEditorKit + * An {@link EditorKit} that supports editing styled text. * * @author Andrew Selkirk + * @author Roman Kennke (roman@kennke.org) */ public class StyledEditorKit extends DefaultEditorKit { + /** The serialVersionUID. */ private static final long serialVersionUID = 7002391892985555948L; /** - * UnderlineAction + * Toggles the underline attribute for the selected text. */ public static class UnderlineAction extends StyledEditorKit.StyledTextAction { /** - * Constructor UnderlineAction + * Creates an instance of <code>UnderlineAction</code>. */ public UnderlineAction() { - super("TODO"); - // TODO + super("TODO"); // TODO: Figure out name for this action. } /** - * actionPerformed - * @param event TODO + * Performs the action. + * + * @param event the <code>ActionEvent</code> that describes the action */ public void actionPerformed(ActionEvent event) { - // TODO + JEditorPane editor = getEditor(event); + StyledDocument doc = getStyledDocument(editor); + Element el = doc.getCharacterElement(editor.getSelectionStart()); + boolean isUnderline = StyleConstants.isUnderline(el.getAttributes()); + SimpleAttributeSet atts = new SimpleAttributeSet(); + StyleConstants.setUnderline(atts, ! isUnderline); + setCharacterAttributes(editor, atts, false); } } /** - * ItalicAction + * Toggles the italic attribute for the selected text. */ public static class ItalicAction extends StyledEditorKit.StyledTextAction { /** - * Constructor ItalicAction + * Creates an instance of <code>ItalicAction</code>. */ public ItalicAction() { - super("TODO"); - // TODO + super("TODO"); // TODO: Figure out correct name of this Action. } /** - * actionPerformed - * @param event TODO + * Performs the action. + * + * @param event the <code>ActionEvent</code> that describes the action */ public void actionPerformed(ActionEvent event) { - // TODO + JEditorPane editor = getEditor(event); + StyledDocument doc = getStyledDocument(editor); + Element el = doc.getCharacterElement(editor.getSelectionStart()); + boolean isItalic = StyleConstants.isItalic(el.getAttributes()); + SimpleAttributeSet atts = new SimpleAttributeSet(); + StyleConstants.setItalic(atts, ! isItalic); + setCharacterAttributes(editor, atts, false); } } /** - * BoldAction + * Toggles the bold attribute for the selected text. */ public static class BoldAction extends StyledEditorKit.StyledTextAction { /** - * Constructor BoldAction + * Creates an instance of <code>BoldAction</code>. */ public BoldAction() { - super("TODO"); - // TODO + super("TODO"); // TODO: Figure out correct name of this Action. } /** - * actionPerformed - * @param event TODO + * Performs the action. + * + * @param event the <code>ActionEvent</code> that describes the action */ public void actionPerformed(ActionEvent event) { - // TODO + JEditorPane editor = getEditor(event); + StyledDocument doc = getStyledDocument(editor); + Element el = doc.getCharacterElement(editor.getSelectionStart()); + boolean isBold = StyleConstants.isBold(el.getAttributes()); + SimpleAttributeSet atts = new SimpleAttributeSet(); + StyleConstants.setItalic(atts, ! isBold); + setCharacterAttributes(editor, atts, false); } } /** - * AlignmentAction + * Sets the alignment attribute on the selected text. */ public static class AlignmentAction extends StyledEditorKit.StyledTextAction { /** - * a + * The aligment to set. */ private int a; /** - * Constructor AlignmentAction - * @param nm TODO - * @param a TODO + * Creates a new instance of <code>AlignmentAction</code> to set the + * alignment to <code>a</code>. + * + * @param nm the name of the Action + * @param a the alignment to set */ public AlignmentAction(String nm, int a) { - super("TODO"); - // TODO + super(nm); + this.a = a; } /** - * actionPerformed - * @param event TODO + * Performs the action. + * + * @param event the <code>ActionEvent</code> that describes the action */ public void actionPerformed(ActionEvent event) { - // TODO + SimpleAttributeSet atts = new SimpleAttributeSet(); + StyleConstants.setAlignment(atts, a); + setParagraphAttributes(getEditor(event), atts, false); } } /** - * ForegroundAction + * Sets the foreground color attribute on the selected text. */ public static class ForegroundAction extends StyledEditorKit.StyledTextAction { /** - * fg + * The foreground color to set. */ private Color fg; /** - * Constructor ForegroundAction - * @param nm TODO - * @param fg TODO + * Creates a new instance of <code>ForegroundAction</code> to set the + * foreground color to <code>fg</code>. + * + * @param nm the name of the Action + * @param fg the foreground color to set */ public ForegroundAction(String nm, Color fg) { - super("TODO"); - // TODO + super(nm); + this.fg = fg; } /** - * actionPerformed - * @param event TODO + * Performs the action. + * + * @param event the <code>ActionEvent</code> that describes the action */ public void actionPerformed(ActionEvent event) { - // TODO + SimpleAttributeSet atts = new SimpleAttributeSet(); + StyleConstants.setForeground(atts, fg); + setCharacterAttributes(getEditor(event), atts, false); } } /** - * FontSizeAction + * Sets the font size attribute on the selected text. */ public static class FontSizeAction extends StyledEditorKit.StyledTextAction { /** - * size + * The font size to set. */ private int size; /** - * Constructor FontSizeAction - * @param nm TODO - * @param size TODO + * Creates a new instance of <code>FontSizeAction</code> to set the + * font size to <code>size</code>. + * + * @param nm the name of the Action + * @param size the font size to set */ public FontSizeAction(String nm, int size) { - super("TODO"); - // TODO + super(nm); + this.size = size; } /** - * actionPerformed - * @param event TODO + * Performs the action. + * + * @param event the <code>ActionEvent</code> that describes the action */ public void actionPerformed(ActionEvent event) { - // TODO + SimpleAttributeSet atts = new SimpleAttributeSet(); + StyleConstants.setFontSize(atts, size); + setCharacterAttributes(getEditor(event), atts, false); } } /** - * FontFamilyAction + * Sets the font family attribute on the selected text. */ public static class FontFamilyAction extends StyledEditorKit.StyledTextAction { /** - * family + * The font family to set. */ private String family; /** - * Constructor FontFamilyAction - * @param nm TODO - * @param family TODO + * Creates a new instance of <code>FontFamilyAction</code> to set the + * font family to <code>family</code>. + * + * @param nm the name of the Action + * @param family the font family to set */ public FontFamilyAction(String nm, String family) { - super("TODO"); - // TODO + super(nm); + this.family = family; } /** - * actionPerformed - * @param event TODO + * Performs the action. + * + * @param event the <code>ActionEvent</code> that describes the action */ public void actionPerformed(ActionEvent event) { - // TODO + SimpleAttributeSet atts = new SimpleAttributeSet(); + StyleConstants.setFontFamily(atts, family); + setCharacterAttributes(getEditor(event), atts, false); } } /** - * StyledTextAction + * The abstract superclass of all styled TextActions. This class + * provides some useful methods to manipulate the text attributes. */ public abstract static class StyledTextAction extends TextAction { /** - * Constructor StyledTextAction - * @param nm TODO + * Creates a new instance of <code>StyledTextAction</code>. + * + * @param nm the name of the <code>StyledTextAction</code> */ public StyledTextAction(String nm) { super(nm); - // TODO } /** - * getEditor - * @param event TODO - * @returns JEditorPane + * Returns the <code>JEditorPane</code> component from which the + * <code>ActionEvent</code> originated. + * + * @param event the <code>ActionEvent</code> + * @return the <code>JEditorPane</code> component from which the + * <code>ActionEvent</code> originated */ protected final JEditorPane getEditor(ActionEvent event) { - return null; // TODO + return (JEditorPane) getTextComponent(event); } /** - * setCharacterAttributes - * @param value0 TODO - * @param value1 TODO - * @param value2 TODO + * Sets the specified character attributes on the currently selected + * text of <code>editor</code>. If <code>editor</code> does not have + * a selection, then the attributes are used as input attributes + * for newly inserted content. + * + * @param editor the <code>JEditorPane</code> component + * @param atts the text attributes to set + * @param replace if <code>true</code> the current attributes of the + * selection are replaces, otherwise they are merged */ - protected final void setCharacterAttributes(JEditorPane value0, - AttributeSet value1, - boolean value2) + protected final void setCharacterAttributes(JEditorPane editor, + AttributeSet atts, + boolean replace) { - // TODO + Document doc = editor.getDocument(); + if (doc instanceof StyledDocument) + { + StyledDocument styleDoc = (StyledDocument) editor.getDocument(); + EditorKit kit = editor.getEditorKit(); + if (!(kit instanceof StyledEditorKit)) + { + StyledEditorKit styleKit = (StyledEditorKit) kit; + int start = editor.getSelectionStart(); + int end = editor.getSelectionEnd(); + int dot = editor.getCaret().getDot(); + if (start == dot && end == dot) + { + // If there is no selection, then we only update the + // input attributes. + MutableAttributeSet inputAttributes = + styleKit.getInputAttributes(); + inputAttributes.addAttributes(atts); + } + else + styleDoc.setCharacterAttributes(start, end, atts, replace); + } + else + throw new AssertionError("The EditorKit for StyledTextActions " + + "is expected to be a StyledEditorKit"); + } + else + throw new AssertionError("The Document for StyledTextActions is " + + "expected to be a StyledDocument."); } /** - * getStyledDocument - * @param value0 TODO - * @returns StyledDocument + * Returns the {@link StyledDocument} that is used by <code>editor</code>. + * + * @param editor the <code>JEditorPane</code> from which to get the + * <code>StyledDocument</code> + * + * @return the {@link StyledDocument} that is used by <code>editor</code> */ - protected final StyledDocument getStyledDocument(JEditorPane value0) + protected final StyledDocument getStyledDocument(JEditorPane editor) { - return null; // TODO + Document doc = editor.getDocument(); + if (!(doc instanceof StyledDocument)) + throw new AssertionError("The Document for StyledEditorKits is " + + "expected to be a StyledDocument."); + + return (StyledDocument) doc; } /** - * getStyledEditorKit - * @param value0 TODO - * @returns StyledEditorKit + * Returns the {@link StyledEditorKit} that is used by <code>editor</code>. + * + * @param editor the <code>JEditorPane</code> from which to get the + * <code>StyledEditorKit</code> + * + * @return the {@link StyledEditorKit} that is used by <code>editor</code> */ - protected final StyledEditorKit getStyledEditorKit(JEditorPane value0) + protected final StyledEditorKit getStyledEditorKit(JEditorPane editor) { - return null; // TODO + EditorKit kit = editor.getEditorKit(); + if (!(kit instanceof StyledEditorKit)) + throw new AssertionError("The EditorKit for StyledDocuments is " + + "expected to be a StyledEditorKit."); + + return (StyledEditorKit) kit; } /** - * setParagraphAttributes - * @param value0 TODO - * @param value1 TODO - * @param value2 TODO + * Sets the specified character attributes on the paragraph that + * contains the currently selected + * text of <code>editor</code>. If <code>editor</code> does not have + * a selection, then the attributes are set on the paragraph that + * contains the current caret position. + * + * @param editor the <code>JEditorPane</code> component + * @param atts the text attributes to set + * @param replace if <code>true</code> the current attributes of the + * selection are replaces, otherwise they are merged */ - protected final void setParagraphAttributes(JEditorPane value0, - AttributeSet value1, - boolean value2) + protected final void setParagraphAttributes(JEditorPane editor, + AttributeSet atts, + boolean replace) { - // TODO + Document doc = editor.getDocument(); + if (doc instanceof StyledDocument) + { + StyledDocument styleDoc = (StyledDocument) editor.getDocument(); + EditorKit kit = editor.getEditorKit(); + if (!(kit instanceof StyledEditorKit)) + { + StyledEditorKit styleKit = (StyledEditorKit) kit; + int start = editor.getSelectionStart(); + int end = editor.getSelectionEnd(); + int dot = editor.getCaret().getDot(); + if (start == dot && end == dot) + { + // If there is no selection, then we only update the + // input attributes. + MutableAttributeSet inputAttributes = + styleKit.getInputAttributes(); + inputAttributes.addAttributes(atts); + } + else + styleDoc.setParagraphAttributes(start, end, atts, replace); + } + else + throw new AssertionError("The EditorKit for StyledTextActions " + + "is expected to be a StyledEditorKit"); + } + else + throw new AssertionError("The Document for StyledTextActions is " + + "expected to be a StyledDocument."); } } /** - * StyledViewFactory + * A {@link ViewFactory} that is able to create {@link View}s for + * the <code>Element</code>s that are supported by + * <code>StyledEditorKit</code>, namely the following types of Elements: + * + * <ul> + * <li>{@link AbstractDocument.ContentElementName}</li> + * <li>{@link AbstractDocument.ParagraphElementName}</li> + * <li>{@link AbstractDocument.SectionElementName}</li> + * <li>{@link StyleContext.ComponentElementName}</li> + * <li>{@link StyleContext.IconElementName}</li> + * </ul> */ static class StyledViewFactory implements ViewFactory { /** - * Constructor StyledViewFactory - */ - StyledViewFactory() - { - // TODO - } - - /** - * create - * @param value0 TODO - * @returns View + * Creates a {@link View} for the specified <code>Element</code>. + * + * @param element the <code>Element</code> to create a <code>View</code> + * for + * @return the <code>View</code> for the specified <code>Element</code> + * or <code>null</code> if the type of <code>element</code> is + * not supported */ - public View create(Element value0) + public View create(Element element) { - return null; // TODO + String name = element.getName(); + View view = null; + if (name.equals(AbstractDocument.ContentElementName)) + view = new LabelView(element); + else if (name.equals(AbstractDocument.ParagraphElementName)) + view = new ParagraphView(element); + else if (name.equals(AbstractDocument.SectionElementName)) + view = new BoxView(element, View.Y_AXIS); + else if (name.equals(StyleConstants.ComponentElementName)) + view = new ComponentView(element); + else if (name.equals(StyleConstants.IconElementName)) + view = new IconView(element); + else + throw new AssertionError("Unknown Element type: " + + element.getClass().getName() + " : " + + name); + return view; } } /** - * AttributeTracker + * Keeps track of the caret position and updates the currentRun + * <code>Element</code> and the <code>inputAttributes</code>. */ - class AttributeTracker - implements CaretListener, PropertyChangeListener, Serializable + class CaretTracker + implements CaretListener { /** - * Constructor AttributeTracker - * @param value0 TODO - */ - AttributeTracker(StyledEditorKit value0) - { - // TODO - } - - /** - * updateInputAttributes - * @param value0 TODO - * @param value1 TODO - * @param value2 TODO + * Notifies an update of the caret position. + * + * @param ev the event for the caret update */ - void updateInputAttributes(int value0, int value1, JTextComponent value2) + public void caretUpdate(CaretEvent ev) { - // TODO - } - - /** - * propertyChange - * @param value0 TODO - */ - public void propertyChange(PropertyChangeEvent value0) - { - // TODO - } - - /** - * caretUpdate - * @param value0 TODO - */ - public void caretUpdate(CaretEvent value0) - { - // TODO + Object source = ev.getSource(); + if (!(source instanceof JTextComponent)) + throw new AssertionError("CaretEvents are expected to come from a" + + "JTextComponent."); + + JTextComponent text = (JTextComponent) source; + Document doc = text.getDocument(); + if (!(doc instanceof StyledDocument)) + throw new AssertionError("The Document used by StyledEditorKits is" + + "expected to be a StyledDocument"); + + StyledDocument styleDoc = (StyledDocument) doc; + currentRun = styleDoc.getCharacterElement(ev.getDot()); + createInputAttributes(currentRun, inputAttributes); } } /** - * currentRun + * Stores the <code>Element</code> at the current caret position. This + * is updated by {@link CaretTracker}. */ Element currentRun; /** - * currentParagraph + * The current input attributes. This is updated by {@link CaretTracker}. */ - Element currentParagraph; + MutableAttributeSet inputAttributes; /** - * inputAttributes + * The CaretTracker that keeps track of the current input attributes, and + * the current character run Element. */ - MutableAttributeSet inputAttributes; + CaretTracker caretTracker; + + /** + * The ViewFactory for StyledEditorKits. + */ + StyledViewFactory viewFactory; /** - * Constructor StyledEditorKit + * Creates a new instance of <code>StyledEditorKit</code>. */ public StyledEditorKit() { - // TODO + inputAttributes = new SimpleAttributeSet(); } /** - * clone - * @returns Object + * Creates an exact copy of this <code>StyledEditorKit</code>. + * + * @return an exact copy of this <code>StyledEditorKit</code> */ public Object clone() { - return null; // TODO + StyledEditorKit clone = (StyledEditorKit) super.clone(); + // FIXME: Investigate which fields must be copied. + return clone; } /** - * getActions - * @returns Action[] + * Returns the <code>Action</code>s supported by this {@link EditorKit}. + * This includes the {@link BoldAction}, {@link ItalicAction} and + * {@link UnderlineAction} as well as the <code>Action</code>s supported + * by {@link DefaultEditorKit}. + * + * The other <code>Action</code>s of <code>StyledEditorKit</code> are not + * returned here, since they require a parameter and thus custom + * instantiation. + * + * @return the <code>Action</code>s supported by this {@link EditorKit} */ public Action[] getActions() { - return null; // TODO + Action[] actions1 = super.getActions(); + Action[] myActions = new Action[] { new BoldAction(), new ItalicAction(), + new UnderlineAction() }; + return TextAction.augmentList(actions1, myActions); } /** - * getInputAttributes - * @returns MutableAttributeSet + * Returns the current input attributes. These are automatically set on + * any newly inserted content, if not specified otherwise. + * + * @return the current input attributes */ public MutableAttributeSet getInputAttributes() { - return null; // TODO + return inputAttributes; } /** - * getCharacterAttributeRun - * @returns Element + * Returns the {@link Element} that represents the character run at the + * current caret position. + * + * @return the {@link Element} that represents the character run at the + * current caret position */ public Element getCharacterAttributeRun() { - return null; // TODO + return currentRun; } /** - * createDefaultDocument - * @returns Document + * Creates the default {@link Document} supported by this + * <code>EditorKit</code>. This is an instance of + * {@link DefaultStyledDocument} in this case but may be overridden by + * subclasses. + * + * @return an instance of <code>DefaultStyledDocument</code> */ public Document createDefaultDocument() { - return null; // TODO + return new DefaultStyledDocument(); } /** - * install - * @param component TODO + * Installs this <code>EditorKit</code> on the specified {@link JEditorPane}. + * This basically involves setting up required listeners on the + * <code>JEditorPane</code>. + * + * @param component the <code>JEditorPane</code> to install this + * <code>EditorKit</code> on */ public void install(JEditorPane component) { - // TODO + CaretTracker tracker = new CaretTracker(); + component.addCaretListener(tracker); } /** - * deinstall - * @param component TODO + * Deinstalls this <code>EditorKit</code> from the specified + * {@link JEditorPane}. This basically involves removing all listeners from + * <code>JEditorPane</code> that have been set up by this + * <code>EditorKit</code>. + * + * @param component the <code>JEditorPane</code> from which to deinstall this + * <code>EditorKit</code> */ public void deinstall(JEditorPane component) { - // TODO + CaretTracker t = caretTracker; + if (t != null) + component.removeCaretListener(t); + caretTracker = null; } /** - * getViewFactory - * @returns ViewFactory + * Returns a {@link ViewFactory} that is able to create {@link View}s + * for {@link Element}s that are supported by this <code>EditorKit</code>, + * namely the following types of <code>Element</code>s: + * + * <ul> + * <li>{@link AbstractDocument.ContentElementName}</li> + * <li>{@link AbstractDocument.ParagraphElementName}</li> + * <li>{@link AbstractDocument.SectionElementName}</li> + * <li>{@link StyleContext.ComponentElementName}</li> + * <li>{@link StyleContext.IconElementName}</li> + * </ul> + * + * @return a {@link ViewFactory} that is able to create {@link View}s + * for {@link Element}s that are supported by this <code>EditorKit</code> */ public ViewFactory getViewFactory() { - return null; // TODO + if (viewFactory == null) + viewFactory = new StyledViewFactory(); + return viewFactory; } /** - * createInputAttributes - * @param element TODO - * @param set TODO + * Copies the text attributes from <code>element</code> to <code>set</code>. + * This is called everytime when the caret position changes to keep + * track of the current input attributes. The attributes in <code>set</code> + * are cleaned before adding the attributes of <code>element</code>. + * + * This method filters out attributes for element names, <code>Icon</code>s + * and <code>Component</code>s. + * + * @param element the <code>Element</code> from which to copy the text + * attributes + * @param set the inputAttributes to copy the attributes to */ - protected void createInputAttributes(Element element, MutableAttributeSet set) + protected void createInputAttributes(Element element, + MutableAttributeSet set) { - // TODO + AttributeSet atts = element.getAttributes(); + set.removeAttributes(set); + // FIXME: Filter out component, icon and element name attributes. + set.addAttributes(atts); } } diff --git a/libjava/classpath/javax/swing/text/View.java b/libjava/classpath/javax/swing/text/View.java index 4d9ed7b3122..24efba9a1bc 100644 --- a/libjava/classpath/javax/swing/text/View.java +++ b/libjava/classpath/javax/swing/text/View.java @@ -62,11 +62,6 @@ public abstract class View implements SwingConstants private View parent; /** - * The child views. - */ - View[] children; - - /** * Creates a new <code>View</code> instance. * * @param elem an <code>Element</code> value @@ -74,7 +69,6 @@ public abstract class View implements SwingConstants public View(Element elem) { elt = elem; - children = new View[0]; } public abstract void paint(Graphics g, Shape s); @@ -92,7 +86,10 @@ public abstract class View implements SwingConstants public Container getContainer() { View parent = getParent(); - return parent != null ? parent.getContainer() : null; + if (parent == null) + throw new AssertionError("The parent of a View must not be null."); + + return parent.getContainer(); } public Document getDocument() @@ -178,12 +175,13 @@ public abstract class View implements SwingConstants public void append(View view) { View[] array = { view }; - replace(getViewCount(), 1, array); + int offset = getViewCount(); + replace(offset, 0, array); } public void removeAll() { - replace(0, getViewCount(), null); + replace(0, getViewCount(), new View[0]); } public void remove(int index) @@ -250,8 +248,6 @@ public abstract class View implements SwingConstants { if (parent != null) parent.preferenceChanged(this, width, height); - else - ((JComponent) getContainer()).revalidate(); } public int getBreakWeight(int axis, float pos, float len) @@ -351,7 +347,7 @@ public abstract class View implements SwingConstants Element el = getElement(); DocumentEvent.ElementChange ec = ev.getChange(el); if (ec != null) - updateChildren(ec, ev, vf); + updateChildren(ec, ev, vf); forwardUpdate(ec, ev, shape, vf); updateLayout(ec, ev, shape); } @@ -382,16 +378,12 @@ public abstract class View implements SwingConstants { Element[] added = ec.getChildrenAdded(); Element[] removed = ec.getChildrenRemoved(); - View[] newChildren = new View[children.length + added.length - - removed.length]; int index = ec.getIndex(); - System.arraycopy(children, 0, newChildren, 0, index); - System.arraycopy(children, index, added, 0, added.length); - int index2 = index + removed.length; - int len2 = children.length - index2; - System.arraycopy(children, index2, newChildren, index + added.length, - len2); - children = newChildren; + + View[] newChildren = new View[added.length]; + for (int i = 0; i < added.length; ++i) + newChildren[i] = vf.create(added[i]); + replace(index, removed.length, newChildren); return true; } @@ -412,9 +404,10 @@ public abstract class View implements SwingConstants protected void forwardUpdate(DocumentEvent.ElementChange ec, DocumentEvent ev, Shape shape, ViewFactory vf) { - for (int i = 0; i < children.length; i++) + int count = getViewCount(); + for (int i = 0; i < count; i++) { - View child = children[i]; + View child = getView(i); forwardUpdateToView(child, ev, shape, vf); } } @@ -459,5 +452,104 @@ public abstract class View implements SwingConstants if (ec != null) preferenceChanged(this, true, true); } -} + /** + * Maps a position in the document into the coordinate space of the View. + * The output rectangle usually reflects the font height but has a width + * of zero. + * + * @param pos the position of the character in the model + * @param a the area that is occupied by the view + * @param b either {@link Position.Bias#Forward} or + * {@link Position.Bias#Backward} depending on the preferred + * direction bias. If <code>null</code> this defaults to + * <code>Position.Bias.Forward</code> + * + * @return a rectangle that gives the location of the document position + * inside the view coordinate space + * + * @throws BadLocationException if <code>pos</code> is invalid + * @throws IllegalArgumentException if b is not one of the above listed + * valid values + */ + public abstract Shape modelToView(int pos, Shape a, Position.Bias b) + throws BadLocationException; + + /** + * Maps a region in the document into the coordinate space of the View. + * + * @param p1 the beginning position inside the document + * @param b1 the direction bias for the beginning position + * @param p2 the end position inside the document + * @param b2 the direction bias for the end position + * @param a the area that is occupied by the view + * + * @return a rectangle that gives the span of the document region + * inside the view coordinate space + * + * @throws BadLocationException if <code>p1</code> or <code>p2</code> are + * invalid + * @throws IllegalArgumentException if b1 or b2 is not one of the above + * listed valid values + */ + public Shape modelToView(int p1, Position.Bias b1, + int p2, Position.Bias b2, Shape a) + throws BadLocationException + { + if (b1 != Position.Bias.Forward && b1 != Position.Bias.Backward) + throw new IllegalArgumentException + ("b1 must be either Position.Bias.Forward or Position.Bias.Backward"); + if (b2 != Position.Bias.Forward && b2 != Position.Bias.Backward) + throw new IllegalArgumentException + ("b2 must be either Position.Bias.Forward or Position.Bias.Backward"); + Shape s1 = modelToView(p1, a, b1); + Shape s2 = modelToView(p2, a, b2); + return s1.getBounds().union(s2.getBounds()); + } + + /** + * Maps coordinates from the <code>View</code>'s space into a position + * in the document model. + * + * @param x the x coordinate in the view space + * @param y the y coordinate in the view space + * @param a the allocation of this <code>View</code> + * @param b the bias to use + * + * @return the position in the document that corresponds to the screen + * coordinates <code>x, y</code> + */ + public abstract int viewToModel(float x, float y, Shape a, Position.Bias[] b); + + + /** + * Dumps the complete View hierarchy. This method can be used for debugging + * purposes. + */ + void dump() + { + // Climb up the hierarchy to the parent. + View parent = getParent(); + if (parent != null) + parent.dump(); + else + dump(0); + } + + /** + * Dumps the view hierarchy below this View with the specified indentation + * level. + * + * @param indent the indentation level to be used for this view + */ + void dump(int indent) + { + for (int i = 0; i < indent; ++i) + System.out.print('.'); + System.out.println(this); + + int count = getViewCount(); + for (int i = 0; i < count; ++i) + getView(i).dump(indent + 1); + } +} diff --git a/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java b/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java index 7ae78ec0725..c0182fe6ac9 100644 --- a/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java +++ b/libjava/classpath/javax/swing/text/html/HTMLEditorKit.java @@ -38,6 +38,7 @@ exception statement from your version. */ package javax.swing.text.html; +import java.io.IOException; import java.io.Reader; import java.io.Serializable; @@ -75,7 +76,7 @@ public class HTMLEditorKit public abstract void parse(Reader reader, ParserCallback callback, boolean ignoreCharSet ) - throws java.io.IOException; + throws IOException; } /** @@ -123,8 +124,8 @@ public class HTMLEditorKit * The method is called when the HTML closing tag ((like </table>) * is found or if the parser concludes that the one should be present * in the current position. - * @param The tag being handled - * @position the tag position in the text being parsed. + * @param tag The tag being handled + * @param position the tag position in the text being parsed. */ public void handleEndTag(HTML.Tag tag, int position) { diff --git a/libjava/classpath/javax/swing/text/html/parser/DTD.java b/libjava/classpath/javax/swing/text/html/parser/DTD.java index 63d03eaccf0..f17ca011ea0 100644 --- a/libjava/classpath/javax/swing/text/html/parser/DTD.java +++ b/libjava/classpath/javax/swing/text/html/parser/DTD.java @@ -62,7 +62,8 @@ import java.util.Vector; * <p> * If you need more information about SGML DTD documents, * the author suggests to read SGML tutorial on - * {@link http://www.w3.org/TR/WD-html40-970708/intro/sgmltut.html}. + * <a href="http://www.w3.org/TR/WD-html40-970708/intro/sgmltut.html" + * >http://www.w3.org/TR/WD-html40-970708/intro/sgmltut.html</a>. * We also recommend Goldfarb C.F (1991) <i>The SGML Handbook</i>, * Oxford University Press, 688 p, ISBN: 0198537379. * </p> @@ -402,7 +403,7 @@ public class DTD * placed to the field * {@link javax.swing.text.html.parser.AttributeList#next }, * creating a linked list. - * @return + * @return The attributes. */ protected AttributeList defAttributeList(String name, int type, int modifier, String default_value, @@ -541,7 +542,7 @@ public class DTD * The unknown elements are automatically defined and added * to the element table. * @param elements - * @return + * @return The bit set. */ private BitSet bitSet(String[] elements) { diff --git a/libjava/classpath/javax/swing/text/html/parser/DTDConstants.java b/libjava/classpath/javax/swing/text/html/parser/DTDConstants.java index a771264a1ad..75e7afb4db6 100644 --- a/libjava/classpath/javax/swing/text/html/parser/DTDConstants.java +++ b/libjava/classpath/javax/swing/text/html/parser/DTDConstants.java @@ -40,14 +40,16 @@ package javax.swing.text.html.parser; /** * <p>This class defines the SGML basic types, used for describing HTML 4.01 - * at {@link http://www.w3.org/TR/html4/types.html }. Not all constants, + * at <a href="http://www.w3.org/TR/html4/types.html" + * >http://www.w3.org/TR/html4/types.html</a>. Not all constants, * defined here, are actually used in HTML 4.01 SGML specification. Some others * are defined just as part of the required implementation. * </p> * <p> * If you need more information about SGML DTD documents, * the author suggests to read SGML tutorial on - * {@link http://www.w3.org/TR/WD-html40-970708/intro/sgmltut.html}. + * <a href="http://www.w3.org/TR/WD-html40-970708/intro/sgmltut.html" + * >http://www.w3.org/TR/WD-html40-970708/intro/sgmltut.html</a>. * We also recommend Goldfarb C.F (1991) <i>The SGML Handbook</i>, * Oxford University Press, 688 p, ISBN: 0198537379. * </p> diff --git a/libjava/classpath/javax/swing/text/html/parser/DocumentParser.java b/libjava/classpath/javax/swing/text/html/parser/DocumentParser.java index c706f4d0f0b..164297f1882 100644 --- a/libjava/classpath/javax/swing/text/html/parser/DocumentParser.java +++ b/libjava/classpath/javax/swing/text/html/parser/DocumentParser.java @@ -167,7 +167,7 @@ public class DocumentParser * to get a default DTD; you must either refer to the implementation - * specific packages, write your own DTD or obtain the working instance * of parser in other way, for example, by calling - * {@link javax.swing.text.html.HTMLEditorKit#getParser() }. + * {@link javax.swing.text.html.HTMLEditorKit#getParser()}. * @param a_dtd a DTD to use. */ public DocumentParser(DTD a_dtd) @@ -180,18 +180,18 @@ public class DocumentParser * Parses the HTML document, calling methods of the provided * callback. This method must be multithread - safe. * @param reader The reader to read the HTML document from - * @param callback The callback that is notifyed about the presence + * @param aCallback The callback that is notifyed about the presence * of HTML elements in the document. * @param ignoreCharSet If thrue, any charset changes during parsing * are ignored. * @throws java.io.IOException */ - public void parse(Reader reader, HTMLEditorKit.ParserCallback a_callback, + public void parse(Reader reader, HTMLEditorKit.ParserCallback aCallback, boolean ignoreCharSet ) throws IOException { - callBack = a_callback; + callBack = aCallback; gnu.parse(reader); callBack.handleEndOfLineString(gnu.getEndOfLineSequence()); @@ -230,7 +230,7 @@ public class DocumentParser * The method is called when the HTML closing tag ((like </table>) * is found or if the parser concludes that the one should be present * in the current position. - * @param The tag being handled + * @param tag The tag being handled */ protected void handleEndTag(TagElement tag) { @@ -245,7 +245,7 @@ public class DocumentParser * The method is called when the HTML opening tag ((like <table>) * is found or if the parser concludes that the one should be present * in the current position. - * @param The tag being handled + * @param tag The tag being handled */ protected void handleStartTag(TagElement tag) { diff --git a/libjava/classpath/javax/swing/text/html/parser/Element.java b/libjava/classpath/javax/swing/text/html/parser/Element.java index f0a0f3303cb..098983c6923 100644 --- a/libjava/classpath/javax/swing/text/html/parser/Element.java +++ b/libjava/classpath/javax/swing/text/html/parser/Element.java @@ -225,7 +225,7 @@ public final class Element /** * Get all attributes of this document as an attribute list. - * @return + * @return The attribute list. */ public AttributeList getAttributes() { diff --git a/libjava/classpath/javax/swing/text/html/parser/Parser.java b/libjava/classpath/javax/swing/text/html/parser/Parser.java index 5867107cd45..7ff6853da82 100644 --- a/libjava/classpath/javax/swing/text/html/parser/Parser.java +++ b/libjava/classpath/javax/swing/text/html/parser/Parser.java @@ -327,7 +327,7 @@ public class Parser * Handle the tag with no content, like <br>. The method is * called for the elements that, in accordance with the current DTD, * has an empty content. - * @param The tag being handled. + * @param tag The tag being handled. * @throws javax.swing.text.ChangedCharSetException */ protected void handleEmptyTag(TagElement tag) @@ -339,7 +339,7 @@ public class Parser * The method is called when the HTML closing tag ((like </table>) * is found or if the parser concludes that the one should be present * in the current position. - * @param The tag being handled + * @param tag The tag being handled */ protected void handleEndTag(TagElement tag) { @@ -354,7 +354,7 @@ public class Parser * The method is called when the HTML opening tag ((like <table>) * is found or if the parser concludes that the one should be present * in the current position. - * @param The tag being handled + * @param tag The tag being handled */ protected void handleStartTag(TagElement tag) { @@ -383,7 +383,7 @@ public class Parser * both title starting and closing tags are already behind. * The passed argument contains the concatenation of all * title text sections. - * @param The title text. + * @param title The title text. */ protected void handleTitle(char[] title) { @@ -402,7 +402,7 @@ public class Parser /** * Constructs the tag from the given element. - * @param the tag base {@link javax.swing.text.html.parser.Element} + * @param element the tag base {@link javax.swing.text.html.parser.Element} * @param isSupposed true if the tag is not actually present in the * html input, but the parser supposes that it should to occur in * the current location. @@ -427,7 +427,7 @@ public class Parser * is found or if the parser concludes that the one should be present * in the current position. The method is called immediately before * calling the handleStartTag. - * @param The tag + * @param tag The tag */ protected void startTag(TagElement tag) throws ChangedCharSetException diff --git a/libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java b/libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java index 4b54e8a486c..e5d2db4df7c 100644 --- a/libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java +++ b/libjava/classpath/javax/swing/text/html/parser/ParserDelegator.java @@ -143,7 +143,7 @@ public class ParserDelegator * Parses the HTML document, calling methods of the provided * callback. This method must be multithread - safe. * @param reader The reader to read the HTML document from - * @param callback The callback that is notifyed about the presence + * @param a_callback The callback that is notifyed about the presence * of HTML elements in the document. * @param ignoreCharSet If thrue, any charset changes during parsing * are ignored. @@ -191,7 +191,7 @@ public class ParserDelegator * all subsequent calls to the parse(...) . If you need to specify * your DTD locally, simply {@link javax.swing.text.html.parser.Parser} * instead. - * @param dtd The DTD that will be used to parse documents by this class. + * @param a_dtd The DTD that will be used to parse documents by this class. * @param name The name of this DTD. * @return No standard is specified on which instance of DTD must be * returned by this method, and it is recommended to leave the returned |