/jEdit/tags/jedit-4-0-pre2/org/gjt/sp/jedit/textarea/TextAreaPainter.java

# · Java · 938 lines · 553 code · 116 blank · 269 comment · 95 complexity · ca7c34690f0b56be95422d52c5494e06 MD5 · raw file

  1. /*
  2. * TextAreaPainter.java - Paints the text area
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 1999, 2000, 2001 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. package org.gjt.sp.jedit.textarea;
  23. //{{{ Imports
  24. import javax.swing.text.*;
  25. import javax.swing.JComponent;
  26. import java.awt.event.MouseEvent;
  27. import java.awt.*;
  28. import java.lang.reflect.Method;
  29. import java.util.Vector;
  30. import org.gjt.sp.jedit.syntax.*;
  31. import org.gjt.sp.jedit.Buffer;
  32. import org.gjt.sp.jedit.TextUtilities;
  33. import org.gjt.sp.util.Log;
  34. //}}}
  35. /**
  36. * The text area repaint manager. It performs double buffering and paints
  37. * lines of text.
  38. * @author Slava Pestov
  39. * @version $Id: TextAreaPainter.java 3917 2001-11-25 03:42:16Z spestov $
  40. */
  41. public class TextAreaPainter extends JComponent implements TabExpander
  42. {
  43. //{{{ TextAreaPainter constructor
  44. /**
  45. * Creates a new painter. Do not create instances of this class
  46. * directly.
  47. */
  48. public TextAreaPainter(JEditTextArea textArea)
  49. {
  50. enableEvents(AWTEvent.FOCUS_EVENT_MASK
  51. | AWTEvent.KEY_EVENT_MASK
  52. | AWTEvent.MOUSE_EVENT_MASK);
  53. this.textArea = textArea;
  54. highlights = new Vector();
  55. setAutoscrolls(true);
  56. setDoubleBuffered(true);
  57. setOpaque(true);
  58. setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
  59. } //}}}
  60. //{{{ isManagingFocus() method
  61. /**
  62. * Returns if this component can be traversed by pressing the
  63. * Tab key. This returns false.
  64. */
  65. public boolean isManagingFocus()
  66. {
  67. return false;
  68. } //}}}
  69. //{{{ getFocusTraversalKeysEnabled() method
  70. /**
  71. * Makes the tab key work in Java 1.4.
  72. * @since jEdit 3.2pre4
  73. */
  74. public boolean getFocusTraversalKeysEnabled()
  75. {
  76. return false;
  77. } //}}}
  78. //{{{ Getters and setters
  79. //{{{ getStyles() method
  80. /**
  81. * Returns the syntax styles used to paint colorized text. Entry <i>n</i>
  82. * will be used to paint tokens with id = <i>n</i>.
  83. * @see org.gjt.sp.jedit.syntax.Token
  84. */
  85. public final SyntaxStyle[] getStyles()
  86. {
  87. return styles;
  88. } //}}}
  89. //{{{ setStyles() method
  90. /**
  91. * Sets the syntax styles used to paint colorized text. Entry <i>n</i>
  92. * will be used to paint tokens with id = <i>n</i>.
  93. * @param styles The syntax styles
  94. * @see org.gjt.sp.jedit.syntax.Token
  95. */
  96. public final void setStyles(SyntaxStyle[] styles)
  97. {
  98. this.styles = styles;
  99. repaint();
  100. } //}}}
  101. //{{{ getCaretColor() method
  102. /**
  103. * Returns the caret color.
  104. */
  105. public final Color getCaretColor()
  106. {
  107. return caretColor;
  108. } //}}}
  109. //{{{ setCaretColor() method
  110. /**
  111. * Sets the caret color.
  112. * @param caretColor The caret color
  113. */
  114. public final void setCaretColor(Color caretColor)
  115. {
  116. this.caretColor = caretColor;
  117. if(textArea.getBuffer() != null)
  118. textArea.invalidateLine(textArea.getCaretLine());
  119. } //}}}
  120. //{{{ getSelectionColor() method
  121. /**
  122. * Returns the selection color.
  123. */
  124. public final Color getSelectionColor()
  125. {
  126. return selectionColor;
  127. } //}}}
  128. //{{{ setSelectionColor() method
  129. /**
  130. * Sets the selection color.
  131. * @param selectionColor The selection color
  132. */
  133. public final void setSelectionColor(Color selectionColor)
  134. {
  135. this.selectionColor = selectionColor;
  136. if(textArea.getBuffer() != null)
  137. textArea.invalidateSelectedLines();
  138. } //}}}
  139. //{{{ getLineHighlightColor() method
  140. /**
  141. * Returns the line highlight color.
  142. */
  143. public final Color getLineHighlightColor()
  144. {
  145. return lineHighlightColor;
  146. } //}}}
  147. //{{{ setLineHighlightColor() method
  148. /**
  149. * Sets the line highlight color.
  150. * @param lineHighlightColor The line highlight color
  151. */
  152. public final void setLineHighlightColor(Color lineHighlightColor)
  153. {
  154. this.lineHighlightColor = lineHighlightColor;
  155. if(textArea.getBuffer() != null)
  156. textArea.invalidateLine(textArea.getCaretLine());
  157. } //}}}
  158. //{{{ isLineHighlightEnabled() method
  159. /**
  160. * Returns true if line highlight is enabled, false otherwise.
  161. */
  162. public final boolean isLineHighlightEnabled()
  163. {
  164. return lineHighlight;
  165. } //}}}
  166. //{{{ setLineHighlightEnabled() method
  167. /**
  168. * Enables or disables current line highlighting.
  169. * @param lineHighlight True if current line highlight should be enabled,
  170. * false otherwise
  171. */
  172. public final void setLineHighlightEnabled(boolean lineHighlight)
  173. {
  174. this.lineHighlight = lineHighlight;
  175. if(textArea.getBuffer() != null)
  176. textArea.invalidateSelectedLines();
  177. } //}}}
  178. //{{{ getFoldedLineColor() method
  179. /**
  180. * Returns the background color of a collapsed fold line.
  181. */
  182. public final Color getFoldedLineColor()
  183. {
  184. return foldedLineColor;
  185. } //}}}
  186. //{{{ setFoldedLineColor() method
  187. /**
  188. * Sets the background color of a collapsed fold line.
  189. * @param foldedLineColor The folded line color
  190. */
  191. public final void setFoldedLineColor(Color foldedLineColor)
  192. {
  193. this.foldedLineColor = foldedLineColor;
  194. repaint();
  195. } //}}}
  196. //{{{ getBracketHighlightColor() method
  197. /**
  198. * Returns the bracket highlight color.
  199. */
  200. public final Color getBracketHighlightColor()
  201. {
  202. return bracketHighlightColor;
  203. } //}}}
  204. //{{{ setBracketHighlightColor() method
  205. /**
  206. * Sets the bracket highlight color.
  207. * @param bracketHighlightColor The bracket highlight color
  208. */
  209. public final void setBracketHighlightColor(Color bracketHighlightColor)
  210. {
  211. this.bracketHighlightColor = bracketHighlightColor;
  212. if(textArea.getBuffer() != null)
  213. textArea.invalidateLine(textArea.getBracketLine());
  214. } //}}}
  215. //{{{ isBracketHighlightEnabled() method
  216. /**
  217. * Returns true if bracket highlighting is enabled, false otherwise.
  218. * When bracket highlighting is enabled, the bracket matching the
  219. * one before the caret (if any) is highlighted.
  220. */
  221. public final boolean isBracketHighlightEnabled()
  222. {
  223. return bracketHighlight;
  224. } //}}}
  225. //{{{ setBracketHighlightEnabled() method
  226. /**
  227. * Enables or disables bracket highlighting.
  228. * When bracket highlighting is enabled, the bracket matching the
  229. * one before the caret (if any) is highlighted.
  230. * @param bracketHighlight True if bracket highlighting should be
  231. * enabled, false otherwise
  232. */
  233. public final void setBracketHighlightEnabled(boolean bracketHighlight)
  234. {
  235. this.bracketHighlight = bracketHighlight;
  236. if(textArea.getBuffer() != null)
  237. textArea.invalidateLine(textArea.getBracketLine());
  238. } //}}}
  239. //{{{ isBlockCaretEnabled() method
  240. /**
  241. * Returns true if the caret should be drawn as a block, false otherwise.
  242. */
  243. public final boolean isBlockCaretEnabled()
  244. {
  245. return blockCaret;
  246. } //}}}
  247. //{{{ setBlockCaretEnabled() method
  248. /**
  249. * Sets if the caret should be drawn as a block, false otherwise.
  250. * @param blockCaret True if the caret should be drawn as a block,
  251. * false otherwise.
  252. */
  253. public final void setBlockCaretEnabled(boolean blockCaret)
  254. {
  255. this.blockCaret = blockCaret;
  256. if(textArea.getBuffer() != null)
  257. textArea.invalidateLine(textArea.getCaretLine());
  258. } //}}}
  259. //{{{ getEOLMarkerColor() method
  260. /**
  261. * Returns the EOL marker color.
  262. */
  263. public final Color getEOLMarkerColor()
  264. {
  265. return eolMarkerColor;
  266. } //}}}
  267. //{{{ setEOLMarkerColor() method
  268. /**
  269. * Sets the EOL marker color.
  270. * @param eolMarkerColor The EOL marker color
  271. */
  272. public final void setEOLMarkerColor(Color eolMarkerColor)
  273. {
  274. this.eolMarkerColor = eolMarkerColor;
  275. repaint();
  276. } //}}}
  277. //{{{ getEOLMarkersPainted() method
  278. /**
  279. * Returns true if EOL markers are drawn, false otherwise.
  280. */
  281. public final boolean getEOLMarkersPainted()
  282. {
  283. return eolMarkers;
  284. } //}}}
  285. //{{{ setEOLMarkersPainted() method
  286. /**
  287. * Sets if EOL markers are to be drawn.
  288. * @param eolMarkers True if EOL markers should be drawn, false otherwise
  289. */
  290. public final void setEOLMarkersPainted(boolean eolMarkers)
  291. {
  292. this.eolMarkers = eolMarkers;
  293. repaint();
  294. } //}}}
  295. //{{{ getWrapGuideColor() method
  296. /**
  297. * Returns the wrap guide color.
  298. */
  299. public final Color getWrapGuideColor()
  300. {
  301. return wrapGuideColor;
  302. } //}}}
  303. //{{{ setWrapGuideColor() method
  304. /**
  305. * Sets the wrap guide color.
  306. * @param wrapGuideColor The wrap guide color
  307. */
  308. public final void setWrapGuideColor(Color wrapGuideColor)
  309. {
  310. this.wrapGuideColor = wrapGuideColor;
  311. repaint();
  312. } //}}}
  313. //{{{ isWrapGuidePainted()
  314. /**
  315. * Returns true if the wrap guide is drawn, false otherwise.
  316. */
  317. public final boolean getWrapGuidePainted()
  318. {
  319. return wrapGuide;
  320. } //}}}
  321. //{{{ setWrapGuidePainted() method
  322. /**
  323. * Sets if the wrap guide is to be drawn.
  324. * @param wrapGuide True if the wrap guide should be drawn, false otherwise
  325. */
  326. public final void setWrapGuidePainted(boolean wrapGuide)
  327. {
  328. this.wrapGuide = wrapGuide;
  329. repaint();
  330. } //}}}
  331. //{{{ setAntiAliasEnabled() method
  332. /**
  333. * Sets if anti-aliasing should be enabled. Has no effect when
  334. * running on Java 1.1.
  335. * @since jEdit 3.2pre6
  336. */
  337. public void setAntiAliasEnabled(boolean antiAlias)
  338. {
  339. this.antiAlias = antiAlias;
  340. textArea.getTextRenderer().configure(antiAlias,fracFontMetrics);
  341. } //}}}
  342. //{{{ isAntiAliasEnabled() method
  343. /**
  344. * Returns if anti-aliasing is enabled.
  345. * @since jEdit 3.2pre6
  346. */
  347. public boolean isAntiAliasEnabled()
  348. {
  349. return antiAlias;
  350. } //}}}
  351. //{{{ setFractionalFontMetricsEnabled() method
  352. /**
  353. * Sets if fractional font metrics should be enabled. Has no effect when
  354. * running on Java 1.1.
  355. * @since jEdit 3.2pre6
  356. */
  357. public void setFractionalFontMetricsEnabled(boolean fracFontMetrics)
  358. {
  359. this.fracFontMetrics = fracFontMetrics;
  360. textArea.getTextRenderer().configure(antiAlias,fracFontMetrics);
  361. } //}}}
  362. //{{{ isFractionalFontMetricsEnabled() method
  363. /**
  364. * Returns if fractional font metrics are enabled.
  365. * @since jEdit 3.2pre6
  366. */
  367. public boolean isFractionalFontMetricsEnabled()
  368. {
  369. return fracFontMetrics;
  370. } //}}}
  371. //}}}
  372. //{{{ addCustomHighlight() method
  373. /**
  374. * Adds a custom highlight painter.
  375. * @param highlight The highlight
  376. */
  377. public void addCustomHighlight(TextAreaHighlight highlight)
  378. {
  379. highlights.addElement(highlight);
  380. // handle old highlighters
  381. Class clazz = highlight.getClass();
  382. try
  383. {
  384. Method method = clazz.getMethod("init",
  385. new Class[] { JEditTextArea.class,
  386. TextAreaHighlight.class });
  387. if(method != null)
  388. {
  389. Log.log(Log.WARNING,this,clazz.getName()
  390. + " uses old highlighter API");
  391. method.invoke(highlight,new Object[] { textArea, null });
  392. }
  393. }
  394. catch(Exception e)
  395. {
  396. // ignore
  397. }
  398. repaint();
  399. } //}}}
  400. //{{{ removeCustomHighlight() method
  401. /**
  402. * Removes a custom highlight painter.
  403. * @param highlight The highlight
  404. * @since jEdit 4.0pre1
  405. */
  406. public void removeCustomHighlight(TextAreaHighlight highlight)
  407. {
  408. highlights.removeElement(highlight);
  409. repaint();
  410. } //}}}
  411. //{{{ getToolTipText() method
  412. /**
  413. * Returns the tool tip to display at the specified location.
  414. * @param evt The mouse event
  415. */
  416. public String getToolTipText(MouseEvent evt)
  417. {
  418. if(maxLineLen != 0)
  419. {
  420. int wrapGuidePos = maxLineLen + textArea.getHorizontalOffset();
  421. if(Math.abs(evt.getX() - wrapGuidePos) < 5)
  422. {
  423. return String.valueOf(textArea.getBuffer()
  424. .getProperty("maxLineLen"));
  425. }
  426. }
  427. for(int i = 0; i < highlights.size(); i++)
  428. {
  429. TextAreaHighlight highlight =
  430. (TextAreaHighlight)
  431. highlights.elementAt(i);
  432. String toolTip = highlight.getToolTipText(evt);
  433. if(toolTip != null)
  434. return toolTip;
  435. }
  436. return null;
  437. } //}}}
  438. //{{{ getFontMetrics() method
  439. /**
  440. * Returns the font metrics used by this component.
  441. */
  442. public FontMetrics getFontMetrics()
  443. {
  444. return fm;
  445. } //}}}
  446. //{{{ setFont() method
  447. /**
  448. * Sets the font for this component. This is overridden to update the
  449. * cached font metrics and to recalculate which lines are visible.
  450. * @param font The font
  451. */
  452. public void setFont(Font font)
  453. {
  454. super.setFont(font);
  455. fm = getFontMetrics(font);
  456. textArea.recalculateVisibleLines();
  457. updateTabSize();
  458. } //}}}
  459. //{{{ paintComponent() method
  460. /**
  461. * Repaints the text.
  462. * @param g The graphics context
  463. */
  464. public void paintComponent(Graphics gfx)
  465. {
  466. updateTabSize();
  467. textArea.getTextRenderer().setupGraphics(gfx);
  468. Buffer buffer = textArea.getBuffer();
  469. Rectangle clipRect = gfx.getClipBounds();
  470. gfx.setColor(getBackground());
  471. gfx.fillRect(clipRect.x,clipRect.y,clipRect.width,clipRect.height);
  472. int x = textArea.getHorizontalOffset();
  473. int height = fm.getHeight();
  474. int firstLine = textArea.getFirstLine();
  475. int firstInvalid = firstLine + clipRect.y / height;
  476. // Because the clipRect's height is usually an even multiple
  477. // of the font height, we subtract 1 from it, otherwise one
  478. // too many lines will always be painted.
  479. int lastInvalid = firstLine + (clipRect.y + clipRect.height - 1) / height;
  480. FoldVisibilityManager foldVisibilityManager
  481. = textArea.getFoldVisibilityManager();
  482. int lineCount = foldVisibilityManager.getVirtualLineCount();
  483. int y = (clipRect.y - clipRect.y % height);
  484. try
  485. {
  486. boolean updateMaxHorizontalScrollWidth = false;
  487. for(int line = firstInvalid; line <= lastInvalid; line++)
  488. {
  489. boolean valid = buffer.isLoaded()
  490. && line >= 0 && line < lineCount;
  491. int physicalLine;
  492. boolean collapsedFold;
  493. if(valid)
  494. {
  495. physicalLine = textArea.virtualToPhysical(line);
  496. collapsedFold = (physicalLine < buffer.getLineCount() - 1
  497. && buffer.isFoldStart(physicalLine)
  498. && !foldVisibilityManager
  499. .isLineVisible(physicalLine + 1));
  500. }
  501. else
  502. {
  503. physicalLine = -1;
  504. collapsedFold = false;
  505. }
  506. int width = paintLine(gfx,buffer,valid,line,
  507. physicalLine,x,y,collapsedFold) - x;
  508. if(valid)
  509. {
  510. // it seems we are repainted before a
  511. // component event is received
  512. // (read: recalculateVisibleLines()
  513. // called)
  514. int screenLine = line - textArea.getFirstLine();
  515. if(screenLine < textArea.lineWidths.length)
  516. textArea.lineWidths[line - textArea.getFirstLine()] = width;
  517. if(width > textArea.maxHorizontalScrollWidth)
  518. updateMaxHorizontalScrollWidth = true;
  519. physicalLine = foldVisibilityManager
  520. .getNextVisibleLine(physicalLine);
  521. }
  522. y += height;
  523. }
  524. if(buffer.isNextLineRequested())
  525. {
  526. int h = clipRect.y + clipRect.height;
  527. repaint(0,h,getWidth(),getHeight() - h);
  528. }
  529. if(updateMaxHorizontalScrollWidth)
  530. textArea.updateMaxHorizontalScrollWidth();
  531. }
  532. catch(Exception e)
  533. {
  534. Log.log(Log.ERROR,this,"Error repainting line"
  535. + " range {" + firstInvalid + ","
  536. + lastInvalid + "}:");
  537. Log.log(Log.ERROR,this,e);
  538. }
  539. } //}}}
  540. //{{{ nextTabStop() method
  541. /**
  542. * Implementation of TabExpander interface. Returns next tab stop after
  543. * a specified point.
  544. * @param x The x co-ordinate
  545. * @param tabOffset Ignored
  546. * @return The next tab stop after <i>x</i>
  547. */
  548. public float nextTabStop(float x, int tabOffset)
  549. {
  550. int offset = textArea.getHorizontalOffset();
  551. int ntabs = ((int)x - offset) / tabSize;
  552. return (ntabs + 1) * tabSize + offset;
  553. } //}}}
  554. //{{{ getPreferredSize() method
  555. /**
  556. * Returns the painter's preferred size.
  557. */
  558. public Dimension getPreferredSize()
  559. {
  560. Dimension dim = new Dimension();
  561. dim.width = fm.charWidth('w') * 80;
  562. dim.height = fm.getHeight() * 25;
  563. return dim;
  564. } //}}}
  565. //{{{ getMinimumSize() method
  566. /**
  567. * Returns the painter's minimum size.
  568. */
  569. public Dimension getMinimumSize()
  570. {
  571. return getPreferredSize();
  572. } //}}}
  573. //{{{ Package-private members
  574. //{{{ updateTabSize() method
  575. void updateTabSize()
  576. {
  577. if(textArea.getBuffer() == null)
  578. return;
  579. tabSize = fm.charWidth(' ') * textArea.getBuffer().getTabSize();
  580. int _maxLineLen = textArea.getBuffer()
  581. .getIntegerProperty("maxLineLen",0);
  582. if(_maxLineLen <= 0)
  583. maxLineLen = 0;
  584. else
  585. maxLineLen = fm.charWidth(' ') * _maxLineLen;
  586. } //}}}
  587. //}}}
  588. //{{{ Private members
  589. //{{{ Instance variables
  590. private JEditTextArea textArea;
  591. private SyntaxStyle[] styles;
  592. private Color caretColor;
  593. private Color selectionColor;
  594. private Color lineHighlightColor;
  595. private Color foldedLineColor;
  596. private Color bracketHighlightColor;
  597. private Color eolMarkerColor;
  598. private Color wrapGuideColor;
  599. private boolean blockCaret;
  600. private boolean lineHighlight;
  601. private boolean bracketHighlight;
  602. private boolean eolMarkers;
  603. private boolean wrapGuide;
  604. private boolean antiAlias;
  605. private boolean fracFontMetrics;
  606. private int tabSize;
  607. private int maxLineLen;
  608. private FontMetrics fm;
  609. private Vector highlights;
  610. //}}}
  611. //{{{ paintLine() method
  612. private int paintLine(Graphics gfx, Buffer buffer, boolean valid,
  613. int virtualLine, int physicalLine, int x, int y,
  614. boolean collapsedFold)
  615. {
  616. paintHighlight(gfx,virtualLine,physicalLine,y,valid,collapsedFold);
  617. if(maxLineLen != 0 && wrapGuide)
  618. {
  619. gfx.setColor(wrapGuideColor);
  620. gfx.drawLine(x + maxLineLen,y,x + maxLineLen,
  621. y + fm.getHeight());
  622. }
  623. if(valid)
  624. {
  625. Font defaultFont = getFont();
  626. Color defaultColor = getForeground();
  627. gfx.setFont(defaultFont);
  628. gfx.setColor(defaultColor);
  629. int baseLine = y + fm.getHeight()
  630. - fm.getLeading() - fm.getDescent();
  631. x = buffer.paintSyntaxLine(physicalLine,gfx,x,baseLine,
  632. this,true,true,defaultFont,defaultColor,
  633. (lineHighlight
  634. && textArea.getSelectionCount() == 0
  635. && physicalLine == textArea.getCaretLine()
  636. ? lineHighlightColor
  637. : getBackground()),styles,
  638. textArea.getTextRenderer());
  639. gfx.setFont(defaultFont);
  640. gfx.setColor(eolMarkerColor);
  641. if(collapsedFold)
  642. {
  643. int nextLine = textArea.getFoldVisibilityManager()
  644. .getNextVisibleLine(physicalLine);
  645. if(nextLine == -1)
  646. nextLine = buffer.getLineCount();
  647. int count = nextLine - physicalLine - 1;
  648. String str = " [" + count + " lines]";
  649. gfx.drawString(str,x,baseLine);
  650. x += fm.stringWidth(str);
  651. }
  652. else if(eolMarkers)
  653. {
  654. gfx.drawString(".",x,baseLine);
  655. x += fm.charWidth('.');
  656. }
  657. if(physicalLine == textArea.getCaretLine()
  658. && textArea.isCaretVisible())
  659. paintCaret(gfx,physicalLine,y,collapsedFold);
  660. }
  661. return x;
  662. } //}}}
  663. //{{{ paintHighlight() method
  664. private void paintHighlight(Graphics gfx, int virtualLine,
  665. int physicalLine, int y, boolean valid,
  666. boolean collapsedFold)
  667. {
  668. if(valid)
  669. {
  670. boolean paintLineHighlight = lineHighlight
  671. && physicalLine == textArea.getCaretLine()
  672. && textArea.selection.size() == 0;
  673. Buffer buffer = textArea.getBuffer();
  674. if(!paintLineHighlight && collapsedFold)
  675. {
  676. gfx.setColor(foldedLineColor);
  677. gfx.fillRect(0,y,getWidth(),fm.getHeight());
  678. }
  679. if(textArea.selection.size() == 0)
  680. {
  681. if(paintLineHighlight)
  682. {
  683. gfx.setColor(lineHighlightColor);
  684. gfx.fillRect(0,y,getWidth(),fm.getHeight());
  685. }
  686. }
  687. else
  688. {
  689. gfx.setColor(selectionColor);
  690. for(int i = textArea.selection.size() - 1;
  691. i >= 0; i--)
  692. {
  693. paintSelection(gfx,physicalLine,y,
  694. (Selection)textArea.selection
  695. .elementAt(i));
  696. }
  697. }
  698. if(bracketHighlight
  699. && physicalLine == textArea.getBracketLine()
  700. && textArea.isBracketHighlightVisible())
  701. paintBracketHighlight(gfx,physicalLine,y);
  702. }
  703. if(highlights.size() != 0)
  704. {
  705. for(int i = 0; i < highlights.size(); i++)
  706. {
  707. TextAreaHighlight highlight = (TextAreaHighlight)
  708. highlights.elementAt(i);
  709. try
  710. {
  711. highlight.paintHighlight(gfx,virtualLine,
  712. y - fm.getLeading() - fm.getDescent());
  713. }
  714. catch(Throwable t)
  715. {
  716. Log.log(Log.ERROR,this,t);
  717. // remove it so editor can continue
  718. // functioning
  719. highlights.removeElementAt(i);
  720. i--;
  721. }
  722. }
  723. }
  724. } //}}}
  725. //{{{ paintBracketHighlight() method
  726. private void paintBracketHighlight(Graphics gfx, int physicalLine, int y)
  727. {
  728. int position = textArea.getBracketPosition();
  729. if(position == -1)
  730. return;
  731. int x = textArea.offsetToX(physicalLine,position);
  732. gfx.setColor(bracketHighlightColor);
  733. // Hack!!! Since there is no fast way to get the character
  734. // from the bracket matching routine, we use ( since all
  735. // brackets probably have the same width anyway
  736. gfx.drawRect(x,y,fm.charWidth('(') - 1,
  737. fm.getHeight() - 1);
  738. } //}}}
  739. //{{{ paintCaret() method
  740. private void paintCaret(Graphics gfx, int physicalLine, int y,
  741. boolean collapsedFold)
  742. {
  743. int offset = textArea.getCaretPosition()
  744. - textArea.getLineStartOffset(physicalLine);
  745. int caretX = textArea.offsetToX(physicalLine,offset);
  746. int height = fm.getHeight();
  747. gfx.setColor(caretColor);
  748. if(textArea.isOverwriteEnabled())
  749. {
  750. gfx.drawLine(caretX,y + height - 1,
  751. caretX + fm.charWidth('w'),y + height - 1);
  752. }
  753. else if(blockCaret)
  754. {
  755. if(collapsedFold)
  756. gfx.setXORMode(foldedLineColor);
  757. else if(textArea.selection == null && lineHighlight)
  758. gfx.setXORMode(lineHighlightColor);
  759. else
  760. gfx.setXORMode(getBackground());
  761. gfx.fillRect(caretX,y,fm.charWidth('w'),height);
  762. gfx.setPaintMode();
  763. }
  764. else
  765. {
  766. gfx.drawLine(caretX,y,caretX,y + height - 1);
  767. }
  768. } //}}}
  769. //{{{ paintSelection() method
  770. private void paintSelection(Graphics gfx, int physicalLine, int y,
  771. Selection s)
  772. {
  773. if(physicalLine < s.startLine || physicalLine > s.endLine)
  774. return;
  775. int lineStart = textArea.getLineStartOffset(physicalLine);
  776. int x1, x2;
  777. if(s instanceof Selection.Rect)
  778. {
  779. int lineLen = textArea.getLineLength(physicalLine);
  780. x1 = textArea.offsetToX(physicalLine,Math.min(lineLen,
  781. s.start - textArea.getLineStartOffset(
  782. s.startLine)));
  783. x2 = textArea.offsetToX(physicalLine,Math.min(lineLen,
  784. s.end - textArea.getLineStartOffset(
  785. s.endLine)));
  786. if(x1 > x2)
  787. {
  788. int tmp = x2;
  789. x2 = x1;
  790. x1 = tmp;
  791. }
  792. }
  793. else if(s.startLine == s.endLine)
  794. {
  795. x1 = textArea.offsetToX(physicalLine,
  796. s.start - lineStart);
  797. x2 = textArea.offsetToX(physicalLine,
  798. s.end - lineStart);
  799. }
  800. else if(physicalLine == s.startLine)
  801. {
  802. x1 = textArea.offsetToX(physicalLine,
  803. s.start - lineStart);
  804. x2 = getWidth();
  805. }
  806. else if(physicalLine == s.endLine)
  807. {
  808. x1 = 0;
  809. x2 = textArea.offsetToX(physicalLine,
  810. s.end - lineStart);
  811. }
  812. else
  813. {
  814. x1 = 0;
  815. x2 = getWidth();
  816. }
  817. if(x1 == x2)
  818. x2++;
  819. gfx.fillRect(x1,y,x2 - x1,fm.getHeight());
  820. } //}}}
  821. //}}}
  822. }