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