1
2
3
4
5
6
7
8
9
10 package org.syntax.jedit;
11
12 import javax.swing.event.DocumentEvent;
13 import javax.swing.text.BadLocationException;
14 import javax.swing.text.Element;
15 import javax.swing.text.PlainDocument;
16 import javax.swing.text.Segment;
17 import javax.swing.undo.UndoableEdit;
18
19 import org.syntax.jedit.tokenmarker.TokenMarker;
20
21 /***
22 * A document implementation that can be tokenized by the syntax highlighting
23 * system.
24 *
25 * @author Slava Pestov
26 * @version $Id$
27 */
28 public class SyntaxDocument extends PlainDocument
29 {
30 /***
31 * Returns the token marker that is to be used to split lines
32 * of this document up into tokens. May return null if this
33 * document is not to be colorized.
34 */
35 public TokenMarker getTokenMarker()
36 {
37 return tokenMarker;
38 }
39
40 /***
41 * Sets the token marker that is to be used to split lines of
42 * this document up into tokens. May throw an exception if
43 * this is not supported for this type of document.
44 * @param tm The new token marker
45 */
46 public void setTokenMarker(TokenMarker tm)
47 {
48 tokenMarker = tm;
49 if(tm == null)
50 return;
51 tokenMarker.insertLines(0,getDefaultRootElement()
52 .getElementCount());
53 tokenizeLines();
54 }
55
56 /***
57 * Reparses the document, by passing all lines to the token
58 * marker. This should be called after the document is first
59 * loaded.
60 */
61 public void tokenizeLines()
62 {
63 tokenizeLines(0,getDefaultRootElement().getElementCount());
64 }
65
66 /***
67 * Reparses the document, by passing the specified lines to the
68 * token marker. This should be called after a large quantity of
69 * text is first inserted.
70 * @param start The first line to parse
71 * @param len The number of lines, after the first one to parse
72 */
73 public void tokenizeLines(int start, int len)
74 {
75 if(tokenMarker == null || !tokenMarker.supportsMultilineTokens())
76 return;
77
78 Segment lineSegment = new Segment();
79 Element map = getDefaultRootElement();
80
81 len += start;
82
83 try
84 {
85 for(int i = start; i < len; i++)
86 {
87 Element lineElement = map.getElement(i);
88 int lineStart = lineElement.getStartOffset();
89 getText(lineStart,lineElement.getEndOffset()
90 - lineStart - 1,lineSegment);
91 tokenMarker.markTokens(lineSegment,i);
92 }
93 }
94 catch(BadLocationException bl)
95 {
96 bl.printStackTrace();
97 }
98 }
99
100 /***
101 * Starts a compound edit that can be undone in one operation.
102 * Subclasses that implement undo should override this method;
103 * this class has no undo functionality so this method is
104 * empty.
105 */
106 public void beginCompoundEdit() {}
107
108 /***
109 * Ends a compound edit that can be undone in one operation.
110 * Subclasses that implement undo should override this method;
111 * this class has no undo functionality so this method is
112 * empty.
113 */
114 public void endCompoundEdit() {
115 }
116
117 /***
118 * Adds an undoable edit to this document's undo list. The edit
119 * should be ignored if something is currently being undone.
120 * @param edit The undoable edit
121 *
122 * @since jEdit 2.2pre1
123 */
124 public void addUndoableEdit(UndoableEdit edit) {}
125
126
127 protected TokenMarker tokenMarker;
128
129 /***
130 * We overwrite this method to update the token marker
131 * state immediately so that any event listeners get a
132 * consistent token marker.
133 */
134 protected void fireInsertUpdate(DocumentEvent evt)
135 {
136 if(tokenMarker != null)
137 {
138 DocumentEvent.ElementChange ch = evt.getChange(
139 getDefaultRootElement());
140 if(ch != null)
141 {
142 tokenMarker.insertLines(ch.getIndex() + 1,
143 ch.getChildrenAdded().length -
144 ch.getChildrenRemoved().length);
145 }
146 }
147
148 super.fireInsertUpdate(evt);
149 }
150
151 /***
152 * We overwrite this method to update the token marker
153 * state immediately so that any event listeners get a
154 * consistent token marker.
155 */
156 protected void fireRemoveUpdate(DocumentEvent evt)
157 {
158 if(tokenMarker != null)
159 {
160 DocumentEvent.ElementChange ch = evt.getChange(
161 getDefaultRootElement());
162 if(ch != null)
163 {
164 tokenMarker.deleteLines(ch.getIndex() + 1,
165 ch.getChildrenRemoved().length -
166 ch.getChildrenAdded().length);
167 }
168 }
169
170 super.fireRemoveUpdate(evt);
171 }
172 }