PageRenderTime 118ms CodeModel.GetById 101ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/jedit/textarea/StructureMatcher.java

#
Java | 239 lines | 152 code | 31 blank | 56 comment | 20 complexity | 5403296a8feacf996342fc96782f72a2 MD5 | raw file
  1/*
  2 * StructureMatcher.java - Abstract interface for bracket matching, etc.
  3 * :tabSize=8:indentSize=8:noTabs=false:
  4 * :folding=explicit:collapseFolds=1:
  5 *
  6 * Copyright (C) 2003 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
 25//{{{ Imports
 26import java.awt.*;
 27import org.gjt.sp.jedit.TextUtilities;
 28//}}}
 29
 30/**
 31 * An interface for matching parts of a source file's stucture. The default
 32 * implementation matches brackets. The XML plugin provides an implementation
 33 * for matching XML tags.
 34 *
 35 * @author Slava Pestov
 36 * @version $Id: StructureMatcher.java 4918 2003-11-18 20:51:58Z spestov $
 37 * @since jEdit 4.2pre3
 38 */
 39public interface StructureMatcher
 40{
 41	//{{{ getMatch() method
 42	/**
 43	 * Returns the element matching the one at the given text area's
 44	 * caret position, or null.
 45	 * @since jEdit 4.2pre3
 46	 */
 47	Match getMatch(JEditTextArea textArea);
 48	//}}}
 49
 50	//{{{ selectMatch() method
 51	/**
 52	 * Selects from the caret to the matching structure element (if there is
 53	 * one, otherwise the behavior of this method is undefined).
 54	 * @since jEdit 4.2pre3
 55	 */
 56	void selectMatch(JEditTextArea textArea);
 57	//}}}
 58
 59	//{{{ BracketMatcher class
 60	static class BracketMatcher implements StructureMatcher
 61	{
 62		public Match getMatch(JEditTextArea textArea)
 63		{
 64			int offset = textArea.getCaretPosition()
 65				- textArea.getLineStartOffset(
 66				textArea.getCaretLine());
 67
 68			if(offset != 0)
 69			{
 70				int bracketOffset = TextUtilities.findMatchingBracket(
 71					textArea.getBuffer(),
 72					textArea.getCaretLine(),
 73					offset - 1);
 74				if(bracketOffset != -1)
 75				{
 76					int bracketLine = textArea
 77						.getLineOfOffset(
 78						bracketOffset);
 79					return new Match(this,
 80						bracketLine,
 81						bracketOffset,
 82						bracketLine,
 83						bracketOffset + 1);
 84				}
 85			}
 86
 87			return null;
 88		}
 89
 90		public void selectMatch(JEditTextArea textArea)
 91		{
 92			textArea.selectToMatchingBracket();
 93		}
 94	} //}}}
 95
 96	//{{{ Match class
 97	/**
 98	 * A structure match, denoted by a start and end position.
 99	 * @since jEdit 4.2pre3
100	 */
101	public static class Match
102	{
103		public StructureMatcher matcher;
104		public int startLine;
105		public int start;
106		public int endLine;
107		public int end;
108
109		public Match() {}
110
111		public Match(StructureMatcher matcher)
112		{
113			this.matcher = matcher;
114		}
115
116		public Match(StructureMatcher matcher, int startLine,
117			int start, int endLine, int end)
118		{
119			this(matcher);
120			this.startLine = startLine;
121			this.start = start;
122			this.endLine = endLine;
123			this.end = end;
124		}
125	} //}}}
126
127	//{{{ Highlight class
128	/**
129	 * Paints the structure match highlight.
130	 */
131	static class Highlight extends TextAreaExtension
132	{
133		Highlight(JEditTextArea textArea)
134		{
135			this.textArea = textArea;
136		}
137
138		public void paintValidLine(Graphics2D gfx, int screenLine,
139			int physicalLine, int start, int end, int y)
140		{
141			if(!textArea.getPainter().isStructureHighlightEnabled())
142				return;
143
144			Match match = textArea.getStructureMatch();
145			if(match != null)
146			{
147				paintHighlight(gfx,screenLine,physicalLine,
148					start,end,y,match);
149			}
150		}
151
152		private int[] getOffsets(int screenLine, Match match)
153		{
154			int x1, x2;
155
156			int matchStartLine = textArea.getScreenLineOfOffset(
157				match.start);
158			int matchEndLine = textArea.getScreenLineOfOffset(
159				match.end);
160
161			if(matchStartLine == screenLine)
162			{
163				x1 = match.start;
164			}
165			else
166			{
167				x1 = textArea.getScreenLineStartOffset(
168					screenLine);
169			}
170
171			if(matchEndLine == screenLine)
172			{
173				x2 = match.end;
174			}
175			else
176			{
177				x2 = textArea.getScreenLineEndOffset(
178					screenLine) - 1;
179			}
180
181			return new int[] {
182				textArea.offsetToXY(x1).x,
183				textArea.offsetToXY(x2).x
184			};
185		}
186	
187		private void paintHighlight(Graphics gfx, int screenLine,
188			int physicalLine, int start, int end, int y,
189			Match match)
190		{
191			if(!textArea.isStructureHighlightVisible())
192				return;
193
194			if(match.start >= end || match.end < start)
195			{
196				return;
197			}
198
199			int matchStartLine = textArea.getScreenLineOfOffset(
200				match.start);
201			int matchEndLine = textArea.getScreenLineOfOffset(
202				match.end);
203
204			FontMetrics fm = textArea.getPainter().getFontMetrics();
205			int height = fm.getHeight();
206
207			int[] offsets = getOffsets(screenLine,match);
208			int x1 = offsets[0];
209			int x2 = offsets[1];
210
211			gfx.setColor(textArea.getPainter().getStructureHighlightColor());
212
213			gfx.drawLine(x1,y,x1,y + height - 1);
214			gfx.drawLine(x2,y,x2,y + height - 1);
215
216			if(matchStartLine == screenLine || screenLine == 0)
217				gfx.drawLine(x1,y,x2,y);
218			else
219			{
220				offsets = getOffsets(screenLine - 1,match);
221				int prevX1 = offsets[0];
222				int prevX2 = offsets[1];
223
224				gfx.drawLine(Math.min(x1,prevX1),y,
225					Math.max(x1,prevX1),y);
226				gfx.drawLine(Math.min(x2,prevX2),y,
227					Math.max(x2,prevX2),y);
228			}
229
230			if(matchEndLine == screenLine)
231			{
232				gfx.drawLine(x1,y + height - 1,
233					x2,y + height - 1);
234			}
235		}
236
237		private JEditTextArea textArea;
238	} //}}}
239}