Merge from mainline
[official-gcc.git] / libjava / classpath / javax / swing / text / AbstractDocument.java
blobc7353885e1213c551a8c031c671cdb4d46d8f15c
1 /* AbstractDocument.java --
2 Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing.text;
41 import java.io.PrintStream;
42 import java.io.Serializable;
43 import java.util.Dictionary;
44 import java.util.Enumeration;
45 import java.util.EventListener;
46 import java.util.Hashtable;
47 import java.util.Vector;
49 import javax.swing.event.DocumentEvent;
50 import javax.swing.event.DocumentListener;
51 import javax.swing.event.EventListenerList;
52 import javax.swing.event.UndoableEditEvent;
53 import javax.swing.event.UndoableEditListener;
54 import javax.swing.tree.TreeNode;
55 import javax.swing.undo.AbstractUndoableEdit;
56 import javax.swing.undo.CompoundEdit;
57 import javax.swing.undo.UndoableEdit;
59 /**
60 * An abstract base implementation for the {@link Document} interface.
61 * This class provides some common functionality for all <code>Element</code>s,
62 * most notably it implements a locking mechanism to make document modification
63 * thread-safe.
65 * @author original author unknown
66 * @author Roman Kennke (roman@kennke.org)
68 public abstract class AbstractDocument implements Document, Serializable
70 /** The serialization UID (compatible with JDK1.5). */
71 private static final long serialVersionUID = 6842927725919637215L;
73 /**
74 * Standard error message to indicate a bad location.
76 protected static final String BAD_LOCATION = "document location failure";
78 /**
79 * Standard name for unidirectional <code>Element</code>s.
81 public static final String BidiElementName = "bidi level";
83 /**
84 * Standard name for content <code>Element</code>s. These are usually
85 * {@link LeafElement}s.
87 public static final String ContentElementName = "content";
89 /**
90 * Standard name for paragraph <code>Element</code>s. These are usually
91 * {@link BranchElement}s.
93 public static final String ParagraphElementName = "paragraph";
95 /**
96 * Standard name for section <code>Element</code>s. These are usually
97 * {@link DefaultStyledDocument.SectionElement}s.
99 public static final String SectionElementName = "section";
102 * Attribute key for storing the element name.
104 public static final String ElementNameAttribute = "$ename";
107 * The actual content model of this <code>Document</code>.
109 Content content;
112 * The AttributeContext for this <code>Document</code>.
114 AttributeContext context;
117 * The currently installed <code>DocumentFilter</code>.
119 DocumentFilter documentFilter;
122 * The documents properties.
124 Dictionary properties;
127 * Manages event listeners for this <code>Document</code>.
129 protected EventListenerList listenerList = new EventListenerList();
132 * Stores the current writer thread. Used for locking.
134 private Thread currentWriter = null;
137 * The number of readers. Used for locking.
139 private int numReaders = 0;
142 * Tells if there are one or more writers waiting.
144 private int numWritersWaiting = 0;
147 * A condition variable that readers and writers wait on.
149 Object documentCV = new Object();
153 * Creates a new <code>AbstractDocument</code> with the specified
154 * {@link Content} model.
156 * @param doc the <code>Content</code> model to be used in this
157 * <code>Document<code>
159 * @see GapContent
160 * @see StringContent
162 protected AbstractDocument(Content doc)
164 this(doc, StyleContext.getDefaultStyleContext());
168 * Creates a new <code>AbstractDocument</code> with the specified
169 * {@link Content} model and {@link AttributeContext}.
171 * @param doc the <code>Content</code> model to be used in this
172 * <code>Document<code>
173 * @param ctx the <code>AttributeContext</code> to use
175 * @see GapContent
176 * @see StringContent
178 protected AbstractDocument(Content doc, AttributeContext ctx)
180 content = doc;
181 context = ctx;
185 * Returns the paragraph {@link Element} that holds the specified position.
187 * @param pos the position for which to get the paragraph element
189 * @return the paragraph {@link Element} that holds the specified position
191 public abstract Element getParagraphElement(int pos);
194 * Returns the default root {@link Element} of this <code>Document</code>.
195 * Usual <code>Document</code>s only have one root element and return this.
196 * However, there may be <code>Document</code> implementations that
197 * support multiple root elements, they have to return a default root element
198 * here.
200 * @return the default root {@link Element} of this <code>Document</code>
202 public abstract Element getDefaultRootElement();
205 * Creates and returns a branch element with the specified
206 * <code>parent</code> and <code>attributes</code>. Note that the new
207 * <code>Element</code> is linked to the parent <code>Element</code>
208 * through {@link Element#getParentElement}, but it is not yet added
209 * to the parent <code>Element</code> as child.
211 * @param parent the parent <code>Element</code> for the new branch element
212 * @param attributes the text attributes to be installed in the new element
214 * @return the new branch <code>Element</code>
216 * @see BranchElement
218 protected Element createBranchElement(Element parent,
219 AttributeSet attributes)
221 return new BranchElement(parent, attributes);
225 * Creates and returns a leaf element with the specified
226 * <code>parent</code> and <code>attributes</code>. Note that the new
227 * <code>Element</code> is linked to the parent <code>Element</code>
228 * through {@link Element#getParentElement}, but it is not yet added
229 * to the parent <code>Element</code> as child.
231 * @param parent the parent <code>Element</code> for the new branch element
232 * @param attributes the text attributes to be installed in the new element
234 * @return the new branch <code>Element</code>
236 * @see LeafElement
238 protected Element createLeafElement(Element parent, AttributeSet attributes,
239 int start, int end)
241 return new LeafElement(parent, attributes, start, end);
245 * Creates a {@link Position} that keeps track of the location at the
246 * specified <code>offset</code>.
248 * @param offset the location in the document to keep track by the new
249 * <code>Position</code>
251 * @return the newly created <code>Position</code>
253 * @throws BadLocationException if <code>offset</code> is not a valid
254 * location in the documents content model
256 public Position createPosition(final int offset) throws BadLocationException
258 return content.createPosition(offset);
262 * Notifies all registered listeners when the document model changes.
264 * @param event the <code>DocumentEvent</code> to be fired
266 protected void fireChangedUpdate(DocumentEvent event)
268 DocumentListener[] listeners = getDocumentListeners();
270 for (int index = 0; index < listeners.length; ++index)
271 listeners[index].changedUpdate(event);
275 * Notifies all registered listeners when content is inserted in the document
276 * model.
278 * @param event the <code>DocumentEvent</code> to be fired
280 protected void fireInsertUpdate(DocumentEvent event)
282 DocumentListener[] listeners = getDocumentListeners();
284 for (int index = 0; index < listeners.length; ++index)
285 listeners[index].insertUpdate(event);
289 * Notifies all registered listeners when content is removed from the
290 * document model.
292 * @param event the <code>DocumentEvent</code> to be fired
294 protected void fireRemoveUpdate(DocumentEvent event)
296 DocumentListener[] listeners = getDocumentListeners();
298 for (int index = 0; index < listeners.length; ++index)
299 listeners[index].removeUpdate(event);
303 * Notifies all registered listeners when an <code>UndoableEdit</code> has
304 * been performed on this <code>Document</code>.
306 * @param event the <code>UndoableEditEvent</code> to be fired
308 protected void fireUndoableEditUpdate(UndoableEditEvent event)
310 UndoableEditListener[] listeners = getUndoableEditListeners();
312 for (int index = 0; index < listeners.length; ++index)
313 listeners[index].undoableEditHappened(event);
317 * Returns the asynchronous loading priority. Returns <code>-1</code> if this
318 * document should not be loaded asynchronously.
320 * @return the asynchronous loading priority
322 public int getAsynchronousLoadPriority()
324 return 0;
328 * Returns the {@link AttributeContext} used in this <code>Document</code>.
330 * @return the {@link AttributeContext} used in this <code>Document</code>
332 protected AttributeContext getAttributeContext()
334 return context;
338 * Returns the root element for bidirectional content.
340 * @return the root element for bidirectional content
342 public Element getBidiRootElement()
344 return null;
348 * Returns the {@link Content} model for this <code>Document</code>
350 * @return the {@link Content} model for this <code>Document</code>
352 * @see GapContent
353 * @see StringContent
355 protected final Content getContent()
357 return content;
361 * Returns the thread that currently modifies this <code>Document</code>
362 * if there is one, otherwise <code>null</code>. This can be used to
363 * distinguish between a method call that is part of an ongoing modification
364 * or if it is a separate modification for which a new lock must be aquired.
366 * @return the thread that currently modifies this <code>Document</code>
367 * if there is one, otherwise <code>null</code>
369 protected Thread getCurrentWriter()
371 return currentWriter;
375 * Returns the properties of this <code>Document</code>.
377 * @return the properties of this <code>Document</code>
379 public Dictionary getDocumentProperties()
381 // FIXME: make me thread-safe
382 if (properties == null)
383 properties = new Hashtable();
385 return properties;
389 * Returns a {@link Position} which will always mark the end of the
390 * <code>Document</code>.
392 * @return a {@link Position} which will always mark the end of the
393 * <code>Document</code>
395 public Position getEndPosition()
397 // FIXME: Properly implement this by calling Content.createPosition().
398 return new Position()
400 public int getOffset()
402 return getLength();
408 * Returns the length of this <code>Document</code>'s content.
410 * @return the length of this <code>Document</code>'s content
412 public int getLength()
414 // We return Content.getLength() -1 here because there is always an
415 // implicit \n at the end of the Content which does count in Content
416 // but not in Document.
417 return content.length() - 1;
421 * Returns all registered listeners of a given listener type.
423 * @param listenerType the type of the listeners to be queried
425 * @return all registered listeners of the specified type
427 public EventListener[] getListeners(Class listenerType)
429 return listenerList.getListeners(listenerType);
433 * Returns a property from this <code>Document</code>'s property list.
435 * @param key the key of the property to be fetched
437 * @return the property for <code>key</code> or <code>null</code> if there
438 * is no such property stored
440 public Object getProperty(Object key)
442 // FIXME: make me thread-safe
443 Object value = null;
444 if (properties != null)
445 value = properties.get(key);
447 return value;
451 * Returns all root elements of this <code>Document</code>. By default
452 * this just returns the single root element returned by
453 * {@link #getDefaultRootElement()}. <code>Document</code> implementations
454 * that support multiple roots must override this method and return all roots
455 * here.
457 * @return all root elements of this <code>Document</code>
459 public Element[] getRootElements()
461 Element[] elements = new Element[1];
462 elements[0] = getDefaultRootElement();
463 return elements;
467 * Returns a {@link Position} which will always mark the beginning of the
468 * <code>Document</code>.
470 * @return a {@link Position} which will always mark the beginning of the
471 * <code>Document</code>
473 public Position getStartPosition()
475 // FIXME: Properly implement this using Content.createPosition().
476 return new Position()
478 public int getOffset()
480 return 0;
486 * Returns a piece of this <code>Document</code>'s content.
488 * @param offset the start offset of the content
489 * @param length the length of the content
491 * @return the piece of content specified by <code>offset</code> and
492 * <code>length</code>
494 * @throws BadLocationException if <code>offset</code> or <code>offset +
495 * length</code> are invalid locations with this
496 * <code>Document</code>
498 public String getText(int offset, int length) throws BadLocationException
500 return content.getString(offset, length);
504 * Fetches a piece of this <code>Document</code>'s content and stores
505 * it in the given {@link Segment}.
507 * @param offset the start offset of the content
508 * @param length the length of the content
509 * @param segment the <code>Segment</code> to store the content in
511 * @throws BadLocationException if <code>offset</code> or <code>offset +
512 * length</code> are invalid locations with this
513 * <code>Document</code>
515 public void getText(int offset, int length, Segment segment)
516 throws BadLocationException
518 content.getChars(offset, length, segment);
522 * Inserts a String into this <code>Document</code> at the specified
523 * position and assigning the specified attributes to it.
525 * @param offset the location at which the string should be inserted
526 * @param text the content to be inserted
527 * @param attributes the text attributes to be assigned to that string
529 * @throws BadLocationException if <code>offset</code> is not a valid
530 * location in this <code>Document</code>
532 public void insertString(int offset, String text, AttributeSet attributes)
533 throws BadLocationException
535 // Just return when no text to insert was given.
536 if (text == null || text.length() == 0)
537 return;
538 DefaultDocumentEvent event =
539 new DefaultDocumentEvent(offset, text.length(),
540 DocumentEvent.EventType.INSERT);
542 writeLock();
543 UndoableEdit undo = content.insertString(offset, text);
544 if (undo != null)
545 event.addEdit(undo);
547 insertUpdate(event, attributes);
548 writeUnlock();
550 fireInsertUpdate(event);
551 if (undo != null)
552 fireUndoableEditUpdate(new UndoableEditEvent(this, undo));
556 * Called to indicate that text has been inserted into this
557 * <code>Document</code>. The default implementation does nothing.
558 * This method is executed within a write lock.
560 * @param chng the <code>DefaultDocumentEvent</code> describing the change
561 * @param attr the attributes of the changed content
563 protected void insertUpdate(DefaultDocumentEvent chng, AttributeSet attr)
565 // Do nothing here. Subclasses may want to override this.
569 * Called after some content has been removed from this
570 * <code>Document</code>. The default implementation does nothing.
571 * This method is executed within a write lock.
573 * @param chng the <code>DefaultDocumentEvent</code> describing the change
575 protected void postRemoveUpdate(DefaultDocumentEvent chng)
577 // Do nothing here. Subclasses may want to override this.
581 * Stores a property in this <code>Document</code>'s property list.
583 * @param key the key of the property to be stored
584 * @param value the value of the property to be stored
586 public void putProperty(Object key, Object value)
588 // FIXME: make me thread-safe
589 if (properties == null)
590 properties = new Hashtable();
592 properties.put(key, value);
596 * Blocks until a read lock can be obtained. Must block if there is
597 * currently a writer modifying the <code>Document</code>.
599 public void readLock()
601 if (currentWriter != null && currentWriter.equals(Thread.currentThread()))
602 return;
603 synchronized (documentCV)
605 while (currentWriter != null || numWritersWaiting > 0)
609 documentCV.wait();
611 catch (InterruptedException ie)
613 throw new Error("interrupted trying to get a readLock");
616 numReaders++;
621 * Releases the read lock. If this was the only reader on this
622 * <code>Document</code>, writing may begin now.
624 public void readUnlock()
626 // Note we could have a problem here if readUnlock was called without a
627 // prior call to readLock but the specs simply warn users to ensure that
628 // balance by using a finally block:
629 // readLock()
630 // try
631 // {
632 // doSomethingHere
633 // }
634 // finally
635 // {
636 // readUnlock();
637 // }
639 // All that the JDK seems to check for is that you don't call unlock
640 // more times than you've previously called lock, but it doesn't make
641 // sure that the threads calling unlock were the same ones that called lock
643 // FIXME: the reference implementation throws a
644 // javax.swing.text.StateInvariantError here
645 if (numReaders == 0)
646 throw new IllegalStateException("document lock failure");
648 synchronized (documentCV)
650 // If currentWriter is not null, the application code probably had a
651 // writeLock and then tried to obtain a readLock, in which case
652 // numReaders wasn't incremented
653 if (currentWriter == null)
655 numReaders --;
656 if (numReaders == 0 && numWritersWaiting != 0)
657 documentCV.notify();
663 * Removes a piece of content from this <code>Document</code>.
665 * @param offset the start offset of the fragment to be removed
666 * @param length the length of the fragment to be removed
668 * @throws BadLocationException if <code>offset</code> or
669 * <code>offset + length</code> or invalid locations within this
670 * document
672 public void remove(int offset, int length) throws BadLocationException
674 DefaultDocumentEvent event =
675 new DefaultDocumentEvent(offset, length,
676 DocumentEvent.EventType.REMOVE);
678 removeUpdate(event);
680 boolean shouldFire = content.getString(offset, length).length() != 0;
682 writeLock();
683 UndoableEdit temp = content.remove(offset, length);
684 writeUnlock();
686 postRemoveUpdate(event);
688 if (shouldFire)
689 fireRemoveUpdate(event);
693 * Replaces a piece of content in this <code>Document</code> with
694 * another piece of content.
696 * @param offset the start offset of the fragment to be removed
697 * @param length the length of the fragment to be removed
698 * @param text the text to replace the content with
699 * @param attributes the text attributes to assign to the new content
701 * @throws BadLocationException if <code>offset</code> or
702 * <code>offset + length</code> or invalid locations within this
703 * document
705 * @since 1.4
707 public void replace(int offset, int length, String text,
708 AttributeSet attributes)
709 throws BadLocationException
711 remove(offset, length);
712 insertString(offset, text, attributes);
716 * Adds a <code>DocumentListener</code> object to this document.
718 * @param listener the listener to add
720 public void addDocumentListener(DocumentListener listener)
722 listenerList.add(DocumentListener.class, listener);
726 * Removes a <code>DocumentListener</code> object from this document.
728 * @param listener the listener to remove
730 public void removeDocumentListener(DocumentListener listener)
732 listenerList.remove(DocumentListener.class, listener);
736 * Returns all registered <code>DocumentListener</code>s.
738 * @return all registered <code>DocumentListener</code>s
740 public DocumentListener[] getDocumentListeners()
742 return (DocumentListener[]) getListeners(DocumentListener.class);
746 * Adds an {@link UndoableEditListener} to this <code>Document</code>.
748 * @param listener the listener to add
750 public void addUndoableEditListener(UndoableEditListener listener)
752 listenerList.add(UndoableEditListener.class, listener);
756 * Removes an {@link UndoableEditListener} from this <code>Document</code>.
758 * @param listener the listener to remove
760 public void removeUndoableEditListener(UndoableEditListener listener)
762 listenerList.remove(UndoableEditListener.class, listener);
766 * Returns all registered {@link UndoableEditListener}s.
768 * @return all registered {@link UndoableEditListener}s
770 public UndoableEditListener[] getUndoableEditListeners()
772 return (UndoableEditListener[]) getListeners(UndoableEditListener.class);
776 * Called before some content gets removed from this <code>Document</code>.
777 * The default implementation does nothing but may be overridden by
778 * subclasses to modify the <code>Document</code> structure in response
779 * to a remove request. The method is executed within a write lock.
781 * @param chng the <code>DefaultDocumentEvent</code> describing the change
783 protected void removeUpdate(DefaultDocumentEvent chng)
785 // Do nothing here. Subclasses may wish to override this.
789 * Called to render this <code>Document</code> visually. It obtains a read
790 * lock, ensuring that no changes will be made to the <code>document</code>
791 * during the rendering process. It then calls the {@link Runnable#run()}
792 * method on <code>runnable</code>. This method <em>must not</em> attempt
793 * to modifiy the <code>Document</code>, since a deadlock will occur if it
794 * tries to obtain a write lock. When the {@link Runnable#run()} method
795 * completes (either naturally or by throwing an exception), the read lock
796 * is released. Note that there is nothing in this method related to
797 * the actual rendering. It could be used to execute arbitrary code within
798 * a read lock.
800 * @param runnable the {@link Runnable} to execute
802 public void render(Runnable runnable)
804 readLock();
807 runnable.run();
809 finally
811 readUnlock();
816 * Sets the asynchronous loading priority for this <code>Document</code>.
817 * A value of <code>-1</code> indicates that this <code>Document</code>
818 * should be loaded synchronously.
820 * @param p the asynchronous loading priority to set
822 public void setAsynchronousLoadPriority(int p)
824 // TODO: Implement this properly.
828 * Sets the properties of this <code>Document</code>.
830 * @param p the document properties to set
832 public void setDocumentProperties(Dictionary p)
834 // FIXME: make me thread-safe
835 properties = p;
839 * Blocks until a write lock can be obtained. Must wait if there are
840 * readers currently reading or another thread is currently writing.
842 protected void writeLock()
844 if (currentWriter!= null && currentWriter.equals(Thread.currentThread()))
845 return;
846 synchronized (documentCV)
848 numWritersWaiting++;
849 while (numReaders > 0)
853 documentCV.wait();
855 catch (InterruptedException ie)
857 throw new Error("interruped while trying to obtain write lock");
860 numWritersWaiting --;
861 currentWriter = Thread.currentThread();
866 * Releases the write lock. This allows waiting readers or writers to
867 * obtain the lock.
869 protected void writeUnlock()
871 synchronized (documentCV)
873 if (Thread.currentThread().equals(currentWriter))
875 currentWriter = null;
876 documentCV.notifyAll();
882 * Returns the currently installed {@link DocumentFilter} for this
883 * <code>Document</code>.
885 * @return the currently installed {@link DocumentFilter} for this
886 * <code>Document</code>
888 * @since 1.4
890 public DocumentFilter getDocumentFilter()
892 return documentFilter;
896 * Sets the {@link DocumentFilter} for this <code>Document</code>.
898 * @param filter the <code>DocumentFilter</code> to set
900 * @since 1.4
902 public void setDocumentFilter(DocumentFilter filter)
904 this.documentFilter = filter;
908 * Dumps diagnostic information to the specified <code>PrintStream</code>.
910 * @param out the stream to write the diagnostic information to
912 public void dump(PrintStream out)
914 ((AbstractElement) getDefaultRootElement()).dump(out, 0);
918 * Defines a set of methods for managing text attributes for one or more
919 * <code>Document</code>s.
921 * Replicating {@link AttributeSet}s throughout a <code>Document</code> can
922 * be very expensive. Implementations of this interface are intended to
923 * provide intelligent management of <code>AttributeSet</code>s, eliminating
924 * costly duplication.
926 * @see StyleContext
928 public interface AttributeContext
931 * Returns an {@link AttributeSet} that contains the attributes
932 * of <code>old</code> plus the new attribute specified by
933 * <code>name</code> and <code>value</code>.
935 * @param old the attribute set to be merged with the new attribute
936 * @param name the name of the attribute to be added
937 * @param value the value of the attribute to be added
939 * @return the old attributes plus the new attribute
941 AttributeSet addAttribute(AttributeSet old, Object name, Object value);
944 * Returns an {@link AttributeSet} that contains the attributes
945 * of <code>old</code> plus the new attributes in <code>attributes</code>.
947 * @param old the set of attributes where to add the new attributes
948 * @param attributes the attributes to be added
950 * @return an {@link AttributeSet} that contains the attributes
951 * of <code>old</code> plus the new attributes in
952 * <code>attributes</code>
954 AttributeSet addAttributes(AttributeSet old, AttributeSet attributes);
957 * Returns an empty {@link AttributeSet}.
959 * @return an empty {@link AttributeSet}
961 AttributeSet getEmptySet();
964 * Called to indicate that the attributes in <code>attributes</code> are
965 * no longer used.
967 * @param attributes the attributes are no longer used
969 void reclaim(AttributeSet attributes);
972 * Returns a {@link AttributeSet} that has the attribute with the specified
973 * <code>name</code> removed from <code>old</code>.
975 * @param old the attribute set from which an attribute is removed
976 * @param name the name of the attribute to be removed
978 * @return the attributes of <code>old</code> minus the attribute
979 * specified by <code>name</code>
981 AttributeSet removeAttribute(AttributeSet old, Object name);
984 * Removes all attributes in <code>attributes</code> from <code>old</code>
985 * and returns the resulting <code>AttributeSet</code>.
987 * @param old the set of attributes from which to remove attributes
988 * @param attributes the attributes to be removed from <code>old</code>
990 * @return the attributes of <code>old</code> minus the attributes in
991 * <code>attributes</code>
993 AttributeSet removeAttributes(AttributeSet old, AttributeSet attributes);
996 * Removes all attributes specified by <code>names</code> from
997 * <code>old</code> and returns the resulting <code>AttributeSet</code>.
999 * @param old the set of attributes from which to remove attributes
1000 * @param names the names of the attributes to be removed from
1001 * <code>old</code>
1003 * @return the attributes of <code>old</code> minus the attributes in
1004 * <code>attributes</code>
1006 AttributeSet removeAttributes(AttributeSet old, Enumeration names);
1010 * A sequence of data that can be edited. This is were the actual content
1011 * in <code>AbstractDocument</code>'s is stored.
1013 public interface Content
1016 * Creates a {@link Position} that keeps track of the location at
1017 * <code>offset</code>.
1019 * @return a {@link Position} that keeps track of the location at
1020 * <code>offset</code>.
1022 * @throw BadLocationException if <code>offset</code> is not a valid
1023 * location in this <code>Content</code> model
1025 Position createPosition(int offset) throws BadLocationException;
1028 * Returns the length of the content.
1030 * @return the length of the content
1032 int length();
1035 * Inserts a string into the content model.
1037 * @param where the offset at which to insert the string
1038 * @param str the string to be inserted
1040 * @return an <code>UndoableEdit</code> or <code>null</code> if undo is
1041 * not supported by this <code>Content</code> model
1043 * @throws BadLocationException if <code>where</code> is not a valid
1044 * location in this <code>Content</code> model
1046 UndoableEdit insertString(int where, String str)
1047 throws BadLocationException;
1050 * Removes a piece of content from the content model.
1052 * @param where the offset at which to remove content
1053 * @param nitems the number of characters to be removed
1055 * @return an <code>UndoableEdit</code> or <code>null</code> if undo is
1056 * not supported by this <code>Content</code> model
1058 * @throws BadLocationException if <code>where</code> is not a valid
1059 * location in this <code>Content</code> model
1061 UndoableEdit remove(int where, int nitems) throws BadLocationException;
1064 * Returns a piece of content.
1066 * @param where the start offset of the requested fragment
1067 * @param len the length of the requested fragment
1069 * @return the requested fragment
1070 * @throws BadLocationException if <code>offset</code> or
1071 * <code>offset + len</code>is not a valid
1072 * location in this <code>Content</code> model
1074 String getString(int where, int len) throws BadLocationException;
1077 * Fetches a piece of content and stores it in <code>txt</code>.
1079 * @param where the start offset of the requested fragment
1080 * @param len the length of the requested fragment
1081 * @param txt the <code>Segment</code> where to fragment is stored into
1083 * @throws BadLocationException if <code>offset</code> or
1084 * <code>offset + len</code>is not a valid
1085 * location in this <code>Content</code> model
1087 void getChars(int where, int len, Segment txt) throws BadLocationException;
1091 * An abstract base implementation of the {@link Element} interface.
1093 public abstract class AbstractElement
1094 implements Element, MutableAttributeSet, TreeNode, Serializable
1096 /** The serialization UID (compatible with JDK1.5). */
1097 private static final long serialVersionUID = 1712240033321461704L;
1099 /** The number of characters that this Element spans. */
1100 int count;
1102 /** The starting offset of this Element. */
1103 int offset;
1105 /** The attributes of this Element. */
1106 AttributeSet attributes;
1108 /** The parent element. */
1109 Element element_parent;
1111 /** The parent in the TreeNode interface. */
1112 TreeNode tree_parent;
1114 /** The children of this element. */
1115 Vector tree_children;
1118 * Creates a new instance of <code>AbstractElement</code> with a
1119 * specified parent <code>Element</code> and <code>AttributeSet</code>.
1121 * @param p the parent of this <code>AbstractElement</code>
1122 * @param s the attributes to be assigned to this
1123 * <code>AbstractElement</code>
1125 public AbstractElement(Element p, AttributeSet s)
1127 element_parent = p;
1128 AttributeContext ctx = getAttributeContext();
1129 attributes = ctx.getEmptySet();
1130 if (s != null)
1131 attributes = ctx.addAttributes(attributes, s);
1135 * Returns the child nodes of this <code>Element</code> as an
1136 * <code>Enumeration</code> of {@link TreeNode}s.
1138 * @return the child nodes of this <code>Element</code> as an
1139 * <code>Enumeration</code> of {@link TreeNode}s
1141 public abstract Enumeration children();
1144 * Returns <code>true</code> if this <code>AbstractElement</code>
1145 * allows children.
1147 * @return <code>true</code> if this <code>AbstractElement</code>
1148 * allows children
1150 public abstract boolean getAllowsChildren();
1153 * Returns the child of this <code>AbstractElement</code> at
1154 * <code>index</code>.
1156 * @param index the position in the child list of the child element to
1157 * be returned
1159 * @return the child of this <code>AbstractElement</code> at
1160 * <code>index</code>
1162 public TreeNode getChildAt(int index)
1164 return (TreeNode) tree_children.get(index);
1168 * Returns the number of children of this <code>AbstractElement</code>.
1170 * @return the number of children of this <code>AbstractElement</code>
1172 public int getChildCount()
1174 return tree_children.size();
1178 * Returns the index of a given child <code>TreeNode</code> or
1179 * <code>-1</code> if <code>node</code> is not a child of this
1180 * <code>AbstractElement</code>.
1182 * @param node the node for which the index is requested
1184 * @return the index of a given child <code>TreeNode</code> or
1185 * <code>-1</code> if <code>node</code> is not a child of this
1186 * <code>AbstractElement</code>
1188 public int getIndex(TreeNode node)
1190 return tree_children.indexOf(node);
1194 * Returns the parent <code>TreeNode</code> of this
1195 * <code>AbstractElement</code> or <code>null</code> if this element
1196 * has no parent.
1198 * @return the parent <code>TreeNode</code> of this
1199 * <code>AbstractElement</code> or <code>null</code> if this
1200 * element has no parent
1202 public TreeNode getParent()
1204 return tree_parent;
1208 * Returns <code>true</code> if this <code>AbstractElement</code> is a
1209 * leaf element, <code>false</code> otherwise.
1211 * @return <code>true</code> if this <code>AbstractElement</code> is a
1212 * leaf element, <code>false</code> otherwise
1214 public abstract boolean isLeaf();
1217 * Adds an attribute to this element.
1219 * @param name the name of the attribute to be added
1220 * @param value the value of the attribute to be added
1222 public void addAttribute(Object name, Object value)
1224 attributes = getAttributeContext().addAttribute(attributes, name, value);
1228 * Adds a set of attributes to this element.
1230 * @param attrs the attributes to be added to this element
1232 public void addAttributes(AttributeSet attrs)
1234 attributes = getAttributeContext().addAttributes(attributes, attrs);
1238 * Removes an attribute from this element.
1240 * @param name the name of the attribute to be removed
1242 public void removeAttribute(Object name)
1244 attributes = getAttributeContext().removeAttribute(attributes, name);
1248 * Removes a set of attributes from this element.
1250 * @param attrs the attributes to be removed
1252 public void removeAttributes(AttributeSet attrs)
1254 attributes = getAttributeContext().removeAttributes(attributes, attrs);
1258 * Removes a set of attribute from this element.
1260 * @param names the names of the attributes to be removed
1262 public void removeAttributes(Enumeration names)
1264 attributes = getAttributeContext().removeAttributes(attributes, names);
1268 * Sets the parent attribute set against which the element can resolve
1269 * attributes that are not defined in itself.
1271 * @param parent the resolve parent to set
1273 public void setResolveParent(AttributeSet parent)
1275 attributes = getAttributeContext().addAttribute(attributes,
1276 ResolveAttribute,
1277 parent);
1281 * Returns <code>true</code> if this element contains the specified
1282 * attribute.
1284 * @param name the name of the attribute to check
1285 * @param value the value of the attribute to check
1287 * @return <code>true</code> if this element contains the specified
1288 * attribute
1290 public boolean containsAttribute(Object name, Object value)
1292 return attributes.containsAttribute(name, value);
1296 * Returns <code>true</code> if this element contains all of the
1297 * specified attributes.
1299 * @param attrs the attributes to check
1301 * @return <code>true</code> if this element contains all of the
1302 * specified attributes
1304 public boolean containsAttributes(AttributeSet attrs)
1306 return attributes.containsAttributes(attrs);
1310 * Returns a copy of the attributes of this element.
1312 * @return a copy of the attributes of this element
1314 public AttributeSet copyAttributes()
1316 return attributes.copyAttributes();
1320 * Returns the attribute value with the specified key. If this attribute
1321 * is not defined in this element and this element has a resolving
1322 * parent, the search goes upward to the resolve parent chain.
1324 * @param key the key of the requested attribute
1326 * @return the attribute value for <code>key</code> of <code>null</code>
1327 * if <code>key</code> is not found locally and cannot be resolved
1328 * in this element's resolve parents
1330 public Object getAttribute(Object key)
1332 Object result = attributes.getAttribute(key);
1333 if (result == null && element_parent != null)
1335 AttributeSet parentSet = element_parent.getAttributes();
1336 if (parentSet != null)
1337 result = parentSet.getAttribute(key);
1339 return result;
1343 * Returns the number of defined attributes in this element.
1345 * @return the number of defined attributes in this element
1347 public int getAttributeCount()
1349 return attributes.getAttributeCount();
1353 * Returns the names of the attributes of this element.
1355 * @return the names of the attributes of this element
1357 public Enumeration getAttributeNames()
1359 return attributes.getAttributeNames();
1363 * Returns the resolve parent of this element.
1364 * This is taken from the AttributeSet, but if this is null,
1365 * this method instead returns the Element's parent's
1366 * AttributeSet
1368 * @return the resolve parent of this element
1370 * @see #setResolveParent(AttributeSet)
1372 public AttributeSet getResolveParent()
1374 if (attributes.getResolveParent() != null)
1375 return attributes.getResolveParent();
1376 return element_parent.getAttributes();
1380 * Returns <code>true</code> if an attribute with the specified name
1381 * is defined in this element, <code>false</code> otherwise.
1383 * @param attrName the name of the requested attributes
1385 * @return <code>true</code> if an attribute with the specified name
1386 * is defined in this element, <code>false</code> otherwise
1388 public boolean isDefined(Object attrName)
1390 return attributes.isDefined(attrName);
1394 * Returns <code>true</code> if the specified <code>AttributeSet</code>
1395 * is equal to this element's <code>AttributeSet</code>, <code>false</code>
1396 * otherwise.
1398 * @param attrs the attributes to compare this element to
1400 * @return <code>true</code> if the specified <code>AttributeSet</code>
1401 * is equal to this element's <code>AttributeSet</code>,
1402 * <code>false</code> otherwise
1404 public boolean isEqual(AttributeSet attrs)
1406 return attributes.isEqual(attrs);
1410 * Returns the attributes of this element.
1412 * @return the attributes of this element
1414 public AttributeSet getAttributes()
1416 return this;
1420 * Returns the {@link Document} to which this element belongs.
1422 * @return the {@link Document} to which this element belongs
1424 public Document getDocument()
1426 return AbstractDocument.this;
1430 * Returns the child element at the specified <code>index</code>.
1432 * @param index the index of the requested child element
1434 * @return the requested element
1436 public abstract Element getElement(int index);
1439 * Returns the name of this element.
1441 * @return the name of this element
1443 public String getName()
1445 return (String) getAttribute(NameAttribute);
1449 * Returns the parent element of this element.
1451 * @return the parent element of this element
1453 public Element getParentElement()
1455 return element_parent;
1459 * Returns the offset inside the document model that is after the last
1460 * character of this element.
1462 * @return the offset inside the document model that is after the last
1463 * character of this element
1465 public abstract int getEndOffset();
1468 * Returns the number of child elements of this element.
1470 * @return the number of child elements of this element
1472 public abstract int getElementCount();
1475 * Returns the index of the child element that spans the specified
1476 * offset in the document model.
1478 * @param offset the offset for which the responsible element is searched
1480 * @return the index of the child element that spans the specified
1481 * offset in the document model
1483 public abstract int getElementIndex(int offset);
1486 * Returns the start offset if this element inside the document model.
1488 * @return the start offset if this element inside the document model
1490 public abstract int getStartOffset();
1493 * Prints diagnostic output to the specified stream.
1495 * @param stream the stream to write to
1496 * @param indent the indentation level
1498 public void dump(PrintStream stream, int indent)
1500 StringBuffer b = new StringBuffer();
1501 for (int i = 0; i < indent; ++i)
1502 b.append(' ');
1503 b.append('<');
1504 b.append(getName());
1505 // Dump attributes if there are any.
1506 if (getAttributeCount() > 0)
1508 b.append('\n');
1509 Enumeration attNames = getAttributeNames();
1510 while (attNames.hasMoreElements())
1512 for (int i = 0; i < indent + 2; ++i)
1513 b.append(' ');
1514 Object attName = attNames.nextElement();
1515 b.append(attName);
1516 b.append('=');
1517 Object attribute = getAttribute(attName);
1518 b.append(attribute);
1519 b.append('\n');
1522 b.append(">\n");
1524 // Dump element content for leaf elements.
1525 if (isLeaf())
1527 for (int i = 0; i < indent + 2; ++i)
1528 b.append(' ');
1529 int start = getStartOffset();
1530 int end = getEndOffset();
1531 b.append('[');
1532 b.append(start);
1533 b.append(',');
1534 b.append(end);
1535 b.append("][");
1538 b.append(getDocument().getText(start, end - start));
1540 catch (BadLocationException ex)
1542 AssertionError err = new AssertionError("BadLocationException "
1543 + "must not be thrown "
1544 + "here.");
1545 err.initCause(ex);
1546 throw err;
1548 b.append("]\n");
1550 stream.print(b.toString());
1552 // Dump child elements if any.
1553 int count = getElementCount();
1554 for (int i = 0; i < count; ++i)
1556 Element el = getElement(i);
1557 if (el instanceof AbstractElement)
1558 ((AbstractElement) el).dump(stream, indent + 2);
1564 * An implementation of {@link Element} to represent composite
1565 * <code>Element</code>s that contain other <code>Element</code>s.
1567 public class BranchElement extends AbstractElement
1569 /** The serialization UID (compatible with JDK1.5). */
1570 private static final long serialVersionUID = -6037216547466333183L;
1572 /** The child elements of this BranchElement. */
1573 private Element[] children = new Element[0];
1576 * Creates a new <code>BranchElement</code> with the specified
1577 * parent and attributes.
1579 * @param parent the parent element of this <code>BranchElement</code>
1580 * @param attributes the attributes to set on this
1581 * <code>BranchElement</code>
1583 public BranchElement(Element parent, AttributeSet attributes)
1585 super(parent, attributes);
1589 * Returns the children of this <code>BranchElement</code>.
1591 * @return the children of this <code>BranchElement</code>
1593 public Enumeration children()
1595 if (children.length == 0)
1596 return null;
1598 Vector tmp = new Vector();
1600 for (int index = 0; index < children.length; ++index)
1601 tmp.add(children[index]);
1603 return tmp.elements();
1607 * Returns <code>true</code> since <code>BranchElements</code> allow
1608 * child elements.
1610 * @return <code>true</code> since <code>BranchElements</code> allow
1611 * child elements
1613 public boolean getAllowsChildren()
1615 return true;
1619 * Returns the child element at the specified <code>index</code>.
1621 * @param index the index of the requested child element
1623 * @return the requested element
1625 public Element getElement(int index)
1627 if (index < 0 || index >= children.length)
1628 return null;
1630 return children[index];
1634 * Returns the number of child elements of this element.
1636 * @return the number of child elements of this element
1638 public int getElementCount()
1640 return children.length;
1644 * Returns the index of the child element that spans the specified
1645 * offset in the document model.
1647 * @param offset the offset for which the responsible element is searched
1649 * @return the index of the child element that spans the specified
1650 * offset in the document model
1652 public int getElementIndex(int offset)
1654 // If offset is less than the start offset of our first child,
1655 // return 0
1656 if (offset < getStartOffset())
1657 return 0;
1659 // XXX: There is surely a better algorithm
1660 // as beginning from first element each time.
1661 for (int index = 0; index < children.length - 1; ++index)
1663 Element elem = children[index];
1665 if ((elem.getStartOffset() <= offset)
1666 && (offset < elem.getEndOffset()))
1667 return index;
1668 // If the next element's start offset is greater than offset
1669 // then we have to return the closest Element, since no Elements
1670 // will contain the offset
1671 if (children[index + 1].getStartOffset() > offset)
1673 if ((offset - elem.getEndOffset()) > (children[index + 1].getStartOffset() - offset))
1674 return index + 1;
1675 else
1676 return index;
1680 // If offset is greater than the index of the last element, return
1681 // the index of the last element.
1682 return getElementCount() - 1;
1686 * Returns the offset inside the document model that is after the last
1687 * character of this element.
1688 * This is the end offset of the last child element. If this element
1689 * has no children, this method throws a <code>NullPointerException</code>.
1691 * @return the offset inside the document model that is after the last
1692 * character of this element
1694 * @throws NullPointerException if this branch element has no children
1696 public int getEndOffset()
1698 if (getElementCount() == 0)
1699 throw new NullPointerException("This BranchElement has no children.");
1700 return children[children.length - 1].getEndOffset();
1704 * Returns the name of this element. This is {@link #ParagraphElementName}
1705 * in this case.
1707 * @return the name of this element
1709 public String getName()
1711 return ParagraphElementName;
1715 * Returns the start offset of this element inside the document model.
1716 * This is the start offset of the first child element. If this element
1717 * has no children, this method throws a <code>NullPointerException</code>.
1719 * @return the start offset of this element inside the document model
1721 * @throws NullPointerException if this branch element has no children
1723 public int getStartOffset()
1725 if (getElementCount() == 0)
1726 throw new NullPointerException("This BranchElement has no children.");
1727 return children[0].getStartOffset();
1731 * Returns <code>false</code> since <code>BranchElement</code> are no
1732 * leafes.
1734 * @return <code>false</code> since <code>BranchElement</code> are no
1735 * leafes
1737 public boolean isLeaf()
1739 return false;
1743 * Returns the <code>Element</code> at the specified <code>Document</code>
1744 * offset.
1746 * @return the <code>Element</code> at the specified <code>Document</code>
1747 * offset
1749 * @see #getElementIndex(int)
1751 public Element positionToElement(int position)
1753 // XXX: There is surely a better algorithm
1754 // as beginning from first element each time.
1755 for (int index = 0; index < children.length; ++index)
1757 Element elem = children[index];
1759 if ((elem.getStartOffset() <= position)
1760 && (position < elem.getEndOffset()))
1761 return elem;
1764 return null;
1768 * Replaces a set of child elements with a new set of child elemens.
1770 * @param offset the start index of the elements to be removed
1771 * @param length the number of elements to be removed
1772 * @param elements the new elements to be inserted
1774 public void replace(int offset, int length, Element[] elements)
1776 Element[] target = new Element[children.length - length
1777 + elements.length];
1778 System.arraycopy(children, 0, target, 0, offset);
1779 System.arraycopy(elements, 0, target, offset, elements.length);
1780 System.arraycopy(children, offset + length, target,
1781 offset + elements.length,
1782 children.length - offset - length);
1783 children = target;
1787 * Returns a string representation of this element.
1789 * @return a string representation of this element
1791 public String toString()
1793 return ("BranchElement(" + getName() + ") "
1794 + getStartOffset() + "," + getEndOffset() + "\n");
1799 * Stores the changes when a <code>Document</code> is beeing modified.
1801 public class DefaultDocumentEvent extends CompoundEdit
1802 implements DocumentEvent
1804 /** The serialization UID (compatible with JDK1.5). */
1805 private static final long serialVersionUID = 5230037221564563284L;
1807 /** The starting offset of the change. */
1808 private int offset;
1810 /** The length of the change. */
1811 private int length;
1813 /** The type of change. */
1814 private DocumentEvent.EventType type;
1817 * Maps <code>Element</code> to their change records.
1819 Hashtable changes;
1822 * Indicates if this event has been modified or not. This is used to
1823 * determine if this event is thrown.
1825 boolean modified;
1828 * Creates a new <code>DefaultDocumentEvent</code>.
1830 * @param offset the starting offset of the change
1831 * @param length the length of the change
1832 * @param type the type of change
1834 public DefaultDocumentEvent(int offset, int length,
1835 DocumentEvent.EventType type)
1837 this.offset = offset;
1838 this.length = length;
1839 this.type = type;
1840 changes = new Hashtable();
1841 modified = false;
1845 * Adds an UndoableEdit to this <code>DocumentEvent</code>. If this
1846 * edit is an instance of {@link ElementEdit}, then this record can
1847 * later be fetched by calling {@link #getChange}.
1849 * @param edit the undoable edit to add
1851 public boolean addEdit(UndoableEdit edit)
1853 // XXX - Fully qualify ElementChange to work around gcj bug #2499.
1854 if (edit instanceof DocumentEvent.ElementChange)
1856 modified = true;
1857 DocumentEvent.ElementChange elEdit =
1858 (DocumentEvent.ElementChange) edit;
1859 changes.put(elEdit.getElement(), elEdit);
1861 return super.addEdit(edit);
1865 * Returns the document that has been modified.
1867 * @return the document that has been modified
1869 public Document getDocument()
1871 return AbstractDocument.this;
1875 * Returns the length of the modification.
1877 * @return the length of the modification
1879 public int getLength()
1881 return length;
1885 * Returns the start offset of the modification.
1887 * @return the start offset of the modification
1889 public int getOffset()
1891 return offset;
1895 * Returns the type of the modification.
1897 * @return the type of the modification
1899 public DocumentEvent.EventType getType()
1901 return type;
1905 * Returns the changes for an element.
1907 * @param elem the element for which the changes are requested
1909 * @return the changes for <code>elem</code> or <code>null</code> if
1910 * <code>elem</code> has not been changed
1912 public DocumentEvent.ElementChange getChange(Element elem)
1914 // XXX - Fully qualify ElementChange to work around gcj bug #2499.
1915 return (DocumentEvent.ElementChange) changes.get(elem);
1919 * Returns a String description of the change event. This returns the
1920 * toString method of the Vector of edits.
1922 public String toString()
1924 return edits.toString();
1929 * An implementation of {@link DocumentEvent.ElementChange} to be added
1930 * to {@link DefaultDocumentEvent}s.
1932 public static class ElementEdit extends AbstractUndoableEdit
1933 implements DocumentEvent.ElementChange
1935 /** The serial version UID of ElementEdit. */
1936 private static final long serialVersionUID = -1216620962142928304L;
1939 * The changed element.
1941 private Element elem;
1944 * The index of the change.
1946 private int index;
1949 * The removed elements.
1951 private Element[] removed;
1954 * The added elements.
1956 private Element[] added;
1959 * Creates a new <code>ElementEdit</code>.
1961 * @param elem the changed element
1962 * @param index the index of the change
1963 * @param removed the removed elements
1964 * @param added the added elements
1966 public ElementEdit(Element elem, int index,
1967 Element[] removed, Element[] added)
1969 this.elem = elem;
1970 this.index = index;
1971 this.removed = removed;
1972 this.added = added;
1976 * Returns the added elements.
1978 * @return the added elements
1980 public Element[] getChildrenAdded()
1982 return added;
1986 * Returns the removed elements.
1988 * @return the removed elements
1990 public Element[] getChildrenRemoved()
1992 return removed;
1996 * Returns the changed element.
1998 * @return the changed element
2000 public Element getElement()
2002 return elem;
2006 * Returns the index of the change.
2008 * @return the index of the change
2010 public int getIndex()
2012 return index;
2017 * An implementation of {@link Element} that represents a leaf in the
2018 * document structure. This is used to actually store content.
2020 public class LeafElement extends AbstractElement
2022 /** The serialization UID (compatible with JDK1.5). */
2023 private static final long serialVersionUID = -8906306331347768017L;
2025 /** Manages the start offset of this element. */
2026 Position startPos;
2028 /** Manages the end offset of this element. */
2029 Position endPos;
2032 * Creates a new <code>LeafElement</code>.
2034 * @param parent the parent of this <code>LeafElement</code>
2035 * @param attributes the attributes to be set
2036 * @param start the start index of this element inside the document model
2037 * @param end the end index of this element inside the document model
2039 public LeafElement(Element parent, AttributeSet attributes, int start,
2040 int end)
2042 super(parent, attributes);
2046 if (parent != null)
2048 startPos = parent.getDocument().createPosition(start);
2049 endPos = parent.getDocument().createPosition(end);
2051 else
2053 startPos = createPosition(start);
2054 endPos = createPosition(end);
2057 catch (BadLocationException ex)
2059 AssertionError as;
2060 as = new AssertionError("BadLocationException thrown "
2061 + "here. start=" + start
2062 + ", end=" + end
2063 + ", length=" + getLength());
2064 as.initCause(ex);
2065 throw as;
2071 * Returns <code>null</code> since <code>LeafElement</code>s cannot have
2072 * children.
2074 * @return <code>null</code> since <code>LeafElement</code>s cannot have
2075 * children
2077 public Enumeration children()
2079 return null;
2083 * Returns <code>false</code> since <code>LeafElement</code>s cannot have
2084 * children.
2086 * @return <code>false</code> since <code>LeafElement</code>s cannot have
2087 * children
2089 public boolean getAllowsChildren()
2091 return false;
2095 * Returns <code>null</code> since <code>LeafElement</code>s cannot have
2096 * children.
2098 * @return <code>null</code> since <code>LeafElement</code>s cannot have
2099 * children
2101 public Element getElement(int index)
2103 return null;
2107 * Returns <code>0</code> since <code>LeafElement</code>s cannot have
2108 * children.
2110 * @return <code>0</code> since <code>LeafElement</code>s cannot have
2111 * children
2113 public int getElementCount()
2115 return 0;
2119 * Returns <code>-1</code> since <code>LeafElement</code>s cannot have
2120 * children.
2122 * @return <code>-1</code> since <code>LeafElement</code>s cannot have
2123 * children
2125 public int getElementIndex(int offset)
2127 return -1;
2131 * Returns the end offset of this <code>Element</code> inside the
2132 * document.
2134 * @return the end offset of this <code>Element</code> inside the
2135 * document
2137 public int getEndOffset()
2139 return endPos.getOffset();
2143 * Returns the name of this <code>Element</code>. This is
2144 * {@link #ContentElementName} in this case.
2146 * @return the name of this <code>Element</code>
2148 public String getName()
2150 String name = super.getName();
2151 if (name == null)
2152 name = ContentElementName;
2153 return name;
2157 * Returns the start offset of this <code>Element</code> inside the
2158 * document.
2160 * @return the start offset of this <code>Element</code> inside the
2161 * document
2163 public int getStartOffset()
2165 return startPos.getOffset();
2169 * Returns <code>true</code>.
2171 * @return <code>true</code>
2173 public boolean isLeaf()
2175 return true;
2179 * Returns a string representation of this <code>Element</code>.
2181 * @return a string representation of this <code>Element</code>
2183 public String toString()
2185 return ("LeafElement(" + getName() + ") "
2186 + getStartOffset() + "," + getEndOffset() + "\n");