/plugins/XML/tags/release-0-11/xml/TagHighlight.java

# · Java · 369 lines · 274 code · 60 blank · 35 comment · 65 complexity · 3a865602b3ed396365d030381c72a814 MD5 · raw file

  1. /*
  2. * TagHighlight.java
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (c) 2000 Andre Kaplan
  7. * Portions copyright (c) 2002 Slava Pestov
  8. *
  9. * The XML plugin is licensed under the GNU General Public License, with
  10. * the following exception:
  11. *
  12. * "Permission is granted to link this code with software released under
  13. * the Apache license version 1.1, for example used by the Xerces XML
  14. * parser package."
  15. */
  16. package xml;
  17. //{{{ Imports
  18. import javax.swing.event.*;
  19. import javax.swing.Timer;
  20. import java.awt.event.*;
  21. import java.awt.*;
  22. import org.gjt.sp.jedit.*;
  23. import org.gjt.sp.jedit.buffer.BufferChangeAdapter;
  24. import org.gjt.sp.jedit.msg.*;
  25. import org.gjt.sp.jedit.textarea.*;
  26. import sidekick.SideKickPlugin;
  27. import xml.parser.*;
  28. //}}}
  29. public class TagHighlight extends TextAreaExtension implements EBComponent
  30. {
  31. //{{{ TagHighlight constructor
  32. public TagHighlight(View view, JEditTextArea textArea)
  33. {
  34. this.view = view;
  35. this.textArea = textArea;
  36. bufferHandler = new BufferHandler();
  37. caretHandler = new CaretHandler();
  38. timer = new Timer(0,new ActionListener()
  39. {
  40. public void actionPerformed(ActionEvent evt)
  41. {
  42. updateHighlight();
  43. }
  44. });
  45. bufferChanged(textArea.getBuffer());
  46. returnValue = new Point();
  47. EditBus.addToBus(this);
  48. } //}}}
  49. //{{{ dispose() method
  50. public void dispose()
  51. {
  52. EditBus.removeFromBus(this);
  53. if(buffer != null)
  54. buffer.removeBufferChangeListener(bufferHandler);
  55. } //}}}
  56. //{{{ handleMessage() method
  57. public void handleMessage(EBMessage msg)
  58. {
  59. if(msg instanceof BufferUpdate)
  60. {
  61. BufferUpdate bu = (BufferUpdate)msg;
  62. Buffer buffer = bu.getBuffer();
  63. if(bu.getWhat() == BufferUpdate.PROPERTIES_CHANGED)
  64. {
  65. if(textArea.getBuffer() == buffer)
  66. bufferChanged(buffer);
  67. }
  68. }
  69. else if(msg instanceof EditPaneUpdate)
  70. {
  71. EditPaneUpdate epu = (EditPaneUpdate)msg;
  72. EditPane editPane = epu.getEditPane();
  73. if(epu.getWhat() == EditPaneUpdate.BUFFER_CHANGED)
  74. {
  75. if(editPane.getTextArea() == textArea)
  76. bufferChanged(editPane.getBuffer());
  77. }
  78. }
  79. } //}}}
  80. //{{{ paintValidLine() method
  81. public void paintValidLine(Graphics2D gfx, int screenLine,
  82. int physicalLine, int start, int end, int y)
  83. {
  84. if(match != null)
  85. paintHighlight(gfx,screenLine,physicalLine,start,end,y,match);
  86. } //}}}
  87. //{{{ bufferChanged() method
  88. public void bufferChanged(Buffer buffer)
  89. {
  90. current = match = null;
  91. if(this.buffer != null)
  92. {
  93. //System.err.println("removing from " + this.buffer);
  94. this.buffer.removeBufferChangeListener(bufferHandler);
  95. textArea.removeCaretListener(caretHandler);
  96. textArea.getPainter().removeExtension(this);
  97. }
  98. if(SideKickPlugin.getParserForBuffer(buffer) instanceof XmlParser)
  99. {
  100. //System.err.println("adding to " + buffer);
  101. this.buffer = buffer;
  102. buffer.addBufferChangeListener(bufferHandler);
  103. textArea.addCaretListener(caretHandler);
  104. textArea.getPainter().addExtension(this);
  105. updateHighlightWithDelay();
  106. }
  107. else
  108. this.buffer = null;
  109. } //}}}
  110. //{{{ propertiesChanged() method
  111. public static void propertiesChanged()
  112. {
  113. tagHighlightColor = jEdit.getColorProperty(
  114. "xml.tag-highlight-color");
  115. tagHighlightEnabled = jEdit.getBooleanProperty(
  116. "xml.tag-highlight");
  117. } //}}}
  118. //{{{ Private members
  119. //{{{ Instance variables
  120. private static Color tagHighlightColor;
  121. private static boolean tagHighlightEnabled;
  122. private Timer timer;
  123. private BufferHandler bufferHandler;
  124. private CaretHandler caretHandler;
  125. private TagParser.Tag current;
  126. private TagParser.Tag match;
  127. private boolean bufferChanged;
  128. private View view;
  129. private JEditTextArea textArea;
  130. private Buffer buffer;
  131. private Point returnValue;
  132. //}}}
  133. //{{{ paintHighlight() method
  134. private void paintHighlight(Graphics gfx, int screenLine, int physicalLine,
  135. int start, int end, int y, TagParser.Tag tag)
  136. {
  137. if(tag.start >= end || tag.end < start)
  138. return;
  139. int tagStartLine = textArea.getScreenLineOfOffset(tag.start);
  140. int tagEndLine = textArea.getScreenLineOfOffset(tag.end);
  141. FontMetrics fm = textArea.getPainter().getFontMetrics();
  142. int height = fm.getHeight();
  143. int x1, x2;
  144. if(tagStartLine == screenLine)
  145. {
  146. x1 = tag.start - buffer.getLineStartOffset(
  147. buffer.getLineOfOffset(tag.start));
  148. }
  149. else
  150. x1 = 0;
  151. if(tagEndLine == screenLine)
  152. {
  153. x2 = tag.end - buffer.getLineStartOffset(
  154. buffer.getLineOfOffset(tag.end));
  155. }
  156. else
  157. {
  158. x2 = textArea.getScreenLineEndOffset(screenLine)
  159. - textArea.getScreenLineStartOffset(screenLine);
  160. }
  161. x1 = textArea.offsetToXY(physicalLine,x1,returnValue).x;
  162. x2 = textArea.offsetToXY(physicalLine,x2,returnValue).x;
  163. gfx.setColor(tagHighlightColor);
  164. gfx.drawLine(x1,y,x1,y + height - 1);
  165. gfx.drawLine(x2,y,x2,y + height - 1);
  166. if(tagStartLine == screenLine || screenLine == 0)
  167. gfx.drawLine(x1,y,x2,y);
  168. else
  169. {
  170. int prevX1, prevX2;
  171. if(tagStartLine == screenLine - 1)
  172. {
  173. prevX1 = tag.start - buffer.getLineStartOffset(
  174. buffer.getLineOfOffset(tag.start));
  175. }
  176. else
  177. prevX1 = 0;
  178. prevX2 = textArea.getScreenLineEndOffset(screenLine - 1)
  179. - textArea.getScreenLineStartOffset(screenLine - 1);
  180. prevX1 = textArea.offsetToXY(physicalLine - 1,prevX1,returnValue).x;
  181. prevX2 = textArea.offsetToXY(physicalLine - 1,prevX2,returnValue).x;
  182. gfx.drawLine(Math.min(x1,prevX1),y,
  183. Math.max(x1,prevX1),y);
  184. gfx.drawLine(Math.min(x2,prevX2),y,
  185. Math.max(x2,prevX2),y);
  186. }
  187. if(tagEndLine == screenLine)
  188. gfx.drawLine(x1,y + height - 1,x2,y + height - 1);
  189. } //}}}
  190. //{{{ updateHighlightWithDelay() method
  191. private void updateHighlightWithDelay()
  192. {
  193. if(timer.isRunning())
  194. timer.stop();
  195. if(!tagHighlightEnabled || buffer == null || !buffer.isLoaded())
  196. {
  197. return;
  198. }
  199. timer.setInitialDelay(300);
  200. timer.setRepeats(false);
  201. timer.start();
  202. } //}}}
  203. //{{{ updateHighlight() method
  204. private void updateHighlight()
  205. {
  206. int caret = textArea.getCaretPosition();
  207. if(bufferChanged || current == null
  208. || caret <= current.start
  209. || caret >= current.end)
  210. {
  211. if(match != null)
  212. {
  213. if(match.start < buffer.getLength()
  214. && match.end <= buffer.getLength())
  215. {
  216. textArea.invalidateLineRange(
  217. textArea.getLineOfOffset(match.start),
  218. textArea.getLineOfOffset(match.end)
  219. );
  220. }
  221. match = null;
  222. }
  223. if(XmlPlugin.isDelegated(textArea))
  224. return;
  225. String text = textArea.getText();
  226. current = TagParser.getTagAtOffset(text,caret);
  227. if(current == null)
  228. {
  229. match = null;
  230. }
  231. else
  232. {
  233. match = TagParser.getMatchingTag(text,current);
  234. if(match != null)
  235. {
  236. int offset = buffer.getLineOfOffset(match.start);
  237. int line = textArea.physicalToVirtual(
  238. offset);
  239. if(line < textArea.getFirstLine()
  240. || line >= textArea.getFirstLine()
  241. + textArea.getVisibleLines() - 1)
  242. {
  243. view.getStatus().setMessageAndClear(
  244. jEdit.getProperty("view.status.bracket",
  245. new String[] { text.substring(
  246. match.start,match.end) }));
  247. }
  248. textArea.invalidateLineRange(
  249. buffer.getLineOfOffset(match.start),
  250. buffer.getLineOfOffset(match.end)
  251. );
  252. }
  253. }
  254. }
  255. bufferChanged = false;
  256. } //}}}
  257. //}}}
  258. //{{{ BufferHandler class
  259. class BufferHandler extends BufferChangeAdapter
  260. {
  261. public void contentInserted(Buffer buffer, int startLine,
  262. int offset, int numLines, int length)
  263. {
  264. bufferChanged = true;
  265. if(match != null)
  266. {
  267. if(match.start >= offset)
  268. match.start += length;
  269. if(match.end >= offset)
  270. match.end += length;
  271. }
  272. updateHighlightWithDelay();
  273. }
  274. public void contentRemoved(Buffer buffer, int startLine,
  275. int offset, int numLines, int length)
  276. {
  277. bufferChanged = true;
  278. if(match != null)
  279. {
  280. if(match.start >= offset)
  281. {
  282. if(match.start < offset + length)
  283. match.start = offset;
  284. else
  285. match.start -= length;
  286. }
  287. if(match.end >= offset)
  288. {
  289. if(match.end < offset + length)
  290. match.end = offset;
  291. else
  292. match.end -= length;
  293. }
  294. }
  295. updateHighlightWithDelay();
  296. }
  297. } //}}}
  298. //{{{ CaretHandler class
  299. class CaretHandler implements CaretListener
  300. {
  301. public void caretUpdate(CaretEvent evt)
  302. {
  303. // hack
  304. if(textArea.getBuffer() != buffer)
  305. return;
  306. updateHighlightWithDelay();
  307. }
  308. } //}}}
  309. }