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)
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., 59 Temple Place, Suite 330, Boston, MA
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
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
.Vector
;
48 import javax
.swing
.event
.DocumentEvent
;
49 import javax
.swing
.event
.DocumentListener
;
50 import javax
.swing
.event
.EventListenerList
;
51 import javax
.swing
.event
.UndoableEditEvent
;
52 import javax
.swing
.event
.UndoableEditListener
;
53 import javax
.swing
.tree
.TreeNode
;
54 import javax
.swing
.undo
.AbstractUndoableEdit
;
55 import javax
.swing
.undo
.CompoundEdit
;
56 import javax
.swing
.undo
.UndoableEdit
;
58 public abstract class AbstractDocument
59 implements Document
, Serializable
61 private static final long serialVersionUID
= -116069779446114664L;
63 protected static final String BAD_LOCATION
= "document location failure";
65 public static final String BidiElementName
= "bidi level";
66 public static final String ContentElementName
= "content";
67 public static final String ParagraphElementName
= "paragraph";
68 public static final String SectionElementName
= "section";
69 public static final String ElementNameAttribute
= "$ename";
72 AttributeContext context
;
73 DocumentFilter documentFilter
;
75 protected EventListenerList listenerList
= new EventListenerList();
77 protected AbstractDocument(Content doc
)
79 this(doc
, StyleContext
.getDefaultStyleContext());
82 protected AbstractDocument(Content doc
, AttributeContext ctx
)
88 // These still need to be implemented by a derived class:
89 public abstract Element
getParagraphElement(int pos
);
91 public abstract Element
getDefaultRootElement();
93 protected Element
createBranchElement(Element parent
,
94 AttributeSet attributes
)
96 return new BranchElement(parent
, attributes
);
99 protected Element
createLeafElement(Element parent
, AttributeSet attributes
,
102 return new LeafElement(parent
, attributes
, start
, end
);
105 public Position
createPosition(final int offset
) throws BadLocationException
107 if (offset
< 0 || offset
> getLength())
108 throw new BadLocationException(getText(0, getLength()), offset
);
110 return new Position()
112 public int getOffset()
119 protected void fireChangedUpdate(DocumentEvent event
)
121 DocumentListener
[] listeners
= getDocumentListeners();
123 for (int index
= 0; index
< listeners
.length
; ++index
)
124 listeners
[index
].changedUpdate(event
);
127 protected void fireInsertUpdate(DocumentEvent event
)
129 DocumentListener
[] listeners
= getDocumentListeners();
131 for (int index
= 0; index
< listeners
.length
; ++index
)
132 listeners
[index
].insertUpdate(event
);
135 protected void fireRemoveUpdate(DocumentEvent event
)
137 DocumentListener
[] listeners
= getDocumentListeners();
139 for (int index
= 0; index
< listeners
.length
; ++index
)
140 listeners
[index
].removeUpdate(event
);
143 protected void fireUndoableEditUpdate(UndoableEditEvent event
)
145 UndoableEditListener
[] listeners
= getUndoableEditListeners();
147 for (int index
= 0; index
< listeners
.length
; ++index
)
148 listeners
[index
].undoableEditHappened(event
);
151 public int getAsynchronousLoadPriority()
156 protected AttributeContext
getAttributeContext()
161 public Element
getBidiRootElement()
166 protected Content
getContent()
171 protected Thread
getCurrentWriter()
176 public Dictionary
getDocumentProperties()
181 public Position
getEndPosition()
183 return new Position()
185 public int getOffset()
192 public int getLength()
194 return content
.length() - 1;
197 public EventListener
[] getListeners(Class listenerType
)
199 return listenerList
.getListeners(listenerType
);
202 public Object
getProperty(Object key
)
207 public Element
[] getRootElements()
209 Element
[] elements
= new Element
[1];
210 elements
[0] = getDefaultRootElement();
214 public Position
getStartPosition()
216 return new Position()
218 public int getOffset()
225 public String
getText(int offset
, int length
) throws BadLocationException
227 return content
.getString(offset
, length
);
230 public void getText(int offset
, int length
, Segment segment
)
231 throws BadLocationException
233 content
.getChars(offset
, length
, segment
);
236 public void insertString(int offset
, String text
, AttributeSet attributes
)
237 throws BadLocationException
239 // Just return when no text to insert was given.
240 if (text
== null || text
.length() == 0)
243 DefaultDocumentEvent event
=
244 new DefaultDocumentEvent(offset
, text
.length(),
245 DocumentEvent
.EventType
.INSERT
);
246 content
.insertString(offset
, text
);
247 insertUpdate(event
, attributes
);
248 fireInsertUpdate(event
);
251 protected void insertUpdate(DefaultDocumentEvent chng
, AttributeSet attr
)
255 protected void postRemoveUpdate(DefaultDocumentEvent chng
)
259 public void putProperty(Object key
, Object value
)
263 public void readLock()
267 public void readUnlock()
271 public void remove(int offset
, int length
) throws BadLocationException
273 DefaultDocumentEvent event
=
274 new DefaultDocumentEvent(offset
, length
,
275 DocumentEvent
.EventType
.REMOVE
);
277 content
.remove(offset
, length
);
278 postRemoveUpdate(event
);
279 fireRemoveUpdate(event
);
283 * Replaces some text in the document.
287 public void replace(int offset
, int length
, String text
,
288 AttributeSet attributes
)
289 throws BadLocationException
291 remove(offset
, length
);
292 insertString(offset
, text
, attributes
);
296 * Adds a <code>DocumentListener</code> object to this document.
298 * @param listener the listener to add
300 public void addDocumentListener(DocumentListener listener
)
302 listenerList
.add(DocumentListener
.class, listener
);
306 * Removes a <code>DocumentListener</code> object from this document.
308 * @param listener the listener to remove
310 public void removeDocumentListener(DocumentListener listener
)
312 listenerList
.remove(DocumentListener
.class, listener
);
316 * Returns add added <code>DocumentListener</code> objects.
318 * @return an array of listeners
320 public DocumentListener
[] getDocumentListeners()
322 return (DocumentListener
[]) getListeners(DocumentListener
.class);
326 * Adds a <code>UndoableEditListener</code> object to this document.
328 * @param listener the listener to add
330 public void addUndoableEditListener(UndoableEditListener listener
)
332 listenerList
.add(UndoableEditListener
.class, listener
);
336 * Removes a <code>UndoableEditListener</code> object from this document.
338 * @param listener the listener to remove
340 public void removeUndoableEditListener(UndoableEditListener listener
)
342 listenerList
.remove(UndoableEditListener
.class, listener
);
346 * Returns add added <code>UndoableEditListener</code> objects.
348 * @return an array of listeners
350 public UndoableEditListener
[] getUndoableEditListeners()
352 return (UndoableEditListener
[]) getListeners(UndoableEditListener
.class);
355 protected void removeUpdate(DefaultDocumentEvent chng
)
359 public void render(Runnable r
)
363 public void setAsynchronousLoadPriority(int p
)
367 public void setDocumentProperties(Dictionary x
)
371 protected void writeLock()
375 protected void writeUnlock()
382 public DocumentFilter
getDocumentFilter()
384 return documentFilter
;
390 public void setDocumentFilter(DocumentFilter filter
)
392 this.documentFilter
= filter
;
395 public void dump(PrintStream out
)
397 ((AbstractElement
) getDefaultRootElement()).dump(out
, 0);
400 public interface AttributeContext
402 AttributeSet
addAttribute(AttributeSet old
, Object name
, Object value
);
404 AttributeSet
addAttributes(AttributeSet old
, AttributeSet attributes
);
406 AttributeSet
getEmptySet();
408 void reclaim(AttributeSet attributes
);
410 AttributeSet
removeAttribute(AttributeSet old
, Object name
);
412 AttributeSet
removeAttributes(AttributeSet old
, AttributeSet attributes
);
414 AttributeSet
removeAttributes(AttributeSet old
, Enumeration names
);
417 public interface Content
419 Position
createPosition(int offset
) throws BadLocationException
;
423 UndoableEdit
insertString(int where
, String str
)
424 throws BadLocationException
;
426 UndoableEdit
remove(int where
, int nitems
) throws BadLocationException
;
428 String
getString(int where
, int len
) throws BadLocationException
;
430 void getChars(int where
, int len
, Segment txt
) throws BadLocationException
;
433 public abstract class AbstractElement
434 implements Element
, MutableAttributeSet
, TreeNode
, Serializable
436 private static final long serialVersionUID
= 1265312733007397733L;
440 AttributeSet attributes
;
442 Element element_parent
;
444 TreeNode tree_parent
;
445 Vector tree_children
;
447 public AbstractElement(Element p
, AttributeSet s
)
453 // TreeNode implementation
455 public abstract Enumeration
children();
457 public abstract boolean getAllowsChildren();
459 public TreeNode
getChildAt(int index
)
461 return (TreeNode
) tree_children
.get(index
);
464 public int getChildCount()
466 return tree_children
.size();
469 public int getIndex(TreeNode node
)
471 return tree_children
.indexOf(node
);
474 public TreeNode
getParent()
479 public abstract boolean isLeaf();
482 // MutableAttributeSet support
484 public void addAttribute(Object name
, Object value
)
486 attributes
= getAttributeContext().addAttribute(attributes
, name
, value
);
489 public void addAttributes(AttributeSet attrs
)
491 attributes
= getAttributeContext().addAttributes(attributes
, attrs
);
494 public void removeAttribute(Object name
)
496 attributes
= getAttributeContext().removeAttribute(attributes
, name
);
499 public void removeAttributes(AttributeSet attrs
)
501 attributes
= getAttributeContext().removeAttributes(attributes
, attrs
);
504 public void removeAttributes(Enumeration names
)
506 attributes
= getAttributeContext().removeAttributes(attributes
, names
);
509 public void setResolveParent(AttributeSet parent
)
511 attributes
= getAttributeContext().addAttribute(attributes
, ResolveAttribute
, parent
);
515 // AttributeSet interface support
517 public boolean containsAttribute(Object name
, Object value
)
519 return attributes
.containsAttribute(name
, value
);
522 public boolean containsAttributes(AttributeSet attrs
)
524 return attributes
.containsAttributes(attrs
);
527 public AttributeSet
copyAttributes()
529 return attributes
.copyAttributes();
532 public Object
getAttribute(Object key
)
534 return attributes
.getAttribute(key
);
537 public int getAttributeCount()
539 return attributes
.getAttributeCount();
542 public Enumeration
getAttributeNames()
544 return attributes
.getAttributeNames();
547 public AttributeSet
getResolveParent()
549 return attributes
.getResolveParent();
552 public boolean isDefined(Object attrName
)
554 return attributes
.isDefined(attrName
);
557 public boolean isEqual(AttributeSet attrs
)
559 return attributes
.isEqual(attrs
);
562 // Element interface support
564 public AttributeSet
getAttributes()
569 public Document
getDocument()
571 return AbstractDocument
.this;
574 public abstract Element
getElement(int index
);
576 public String
getName()
578 return (String
) getAttribute(NameAttribute
);
581 public Element
getParentElement()
583 return element_parent
;
586 public abstract int getEndOffset();
588 public abstract int getElementCount();
590 public abstract int getElementIndex(int offset
);
592 public abstract int getStartOffset();
594 private void dumpElement(PrintStream stream
, String indent
, Element element
)
596 System
.out
.println(indent
+ "<" + element
.getName() +">");
598 if (element
.isLeaf())
600 int start
= element
.getStartOffset();
601 int end
= element
.getEndOffset();
605 text
= getContent().getString(start
, end
- start
);
607 catch (BadLocationException e
)
610 System
.out
.println(indent
+ " ["
617 for (int i
= 0; i
< element
.getElementCount(); ++i
)
618 dumpElement(stream
, indent
+ " ", element
.getElement(i
));
622 public void dump(PrintStream stream
, int indent
)
624 String indentStr
= "";
625 for (int i
= 0; i
< indent
; ++i
)
627 dumpElement(stream
, indentStr
, this);
631 public class BranchElement
extends AbstractElement
633 private static final long serialVersionUID
= -8595176318868717313L;
635 private Element
[] children
= new Element
[0];
637 public BranchElement(Element parent
, AttributeSet attributes
)
639 super(parent
, attributes
);
642 public Enumeration
children()
644 if (children
.length
== 0)
647 Vector tmp
= new Vector();
649 for (int index
= 0; index
< children
.length
; ++index
)
650 tmp
.add(children
[index
]);
652 return tmp
.elements();
655 public boolean getAllowsChildren()
660 public Element
getElement(int index
)
662 if (index
< 0 || index
>= children
.length
)
665 return children
[index
];
668 public int getElementCount()
670 return children
.length
;
673 public int getElementIndex(int offset
)
675 // XXX: There is surely a better algorithm
676 // as beginning from first element each time.
677 for (int index
= 0; index
< children
.length
; ++index
)
679 Element elem
= children
[index
];
681 if ((elem
.getStartOffset() <= offset
)
682 && (offset
< elem
.getEndOffset()))
689 public int getEndOffset()
691 return children
[children
.length
- 1].getEndOffset();
694 public String
getName()
696 return ParagraphElementName
;
699 public int getStartOffset()
701 return children
[0].getStartOffset();
704 public boolean isLeaf()
709 public Element
positionToElement(int position
)
711 // XXX: There is surely a better algorithm
712 // as beginning from first element each time.
713 for (int index
= 0; index
< children
.length
; ++index
)
715 Element elem
= children
[index
];
717 if ((elem
.getStartOffset() <= position
)
718 && (position
< elem
.getEndOffset()))
725 public void replace(int offset
, int length
, Element
[] elements
)
727 Element
[] target
= new Element
[children
.length
- length
729 System
.arraycopy(children
, 0, target
, 0, offset
);
730 System
.arraycopy(elements
, 0, target
, offset
, elements
.length
);
731 System
.arraycopy(children
, offset
+ length
, target
,
732 offset
+ elements
.length
,
733 children
.length
- offset
- length
);
737 public String
toString()
739 return ("BranchElement(" + getName() + ") "
740 + getStartOffset() + "," + getEndOffset() + "\n");
744 public class DefaultDocumentEvent
extends CompoundEdit
745 implements DocumentEvent
747 private static final long serialVersionUID
= -7406103236022413522L;
751 private DocumentEvent
.EventType type
;
753 public DefaultDocumentEvent(int offset
, int length
,
754 DocumentEvent
.EventType type
)
756 this.offset
= offset
;
757 this.length
= length
;
761 public Document
getDocument()
763 return AbstractDocument
.this;
766 public int getLength()
771 public int getOffset()
776 public DocumentEvent
.EventType
getType()
781 public DocumentEvent
.ElementChange
getChange(Element elem
)
787 public static class ElementEdit
extends AbstractUndoableEdit
788 implements DocumentEvent
.ElementChange
790 private static final long serialVersionUID
= -1216620962142928304L;
792 private Element elem
;
794 private Element
[] removed
;
795 private Element
[] added
;
797 public ElementEdit(Element elem
, int index
,
798 Element
[] removed
, Element
[] added
)
802 this.removed
= removed
;
806 public Element
[] getChildrenAdded()
811 public Element
[] getChildrenRemoved()
816 public Element
getElement()
821 public int getIndex()
827 public class LeafElement
extends AbstractElement
829 private static final long serialVersionUID
= 5115368706941283802L;
833 public LeafElement(Element parent
, AttributeSet attributes
, int start
,
836 super(parent
, attributes
);
841 public Enumeration
children()
846 public boolean getAllowsChildren()
851 public Element
getElement(int index
)
856 public int getElementCount()
861 public int getElementIndex(int offset
)
866 public int getEndOffset()
871 public String
getName()
873 return ContentElementName
;
876 public int getStartOffset()
881 public boolean isLeaf()
886 public String
toString()
888 return ("LeafElement(" + getName() + ") "
889 + getStartOffset() + "," + getEndOffset() + "\n");