View Javadoc

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   
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 	// protected members
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 }