PageRenderTime 88ms CodeModel.GetById 62ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-3-pre5/org/gjt/sp/jedit/textarea/BufferHandler.java

#
Java | 396 lines | 273 code | 49 blank | 74 comment | 53 complexity | 601e7638a8e08e9e69f491ea57520c81 MD5 | raw file
  1/*
  2 * BufferHandler.java
  3 * :tabSize=8:indentSize=8:noTabs=false:
  4 * :folding=explicit:collapseFolds=1:
  5 *
  6 * Copyright (C) 2001, 2005 Slava Pestov
  7 *
  8 * This program is free software; you can redistribute it and/or
  9 * modify it under the terms of the GNU General Public License
 10 * as published by the Free Software Foundation; either version 2
 11 * of the License, or any later version.
 12 *
 13 * This program is distributed in the hope that it will be useful,
 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16 * GNU General Public License for more details.
 17 *
 18 * You should have received a copy of the GNU General Public License
 19 * along with this program; if not, write to the Free Software
 20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 21 */
 22
 23package org.gjt.sp.jedit.textarea;
 24
 25import java.util.Iterator;
 26import org.gjt.sp.jedit.buffer.*;
 27import org.gjt.sp.jedit.Debug;
 28
 29/**
 30 * Note that in this class we take great care to defer complicated
 31 * calculations to the end of the current transaction if the buffer
 32 * informs us a compound edit is in progress
 33 * (<code>isTransactionInProgress()</code>).
 34 *
 35 * This greatly speeds up replace all for example, by only doing certain
 36 * things once, particularly in <code>moveCaretPosition()</code>.
 37 *
 38 * Try doing a replace all in a large file, for example. It is very slow
 39 * in 3.2, faster in 4.0 (where the transaction optimization was
 40 * introduced) and faster still in 4.1 (where it was further improved).
 41 *
 42 * There is still work to do; see TODO.txt.
 43 */
 44class BufferHandler implements BufferListener
 45{
 46	private DisplayManager displayManager;
 47	private JEditTextArea textArea;
 48	private JEditBuffer buffer;
 49
 50	boolean delayedUpdate;
 51	boolean delayedMultilineUpdate;
 52	int delayedUpdateStart;
 53	int delayedUpdateEnd;
 54
 55	//{{{ BufferChangeHandler constructor
 56	BufferHandler(DisplayManager displayManager,
 57		JEditTextArea textArea,
 58		JEditBuffer buffer)
 59	{
 60		this.displayManager = displayManager;
 61		this.textArea = textArea;
 62		this.buffer = buffer;
 63	} //}}}
 64
 65	//{{{ bufferLoaded() method
 66	public void bufferLoaded(JEditBuffer buffer)
 67	{
 68		displayManager.bufferLoaded();
 69	} //}}}
 70
 71	//{{{ foldHandlerChanged() method
 72	public void foldHandlerChanged(JEditBuffer buffer)
 73	{
 74		displayManager.foldHandlerChanged();
 75	} //}}}
 76
 77	//{{{ foldLevelChanged() method
 78	public void foldLevelChanged(JEditBuffer buffer, int start, int end)
 79	{
 80		//System.err.println("foldLevelChanged " + (start-1) + " to " + textArea.getLastPhysicalLine() + "," + end);
 81
 82		if(textArea.getDisplayManager() == displayManager
 83			&& end != 0 && !buffer.isLoading())
 84		{
 85			textArea.invalidateLineRange(start - 1,
 86				textArea.getLastPhysicalLine());
 87		}
 88	} //}}}
 89
 90	//{{{ contentInserted() method
 91	public void contentInserted(JEditBuffer buffer, int startLine,
 92		int offset, int numLines, int length)
 93	{
 94		if(buffer.isLoading())
 95			return;
 96
 97		displayManager.screenLineMgr.contentInserted(startLine,numLines);
 98
 99		int endLine = startLine + numLines;
100
101		if(numLines != 0)
102			delayedMultilineUpdate = true;
103
104		displayManager.folds.contentInserted(startLine,numLines);
105
106		FirstLine firstLine = displayManager.firstLine;
107		ScrollLineCount scrollLineCount = displayManager.scrollLineCount;
108
109		if(textArea.getDisplayManager() == displayManager)
110		{
111			if(numLines != 0)
112			{
113				firstLine.contentInserted(startLine,numLines);
114				scrollLineCount.contentInserted(startLine,numLines);
115			}
116
117			if(delayedUpdateEnd >= startLine)
118				delayedUpdateEnd += numLines;
119			delayUpdate(startLine,endLine);
120
121			//{{{ resize selections if necessary
122			Iterator iter = textArea.getSelectionIterator();
123			while(iter.hasNext())
124			{
125				Selection s = (Selection)iter.next();
126
127				if(s.contentInserted(buffer,startLine,offset,
128					numLines,length))
129				{
130					delayUpdate(s.startLine,s.endLine);
131				}
132			} //}}}
133
134			int caret = textArea.getCaretPosition();
135			if(caret >= offset)
136			{
137				int scrollMode = (textArea.caretAutoScroll()
138					? JEditTextArea.ELECTRIC_SCROLL
139					: JEditTextArea.NO_SCROLL);
140				textArea.moveCaretPosition(
141					caret + length,scrollMode);
142			}
143			else
144			{
145				int scrollMode = (textArea.caretAutoScroll()
146					? JEditTextArea.NORMAL_SCROLL
147					: JEditTextArea.NO_SCROLL);
148				textArea.moveCaretPosition(
149					caret,scrollMode);
150			}
151		}
152		else
153		{
154			firstLine.callReset = true;
155			scrollLineCount.callReset = true;
156		}
157	} //}}}
158
159	//{{{ preContentRemoved() method
160	public void preContentRemoved(JEditBuffer buffer, int startLine,
161		int offset, int numLines, int length)
162	{
163		if(buffer.isLoading())
164			return;
165
166		FirstLine firstLine = displayManager.firstLine;
167		ScrollLineCount scrollLineCount = displayManager.scrollLineCount;
168
169		if(textArea.getDisplayManager() == displayManager)
170		{
171			if(numLines != 0)
172			{
173				firstLine.preContentRemoved(startLine,numLines);
174				scrollLineCount.preContentRemoved(startLine,numLines);
175			}
176
177			if(delayedUpdateEnd >= startLine)
178				delayedUpdateEnd -= numLines;
179			delayUpdate(startLine,startLine);
180		}
181		else
182		{
183			firstLine.callReset = true;
184			scrollLineCount.callReset = true;
185		}
186
187		displayManager.screenLineMgr.contentRemoved(startLine,numLines);
188
189		if(numLines == 0)
190			return;
191
192		delayedMultilineUpdate = true;
193
194		if(displayManager.folds.preContentRemoved(startLine,numLines))
195		{
196			displayManager.folds.reset(buffer.getLineCount());
197			firstLine.callReset = true;
198			scrollLineCount.callReset = true;
199		}
200
201		if(firstLine.physicalLine
202			> displayManager.getLastVisibleLine()
203			|| firstLine.physicalLine
204			< displayManager.getFirstVisibleLine())
205		{
206			// will be handled later.
207			// see comments at the end of
208			// transactionComplete().
209		}
210		// very subtle... if we leave this for
211		// ensurePhysicalLineIsVisible(), an
212		// extra line will be added to the
213		// scroll line count.
214		else if(!displayManager.isLineVisible(
215			firstLine.physicalLine))
216		{
217			firstLine.physicalLine =
218				displayManager.getNextVisibleLine(
219				firstLine.physicalLine);
220		}
221	} //}}}
222
223	//{{{ contentRemoved() method
224	public void contentRemoved(JEditBuffer buffer, int startLine,
225		int start, int numLines, int length)
226	{
227		if(buffer.isLoading())
228			return;
229
230		if(textArea.getDisplayManager() == displayManager)
231		{
232			//{{{ resize selections if necessary
233			Iterator iter = textArea.getSelectionIterator();
234			while(iter.hasNext())
235			{
236				Selection s = (Selection)iter.next();
237
238				if(s.contentRemoved(buffer,startLine,
239					start,numLines,length))
240				{
241					delayUpdate(s.startLine,s.endLine);
242					if(s.start == s.end)
243						iter.remove();
244				}
245			} //}}}
246
247			int caret = textArea.getCaretPosition();
248
249			if(caret >= start + length)
250			{
251				int scrollMode = (textArea.caretAutoScroll()
252					? JEditTextArea.ELECTRIC_SCROLL
253					: JEditTextArea.NO_SCROLL);
254				textArea.moveCaretPosition(
255					caret - length,
256					scrollMode);
257			}
258			else if(caret >= start)
259			{
260				int scrollMode = (textArea.caretAutoScroll()
261					? JEditTextArea.ELECTRIC_SCROLL
262					: JEditTextArea.NO_SCROLL);
263				textArea.moveCaretPosition(
264					start,scrollMode);
265			}
266			else
267			{
268				int scrollMode = (textArea.caretAutoScroll()
269					? JEditTextArea.NORMAL_SCROLL
270					: JEditTextArea.NO_SCROLL);
271				textArea.moveCaretPosition(caret,scrollMode);
272			}
273		}
274	}
275	//}}}
276
277	//{{{ transactionComplete() method
278	public void transactionComplete(JEditBuffer buffer)
279	{
280		if(textArea.getDisplayManager() != displayManager)
281		{
282			delayedUpdate = false;
283			return;
284		}
285
286		if(delayedUpdate)
287			doDelayedUpdate();
288
289		textArea._finishCaretUpdate();
290
291		delayedUpdate = false;
292
293		//{{{ Debug code
294		if(Debug.SCROLL_VERIFY)
295		{
296			int scrollLineCount = 0;
297			int line = delayedUpdateStart;
298			if(!displayManager.isLineVisible(line))
299				line = displayManager.getNextVisibleLine(line);
300			System.err.println(delayedUpdateStart + ":" + delayedUpdateEnd + ":" + textArea.getLineCount());
301			while(line != -1 && line <= delayedUpdateEnd)
302			{
303				scrollLineCount += displayManager.getScreenLineCount(line);
304				line = displayManager.getNextVisibleLine(line);
305			}
306
307			if(scrollLineCount != displayManager.getScrollLineCount())
308			{
309				throw new InternalError(scrollLineCount
310					+ " != "
311					+ displayManager.getScrollLineCount());
312			}
313		} //}}}
314	} //}}}
315
316	//{{{ doDelayedUpdate() method
317	private void doDelayedUpdate()
318	{
319		// must update screen line counts before we call
320		// notifyScreenLineChanges() since that calls
321		// updateScrollBar() which needs valid info
322		int line = delayedUpdateStart;
323		if(!displayManager.isLineVisible(line))
324			line = displayManager.getNextVisibleLine(line);
325		while(line != -1 && line <= delayedUpdateEnd)
326		{
327			displayManager.updateScreenLineCount(line);
328			line = displayManager.getNextVisibleLine(line);
329		}
330
331		// must be before the below call
332		// so that the chunk cache is not
333		// updated with an invisible first
334		// line (see above)
335		displayManager.notifyScreenLineChanges();
336
337		if(delayedMultilineUpdate)
338		{
339			textArea.invalidateScreenLineRange(
340				textArea.chunkCache
341				.getScreenLineOfOffset(
342				delayedUpdateStart,0),
343				textArea.getVisibleLines());
344			delayedMultilineUpdate = false;
345		}
346		else
347		{
348			textArea.invalidateLineRange(
349				delayedUpdateStart,
350				delayedUpdateEnd);
351		}
352
353		// update visible lines
354		int visibleLines = textArea.getVisibleLines();
355		if(visibleLines != 0)
356		{
357			textArea.chunkCache.getLineInfo(
358				visibleLines - 1);
359		}
360
361		// force the fold levels to be
362		// updated.
363
364		// when painting the last line of
365		// a buffer, Buffer.isFoldStart()
366		// doesn't call getFoldLevel(),
367		// hence the foldLevelChanged()
368		// event might not be sent for the
369		// previous line.
370
371		buffer.getFoldLevel(delayedUpdateEnd);
372	} //}}}
373
374	//{{{ delayUpdate() method
375	private void delayUpdate(int startLine, int endLine)
376	{
377		textArea.chunkCache.invalidateChunksFromPhys(startLine);
378		textArea.repaintMgr.setFastScroll(false);
379
380		if(!delayedUpdate)
381		{
382			delayedUpdateStart = startLine;
383			delayedUpdateEnd = endLine;
384			delayedUpdate = true;
385		}
386		else
387		{
388			delayedUpdateStart = Math.min(
389				delayedUpdateStart,
390				startLine);
391			delayedUpdateEnd = Math.max(
392				delayedUpdateEnd,
393				endLine);
394		}
395	} //}}}
396}