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., 51 Franklin Street, Fifth Floor, 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.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 public abstract class AbstractDocument
60 implements Document, Serializable
62 private static final long serialVersionUID = -116069779446114664L;
64 protected static final String BAD_LOCATION = "document location failure";
66 public static final String BidiElementName = "bidi level";
67 public static final String ContentElementName = "content";
68 public static final String ParagraphElementName = "paragraph";
69 public static final String SectionElementName = "section";
70 public static final String ElementNameAttribute = "$ename";
73 AttributeContext context;
74 DocumentFilter documentFilter;
76 /** The documents properties. */
77 Dictionary properties;
79 protected EventListenerList listenerList = new EventListenerList();
81 protected AbstractDocument(Content doc)
83 this(doc, StyleContext.getDefaultStyleContext());
86 protected AbstractDocument(Content doc, AttributeContext ctx)
92 // These still need to be implemented by a derived class:
93 public abstract Element getParagraphElement(int pos);
95 public abstract Element getDefaultRootElement();
97 protected Element createBranchElement(Element parent,
98 AttributeSet attributes)
100 return new BranchElement(parent, attributes);
103 protected Element createLeafElement(Element parent, AttributeSet attributes,
106 return new LeafElement(parent, attributes, start, end);
109 public Position createPosition(final int offset) throws BadLocationException
111 if (offset < 0 || offset > getLength())
112 throw new BadLocationException(getText(0, getLength()), offset);
114 return new Position()
116 public int getOffset()
123 protected void fireChangedUpdate(DocumentEvent event)
125 DocumentListener[] listeners = getDocumentListeners();
127 for (int index = 0; index < listeners.length; ++index)
128 listeners[index].changedUpdate(event);
131 protected void fireInsertUpdate(DocumentEvent event)
133 DocumentListener[] listeners = getDocumentListeners();
135 for (int index = 0; index < listeners.length; ++index)
136 listeners[index].insertUpdate(event);
139 protected void fireRemoveUpdate(DocumentEvent event)
141 DocumentListener[] listeners = getDocumentListeners();
143 for (int index = 0; index < listeners.length; ++index)
144 listeners[index].removeUpdate(event);
147 protected void fireUndoableEditUpdate(UndoableEditEvent event)
149 UndoableEditListener[] listeners = getUndoableEditListeners();
151 for (int index = 0; index < listeners.length; ++index)
152 listeners[index].undoableEditHappened(event);
155 public int getAsynchronousLoadPriority()
160 protected AttributeContext getAttributeContext()
165 public Element getBidiRootElement()
170 protected Content getContent()
175 protected Thread getCurrentWriter()
180 public Dictionary getDocumentProperties()
182 // FIXME: make me thread-safe
183 if (properties == null)
184 properties = new Hashtable();
189 public Position getEndPosition()
191 return new Position()
193 public int getOffset()
200 public int getLength()
202 return content.length() - 1;
205 public EventListener[] getListeners(Class listenerType)
207 return listenerList.getListeners(listenerType);
210 public Object getProperty(Object key)
212 // FIXME: make me thread-safe
214 if (properties != null)
215 value = properties.get(key);
220 public Element[] getRootElements()
222 Element[] elements = new Element[1];
223 elements[0] = getDefaultRootElement();
227 public Position getStartPosition()
229 return new Position()
231 public int getOffset()
238 public String getText(int offset, int length) throws BadLocationException
240 return content.getString(offset, length);
243 public void getText(int offset, int length, Segment segment)
244 throws BadLocationException
246 content.getChars(offset, length, segment);
249 public void insertString(int offset, String text, AttributeSet attributes)
250 throws BadLocationException
252 // Just return when no text to insert was given.
253 if (text == null || text.length() == 0)
256 DefaultDocumentEvent event =
257 new DefaultDocumentEvent(offset, text.length(),
258 DocumentEvent.EventType.INSERT);
259 content.insertString(offset, text);
260 insertUpdate(event, attributes);
261 fireInsertUpdate(event);
264 protected void insertUpdate(DefaultDocumentEvent chng, AttributeSet attr)
268 protected void postRemoveUpdate(DefaultDocumentEvent chng)
272 public void putProperty(Object key, Object value)
274 // FIXME: make me thread-safe
275 if (properties == null)
276 properties = new Hashtable();
278 properties.put(key, value);
281 public void readLock()
285 public void readUnlock()
289 public void remove(int offset, int length) throws BadLocationException
291 DefaultDocumentEvent event =
292 new DefaultDocumentEvent(offset, length,
293 DocumentEvent.EventType.REMOVE);
295 content.remove(offset, length);
296 postRemoveUpdate(event);
297 fireRemoveUpdate(event);
301 * Replaces some text in the document.
305 public void replace(int offset, int length, String text,
306 AttributeSet attributes)
307 throws BadLocationException
309 remove(offset, length);
310 insertString(offset, text, attributes);
314 * Adds a <code>DocumentListener</code> object to this document.
316 * @param listener the listener to add
318 public void addDocumentListener(DocumentListener listener)
320 listenerList.add(DocumentListener.class, listener);
324 * Removes a <code>DocumentListener</code> object from this document.
326 * @param listener the listener to remove
328 public void removeDocumentListener(DocumentListener listener)
330 listenerList.remove(DocumentListener.class, listener);
334 * Returns add added <code>DocumentListener</code> objects.
336 * @return an array of listeners
338 public DocumentListener[] getDocumentListeners()
340 return (DocumentListener[]) getListeners(DocumentListener.class);
344 * Adds a <code>UndoableEditListener</code> object to this document.
346 * @param listener the listener to add
348 public void addUndoableEditListener(UndoableEditListener listener)
350 listenerList.add(UndoableEditListener.class, listener);
354 * Removes a <code>UndoableEditListener</code> object from this document.
356 * @param listener the listener to remove
358 public void removeUndoableEditListener(UndoableEditListener listener)
360 listenerList.remove(UndoableEditListener.class, listener);
364 * Returns add added <code>UndoableEditListener</code> objects.
366 * @return an array of listeners
368 public UndoableEditListener[] getUndoableEditListeners()
370 return (UndoableEditListener[]) getListeners(UndoableEditListener.class);
373 protected void removeUpdate(DefaultDocumentEvent chng)
377 public void render(Runnable r)
381 public void setAsynchronousLoadPriority(int p)
385 public void setDocumentProperties(Dictionary x)
387 // FIXME: make me thread-safe
391 protected void writeLock()
395 protected void writeUnlock()
402 public DocumentFilter getDocumentFilter()
404 return documentFilter;
410 public void setDocumentFilter(DocumentFilter filter)
412 this.documentFilter = filter;
415 public void dump(PrintStream out)
417 ((AbstractElement) getDefaultRootElement()).dump(out, 0);
420 public interface AttributeContext
422 AttributeSet addAttribute(AttributeSet old, Object name, Object value);
424 AttributeSet addAttributes(AttributeSet old, AttributeSet attributes);
426 AttributeSet getEmptySet();
428 void reclaim(AttributeSet attributes);
430 AttributeSet removeAttribute(AttributeSet old, Object name);
432 AttributeSet removeAttributes(AttributeSet old, AttributeSet attributes);
434 AttributeSet removeAttributes(AttributeSet old, Enumeration names);
437 public interface Content
439 Position createPosition(int offset) throws BadLocationException;
443 UndoableEdit insertString(int where, String str)
444 throws BadLocationException;
446 UndoableEdit remove(int where, int nitems) throws BadLocationException;
448 String getString(int where, int len) throws BadLocationException;
450 void getChars(int where, int len, Segment txt) throws BadLocationException;
453 public abstract class AbstractElement
454 implements Element, MutableAttributeSet, TreeNode, Serializable
456 private static final long serialVersionUID = 1265312733007397733L;
460 AttributeSet attributes;
462 Element element_parent;
464 TreeNode tree_parent;
465 Vector tree_children;
467 public AbstractElement(Element p, AttributeSet s)
473 // TreeNode implementation
475 public abstract Enumeration children();
477 public abstract boolean getAllowsChildren();
479 public TreeNode getChildAt(int index)
481 return (TreeNode) tree_children.get(index);
484 public int getChildCount()
486 return tree_children.size();
489 public int getIndex(TreeNode node)
491 return tree_children.indexOf(node);
494 public TreeNode getParent()
499 public abstract boolean isLeaf();
502 // MutableAttributeSet support
504 public void addAttribute(Object name, Object value)
506 attributes = getAttributeContext().addAttribute(attributes, name, value);
509 public void addAttributes(AttributeSet attrs)
511 attributes = getAttributeContext().addAttributes(attributes, attrs);
514 public void removeAttribute(Object name)
516 attributes = getAttributeContext().removeAttribute(attributes, name);
519 public void removeAttributes(AttributeSet attrs)
521 attributes = getAttributeContext().removeAttributes(attributes, attrs);
524 public void removeAttributes(Enumeration names)
526 attributes = getAttributeContext().removeAttributes(attributes, names);
529 public void setResolveParent(AttributeSet parent)
531 attributes = getAttributeContext().addAttribute(attributes, ResolveAttribute, parent);
535 // AttributeSet interface support
537 public boolean containsAttribute(Object name, Object value)
539 return attributes.containsAttribute(name, value);
542 public boolean containsAttributes(AttributeSet attrs)
544 return attributes.containsAttributes(attrs);
547 public AttributeSet copyAttributes()
549 return attributes.copyAttributes();
552 public Object getAttribute(Object key)
554 return attributes.getAttribute(key);
557 public int getAttributeCount()
559 return attributes.getAttributeCount();
562 public Enumeration getAttributeNames()
564 return attributes.getAttributeNames();
567 public AttributeSet getResolveParent()
569 return attributes.getResolveParent();
572 public boolean isDefined(Object attrName)
574 return attributes.isDefined(attrName);
577 public boolean isEqual(AttributeSet attrs)
579 return attributes.isEqual(attrs);
582 // Element interface support
584 public AttributeSet getAttributes()
589 public Document getDocument()
591 return AbstractDocument.this;
594 public abstract Element getElement(int index);
596 public String getName()
598 return (String) getAttribute(NameAttribute);
601 public Element getParentElement()
603 return element_parent;
606 public abstract int getEndOffset();
608 public abstract int getElementCount();
610 public abstract int getElementIndex(int offset);
612 public abstract int getStartOffset();
614 private void dumpElement(PrintStream stream, String indent, Element element)
616 System.out.println(indent + "<" + element.getName() +">");
618 if (element.isLeaf())
620 int start = element.getStartOffset();
621 int end = element.getEndOffset();
625 text = getContent().getString(start, end - start);
627 catch (BadLocationException e)
630 System.out.println(indent + " ["
637 for (int i = 0; i < element.getElementCount(); ++i)
638 dumpElement(stream, indent + " ", element.getElement(i));
642 public void dump(PrintStream stream, int indent)
644 String indentStr = "";
645 for (int i = 0; i < indent; ++i)
647 dumpElement(stream, indentStr, this);
651 public class BranchElement extends AbstractElement
653 private static final long serialVersionUID = -8595176318868717313L;
655 private Element[] children = new Element[0];
657 public BranchElement(Element parent, AttributeSet attributes)
659 super(parent, attributes);
662 public Enumeration children()
664 if (children.length == 0)
667 Vector tmp = new Vector();
669 for (int index = 0; index < children.length; ++index)
670 tmp.add(children[index]);
672 return tmp.elements();
675 public boolean getAllowsChildren()
680 public Element getElement(int index)
682 if (index < 0 || index >= children.length)
685 return children[index];
688 public int getElementCount()
690 return children.length;
693 public int getElementIndex(int offset)
695 // XXX: There is surely a better algorithm
696 // as beginning from first element each time.
697 for (int index = 0; index < children.length; ++index)
699 Element elem = children[index];
701 if ((elem.getStartOffset() <= offset)
702 && (offset < elem.getEndOffset()))
709 public int getEndOffset()
711 return children[children.length - 1].getEndOffset();
714 public String getName()
716 return ParagraphElementName;
719 public int getStartOffset()
721 return children[0].getStartOffset();
724 public boolean isLeaf()
729 public Element positionToElement(int position)
731 // XXX: There is surely a better algorithm
732 // as beginning from first element each time.
733 for (int index = 0; index < children.length; ++index)
735 Element elem = children[index];
737 if ((elem.getStartOffset() <= position)
738 && (position < elem.getEndOffset()))
745 public void replace(int offset, int length, Element[] elements)
747 Element[] target = new Element[children.length - length
749 System.arraycopy(children, 0, target, 0, offset);
750 System.arraycopy(elements, 0, target, offset, elements.length);
751 System.arraycopy(children, offset + length, target,
752 offset + elements.length,
753 children.length - offset - length);
757 public String toString()
759 return ("BranchElement(" + getName() + ") "
760 + getStartOffset() + "," + getEndOffset() + "\n");
764 public class DefaultDocumentEvent extends CompoundEdit
765 implements DocumentEvent
767 private static final long serialVersionUID = -7406103236022413522L;
771 private DocumentEvent.EventType type;
773 public DefaultDocumentEvent(int offset, int length,
774 DocumentEvent.EventType type)
776 this.offset = offset;
777 this.length = length;
781 public Document getDocument()
783 return AbstractDocument.this;
786 public int getLength()
791 public int getOffset()
796 public DocumentEvent.EventType getType()
801 public DocumentEvent.ElementChange getChange(Element elem)
807 public static class ElementEdit extends AbstractUndoableEdit
808 implements DocumentEvent.ElementChange
810 private static final long serialVersionUID = -1216620962142928304L;
812 private Element elem;
814 private Element[] removed;
815 private Element[] added;
817 public ElementEdit(Element elem, int index,
818 Element[] removed, Element[] added)
822 this.removed = removed;
826 public Element[] getChildrenAdded()
831 public Element[] getChildrenRemoved()
836 public Element getElement()
841 public int getIndex()
847 public class LeafElement extends AbstractElement
849 private static final long serialVersionUID = 5115368706941283802L;
853 public LeafElement(Element parent, AttributeSet attributes, int start,
856 super(parent, attributes);
861 public Enumeration children()
866 public boolean getAllowsChildren()
871 public Element getElement(int index)
876 public int getElementCount()
881 public int getElementIndex(int offset)
886 public int getEndOffset()
891 public String getName()
893 return ContentElementName;
896 public int getStartOffset()
901 public boolean isLeaf()
906 public String toString()
908 return ("LeafElement(" + getName() + ") "
909 + getStartOffset() + "," + getEndOffset() + "\n");