PageRenderTime 62ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

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

#
Java | 1050 lines | 580 code | 130 blank | 340 comment | 89 complexity | 5213ca126863237a3bdeb8afb670bbb9 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  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, 2002 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.font.*;
  28. import java.awt.geom.*;
  29. import java.awt.*;
  30. import java.util.ArrayList;
  31. import java.util.HashMap;
  32. import org.gjt.sp.jedit.syntax.*;
  33. import org.gjt.sp.jedit.Buffer;
  34. import org.gjt.sp.util.Log;
  35. //}}}
  36. /**
  37. * The text area painter is the component responsible for displaying the
  38. * text of the current buffer. The only methods in this class that should
  39. * be called by plugins are those for adding and removing
  40. * text area extensions.
  41. *
  42. * @see #addExtension(TextAreaExtension)
  43. * @see #addExtension(int,TextAreaExtension)
  44. * @see #removeExtension(TextAreaExtension)
  45. * @see TextAreaExtension
  46. * @see JEditTextArea
  47. *
  48. * @author Slava Pestov
  49. * @version $Id: TextAreaPainter.java 4012 2002-02-05 06:28:10Z spestov $
  50. */
  51. public class TextAreaPainter extends JComponent implements TabExpander
  52. {
  53. //{{{ Layers
  54. /**
  55. * The lowest possible layer.
  56. * @see #addExtension(int,TextAreaExtension)
  57. * @since jEdit 4.0pre4
  58. */
  59. public static final int LOWEST_LAYER = Integer.MIN_VALUE;
  60. /**
  61. * Below selection layer. The JDiff plugin will use this.
  62. * @see #addExtension(int,TextAreaExtension)
  63. * @since jEdit 4.0pre4
  64. */
  65. public static final int BELOW_SELECTION_LAYER = -40;
  66. /**
  67. * Selection layer. Most extensions will be above this layer, but some
  68. * (eg, JDiff) will want to be below the selection.
  69. * @see #addExtension(int,TextAreaExtension)
  70. * @since jEdit 4.0pre4
  71. */
  72. public static final int SELECTION_LAYER = -30;
  73. /**
  74. * Wrap guide layer. Most extensions will be above this layer.
  75. * @since jEdit 4.0pre4
  76. */
  77. public static final int WRAP_GUIDE_LAYER = -20;
  78. /**
  79. * Below most extensions layer.
  80. * @see #addExtension(int,TextAreaExtension)
  81. * @since jEdit 4.0pre4
  82. */
  83. public static final int BELOW_MOST_EXTENSIONS_LAYER = -10;
  84. /**
  85. * Default extension layer. This is above the wrap guide but below the
  86. * bracket highlight.
  87. * @since jEdit 4.0pre4
  88. */
  89. public static final int DEFAULT_LAYER = 0;
  90. /**
  91. * Bracket highlight layer. Most extensions will be below this layer.
  92. * @since jEdit 4.0pre4
  93. */
  94. public static final int BRACKET_HIGHLIGHT_LAYER = 100;
  95. /**
  96. * Highest possible layer.
  97. * @since jEdit 4.0pre4
  98. */
  99. public static final int HIGHEST_LAYER = Integer.MAX_VALUE;
  100. //}}}
  101. //{{{ TextAreaPainter constructor
  102. /**
  103. * Creates a new painter. Do not create instances of this class
  104. * directly.
  105. */
  106. public TextAreaPainter(JEditTextArea textArea)
  107. {
  108. enableEvents(AWTEvent.FOCUS_EVENT_MASK
  109. | AWTEvent.KEY_EVENT_MASK
  110. | AWTEvent.MOUSE_EVENT_MASK);
  111. this.textArea = textArea;
  112. extensionMgr = new ExtensionManager();
  113. setAutoscrolls(true);
  114. setOpaque(true);
  115. setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
  116. fontRenderContext = new FontRenderContext(null,false,false);
  117. addExtension(SELECTION_LAYER,new PaintSelection());
  118. addExtension(WRAP_GUIDE_LAYER,new WrapGuide());
  119. addExtension(BRACKET_HIGHLIGHT_LAYER,new BracketHighlight());
  120. } //}}}
  121. //{{{ isManagingFocus() method
  122. /**
  123. * Returns if this component can be traversed by pressing the
  124. * Tab key. This returns false.
  125. */
  126. public boolean isManagingFocus()
  127. {
  128. return false;
  129. } //}}}
  130. //{{{ getFocusTraversalKeysEnabled() method
  131. /**
  132. * Makes the tab key work in Java 1.4.
  133. * @since jEdit 3.2pre4
  134. */
  135. public boolean getFocusTraversalKeysEnabled()
  136. {
  137. return false;
  138. } //}}}
  139. //{{{ Getters and setters
  140. //{{{ getStyles() method
  141. /**
  142. * Returns the syntax styles used to paint colorized text. Entry <i>n</i>
  143. * will be used to paint tokens with id = <i>n</i>.
  144. * @see org.gjt.sp.jedit.syntax.Token
  145. */
  146. public final SyntaxStyle[] getStyles()
  147. {
  148. return styles;
  149. } //}}}
  150. //{{{ setStyles() method
  151. /**
  152. * Sets the syntax styles used to paint colorized text. Entry <i>n</i>
  153. * will be used to paint tokens with id = <i>n</i>.
  154. * @param styles The syntax styles
  155. * @see org.gjt.sp.jedit.syntax.Token
  156. */
  157. public final void setStyles(SyntaxStyle[] styles)
  158. {
  159. this.styles = styles;
  160. styles[Token.NULL] = new SyntaxStyle(getForeground(),null,getFont());
  161. repaint();
  162. } //}}}
  163. //{{{ getCaretColor() method
  164. /**
  165. * Returns the caret color.
  166. */
  167. public final Color getCaretColor()
  168. {
  169. return caretColor;
  170. } //}}}
  171. //{{{ setCaretColor() method
  172. /**
  173. * Sets the caret color.
  174. * @param caretColor The caret color
  175. */
  176. public final void setCaretColor(Color caretColor)
  177. {
  178. this.caretColor = caretColor;
  179. if(textArea.getBuffer() != null)
  180. textArea.invalidateLine(textArea.getCaretLine());
  181. } //}}}
  182. //{{{ getSelectionColor() method
  183. /**
  184. * Returns the selection color.
  185. */
  186. public final Color getSelectionColor()
  187. {
  188. return selectionColor;
  189. } //}}}
  190. //{{{ setSelectionColor() method
  191. /**
  192. * Sets the selection color.
  193. * @param selectionColor The selection color
  194. */
  195. public final void setSelectionColor(Color selectionColor)
  196. {
  197. this.selectionColor = selectionColor;
  198. if(textArea.getBuffer() != null)
  199. textArea.invalidateSelectedLines();
  200. } //}}}
  201. //{{{ getLineHighlightColor() method
  202. /**
  203. * Returns the line highlight color.
  204. */
  205. public final Color getLineHighlightColor()
  206. {
  207. return lineHighlightColor;
  208. } //}}}
  209. //{{{ setLineHighlightColor() method
  210. /**
  211. * Sets the line highlight color.
  212. * @param lineHighlightColor The line highlight color
  213. */
  214. public final void setLineHighlightColor(Color lineHighlightColor)
  215. {
  216. this.lineHighlightColor = lineHighlightColor;
  217. if(textArea.getBuffer() != null)
  218. textArea.invalidateLine(textArea.getCaretLine());
  219. } //}}}
  220. //{{{ isLineHighlightEnabled() method
  221. /**
  222. * Returns true if line highlight is enabled, false otherwise.
  223. */
  224. public final boolean isLineHighlightEnabled()
  225. {
  226. return lineHighlight;
  227. } //}}}
  228. //{{{ setLineHighlightEnabled() method
  229. /**
  230. * Enables or disables current line highlighting.
  231. * @param lineHighlight True if current line highlight should be enabled,
  232. * false otherwise
  233. */
  234. public final void setLineHighlightEnabled(boolean lineHighlight)
  235. {
  236. this.lineHighlight = lineHighlight;
  237. if(textArea.getBuffer() != null)
  238. textArea.invalidateSelectedLines();
  239. } //}}}
  240. //{{{ getFoldedLineColor() method
  241. /**
  242. * Returns the background color of a collapsed fold line.
  243. */
  244. public final Color getFoldedLineColor()
  245. {
  246. return foldedLineColor;
  247. } //}}}
  248. //{{{ setFoldedLineColor() method
  249. /**
  250. * Sets the background color of a collapsed fold line.
  251. * @param foldedLineColor The folded line color
  252. */
  253. public final void setFoldedLineColor(Color foldedLineColor)
  254. {
  255. this.foldedLineColor = foldedLineColor;
  256. repaint();
  257. } //}}}
  258. //{{{ getBracketHighlightColor() method
  259. /**
  260. * Returns the bracket highlight color.
  261. */
  262. public final Color getBracketHighlightColor()
  263. {
  264. return bracketHighlightColor;
  265. } //}}}
  266. //{{{ setBracketHighlightColor() method
  267. /**
  268. * Sets the bracket highlight color.
  269. * @param bracketHighlightColor The bracket highlight color
  270. */
  271. public final void setBracketHighlightColor(Color bracketHighlightColor)
  272. {
  273. this.bracketHighlightColor = bracketHighlightColor;
  274. if(textArea.getBuffer() != null)
  275. textArea.invalidateLine(textArea.getBracketLine());
  276. } //}}}
  277. //{{{ isBracketHighlightEnabled() method
  278. /**
  279. * Returns true if bracket highlighting is enabled, false otherwise.
  280. * When bracket highlighting is enabled, the bracket matching the
  281. * one before the caret (if any) is highlighted.
  282. */
  283. public final boolean isBracketHighlightEnabled()
  284. {
  285. return bracketHighlight;
  286. } //}}}
  287. //{{{ setBracketHighlightEnabled() method
  288. /**
  289. * Enables or disables bracket highlighting.
  290. * When bracket highlighting is enabled, the bracket matching the
  291. * one before the caret (if any) is highlighted.
  292. * @param bracketHighlight True if bracket highlighting should be
  293. * enabled, false otherwise
  294. */
  295. public final void setBracketHighlightEnabled(boolean bracketHighlight)
  296. {
  297. this.bracketHighlight = bracketHighlight;
  298. if(textArea.getBuffer() != null)
  299. textArea.invalidateLine(textArea.getBracketLine());
  300. } //}}}
  301. //{{{ isBlockCaretEnabled() method
  302. /**
  303. * Returns true if the caret should be drawn as a block, false otherwise.
  304. */
  305. public final boolean isBlockCaretEnabled()
  306. {
  307. return blockCaret;
  308. } //}}}
  309. //{{{ setBlockCaretEnabled() method
  310. /**
  311. * Sets if the caret should be drawn as a block, false otherwise.
  312. * @param blockCaret True if the caret should be drawn as a block,
  313. * false otherwise.
  314. */
  315. public final void setBlockCaretEnabled(boolean blockCaret)
  316. {
  317. this.blockCaret = blockCaret;
  318. if(textArea.getBuffer() != null)
  319. textArea.invalidateLine(textArea.getCaretLine());
  320. } //}}}
  321. //{{{ getEOLMarkerColor() method
  322. /**
  323. * Returns the EOL marker color.
  324. */
  325. public final Color getEOLMarkerColor()
  326. {
  327. return eolMarkerColor;
  328. } //}}}
  329. //{{{ setEOLMarkerColor() method
  330. /**
  331. * Sets the EOL marker color.
  332. * @param eolMarkerColor The EOL marker color
  333. */
  334. public final void setEOLMarkerColor(Color eolMarkerColor)
  335. {
  336. this.eolMarkerColor = eolMarkerColor;
  337. repaint();
  338. } //}}}
  339. //{{{ getEOLMarkersPainted() method
  340. /**
  341. * Returns true if EOL markers are drawn, false otherwise.
  342. */
  343. public final boolean getEOLMarkersPainted()
  344. {
  345. return eolMarkers;
  346. } //}}}
  347. //{{{ setEOLMarkersPainted() method
  348. /**
  349. * Sets if EOL markers are to be drawn.
  350. * @param eolMarkers True if EOL markers should be drawn, false otherwise
  351. */
  352. public final void setEOLMarkersPainted(boolean eolMarkers)
  353. {
  354. this.eolMarkers = eolMarkers;
  355. repaint();
  356. } //}}}
  357. //{{{ getWrapGuideColor() method
  358. /**
  359. * Returns the wrap guide color.
  360. */
  361. public final Color getWrapGuideColor()
  362. {
  363. return wrapGuideColor;
  364. } //}}}
  365. //{{{ setWrapGuideColor() method
  366. /**
  367. * Sets the wrap guide color.
  368. * @param wrapGuideColor The wrap guide color
  369. */
  370. public final void setWrapGuideColor(Color wrapGuideColor)
  371. {
  372. this.wrapGuideColor = wrapGuideColor;
  373. repaint();
  374. } //}}}
  375. //{{{ isWrapGuidePainted() method
  376. /**
  377. * Returns true if the wrap guide is drawn, false otherwise.
  378. * @since jEdit 4.0pre4
  379. */
  380. public final boolean isWrapGuidePainted()
  381. {
  382. return wrapGuide;
  383. } //}}}
  384. //{{{ setWrapGuidePainted() method
  385. /**
  386. * Sets if the wrap guide is to be drawn.
  387. * @param wrapGuide True if the wrap guide should be drawn, false otherwise
  388. */
  389. public final void setWrapGuidePainted(boolean wrapGuide)
  390. {
  391. this.wrapGuide = wrapGuide;
  392. repaint();
  393. } //}}}
  394. //{{{ setAntiAliasEnabled() method
  395. /**
  396. * Sets if anti-aliasing should be enabled. Has no effect when
  397. * running on Java 1.1.
  398. * @since jEdit 3.2pre6
  399. */
  400. public void setAntiAliasEnabled(boolean antiAlias)
  401. {
  402. this.antiAlias = antiAlias;
  403. updateRenderingHints();
  404. } //}}}
  405. //{{{ isAntiAliasEnabled() method
  406. /**
  407. * Returns if anti-aliasing is enabled.
  408. * @since jEdit 3.2pre6
  409. */
  410. public boolean isAntiAliasEnabled()
  411. {
  412. return antiAlias;
  413. } //}}}
  414. //{{{ setFractionalFontMetricsEnabled() method
  415. /**
  416. * Sets if fractional font metrics should be enabled. Has no effect when
  417. * running on Java 1.1.
  418. * @since jEdit 3.2pre6
  419. */
  420. public void setFractionalFontMetricsEnabled(boolean fracFontMetrics)
  421. {
  422. this.fracFontMetrics = fracFontMetrics;
  423. updateRenderingHints();
  424. } //}}}
  425. //{{{ isFractionalFontMetricsEnabled() method
  426. /**
  427. * Returns if fractional font metrics are enabled.
  428. * @since jEdit 3.2pre6
  429. */
  430. public boolean isFractionalFontMetricsEnabled()
  431. {
  432. return fracFontMetrics;
  433. } //}}}
  434. //{{{ getFontRenderContext() method
  435. /**
  436. * Returns the font render context.
  437. * @since jEdit 4.0pre4
  438. */
  439. public FontRenderContext getFontRenderContext()
  440. {
  441. return fontRenderContext;
  442. } //}}}
  443. //}}}
  444. //{{{ addCustomHighlight() method
  445. /**
  446. * @deprecated Write a <code>TextAreaExtension</code> instead.
  447. */
  448. public void addCustomHighlight(TextAreaHighlight highlight)
  449. {
  450. Log.log(Log.WARNING,this,"Old highlighter API not supported: "
  451. + highlight);
  452. } //}}}
  453. //{{{ removeCustomHighlight() method
  454. /**
  455. * @deprecated Write a <code>TextAreaExtension</code> instead.
  456. */
  457. public void removeCustomHighlight(TextAreaHighlight highlight)
  458. {
  459. Log.log(Log.WARNING,this,"Old highlighter API not supported: "
  460. + highlight);
  461. } //}}}
  462. //{{{ addExtension() method
  463. /**
  464. * Adds a text area extension, which can perform custom painting and
  465. * tool tip handling.
  466. * @param extension The extension
  467. * @since jEdit 4.0pre4
  468. */
  469. public void addExtension(TextAreaExtension extension)
  470. {
  471. extensionMgr.addExtension(DEFAULT_LAYER,extension);
  472. repaint();
  473. } //}}}
  474. //{{{ addExtension() method
  475. /**
  476. * Adds a text area extension, which can perform custom painting and
  477. * tool tip handling.
  478. * @param layer The layer to add the extension to. Note that more than
  479. * extension can share the same layer.
  480. * @param extension The extension
  481. * @since jEdit 4.0pre4
  482. */
  483. public void addExtension(int layer, TextAreaExtension extension)
  484. {
  485. extensionMgr.addExtension(layer,extension);
  486. repaint();
  487. } //}}}
  488. //{{{ removeExtension() method
  489. /**
  490. * Removes a text area extension. It will no longer be asked to
  491. * perform custom painting and tool tip handling.
  492. * @param extension The extension
  493. * @since jEdit 4.0pre4
  494. */
  495. public void removeExtension(TextAreaExtension extension)
  496. {
  497. extensionMgr.removeExtension(extension);
  498. repaint();
  499. } //}}}
  500. //{{{ getToolTipText() method
  501. /**
  502. * Returns the tool tip to display at the specified location.
  503. * @param evt The mouse event
  504. */
  505. public String getToolTipText(MouseEvent evt)
  506. {
  507. if(!textArea.getBuffer().isLoaded())
  508. return null;
  509. return extensionMgr.getToolTipText(evt.getX(),evt.getY());
  510. } //}}}
  511. //{{{ getFontMetrics() method
  512. /**
  513. * Returns the font metrics used by this component.
  514. */
  515. public FontMetrics getFontMetrics()
  516. {
  517. return fm;
  518. } //}}}
  519. //{{{ setFont() method
  520. /**
  521. * Sets the font for this component. This is overridden to update the
  522. * cached font metrics and to recalculate which lines are visible.
  523. * @param font The font
  524. */
  525. public void setFont(Font font)
  526. {
  527. super.setFont(font);
  528. fm = getFontMetrics(font);
  529. textArea.recalculateVisibleLines();
  530. } //}}}
  531. //{{{ paintComponent() method
  532. /**
  533. * Repaints the text.
  534. * @param g The graphics context
  535. */
  536. public void paintComponent(Graphics _gfx)
  537. {
  538. Graphics2D gfx = (Graphics2D)_gfx;
  539. gfx.setRenderingHints(renderingHints);
  540. fontRenderContext = gfx.getFontRenderContext();
  541. Rectangle clipRect = gfx.getClipBounds();
  542. gfx.setColor(getBackground());
  543. gfx.fillRect(clipRect.x,clipRect.y,clipRect.width,clipRect.height);
  544. Buffer buffer = textArea.getBuffer();
  545. if(!buffer.isLoaded())
  546. return;
  547. int x = textArea.getHorizontalOffset();
  548. int height = fm.getHeight();
  549. int firstInvalid = clipRect.y / height;
  550. // Because the clipRect's height is usually an even multiple
  551. // of the font height, we subtract 1 from it, otherwise one
  552. // too many lines will always be painted.
  553. int lastInvalid = (clipRect.y + clipRect.height - 1) / height;
  554. textArea.chunkCache.updateChunksUpTo(lastInvalid);
  555. int lineCount = textArea.getVirtualLineCount();
  556. int y = (clipRect.y - clipRect.y % height);
  557. try
  558. {
  559. boolean updateMaxHorizontalScrollWidth = false;
  560. for(int line = firstInvalid; line <= lastInvalid; line++)
  561. {
  562. ChunkCache.LineInfo lineInfo = textArea.chunkCache
  563. .getLineInfo(line);
  564. if(!lineInfo.chunksValid)
  565. System.err.println("text area painter: not valid");
  566. lineInfo.width = paintLine(gfx,buffer,lineInfo,line,x,y) - x;
  567. if(lineInfo.width > textArea.maxHorizontalScrollWidth)
  568. updateMaxHorizontalScrollWidth = true;
  569. y += height;
  570. }
  571. if(buffer.isNextLineRequested())
  572. {
  573. int h = clipRect.y + clipRect.height;
  574. textArea.chunkCache.invalidateChunksFrom(lastInvalid + 1);
  575. repaint(0,h,getWidth(),getHeight() - h);
  576. }
  577. if(updateMaxHorizontalScrollWidth)
  578. textArea.updateMaxHorizontalScrollWidth();
  579. }
  580. catch(Exception e)
  581. {
  582. Log.log(Log.ERROR,this,"Error repainting line"
  583. + " range {" + firstInvalid + ","
  584. + lastInvalid + "}:");
  585. Log.log(Log.ERROR,this,e);
  586. }
  587. } //}}}
  588. //{{{ nextTabStop() method
  589. /**
  590. * Implementation of TabExpander interface. Returns next tab stop after
  591. * a specified point.
  592. * @param x The x co-ordinate
  593. * @param tabOffset Ignored
  594. * @return The next tab stop after <i>x</i>
  595. */
  596. public float nextTabStop(float x, int tabOffset)
  597. {
  598. int ntabs = (int)(x / textArea.tabSize);
  599. return (ntabs + 1) * textArea.tabSize;
  600. } //}}}
  601. //{{{ getPreferredSize() method
  602. /**
  603. * Returns the painter's preferred size.
  604. */
  605. public Dimension getPreferredSize()
  606. {
  607. Dimension dim = new Dimension();
  608. char[] foo = new char[80];
  609. for(int i = 0; i < foo.length; i++)
  610. foo[i] = ' ';
  611. dim.width = (int)(getFont().getStringBounds(foo,0,foo.length,
  612. fontRenderContext).getWidth());
  613. dim.height = fm.getHeight() * 25;
  614. return dim;
  615. } //}}}
  616. //{{{ getMinimumSize() method
  617. /**
  618. * Returns the painter's minimum size.
  619. */
  620. public Dimension getMinimumSize()
  621. {
  622. return getPreferredSize();
  623. } //}}}
  624. //{{{ Private members
  625. //{{{ Instance variables
  626. private JEditTextArea textArea;
  627. private SyntaxStyle[] styles;
  628. private Color caretColor;
  629. private Color selectionColor;
  630. private Color lineHighlightColor;
  631. private Color foldedLineColor;
  632. private Color bracketHighlightColor;
  633. private Color eolMarkerColor;
  634. private Color wrapGuideColor;
  635. private boolean blockCaret;
  636. private boolean lineHighlight;
  637. private boolean bracketHighlight;
  638. private boolean eolMarkers;
  639. private boolean wrapGuide;
  640. private boolean antiAlias;
  641. private boolean fracFontMetrics;
  642. // should try to use this as little as possible.
  643. private FontMetrics fm;
  644. private ExtensionManager extensionMgr;
  645. private RenderingHints renderingHints;
  646. private FontRenderContext fontRenderContext;
  647. //}}}
  648. //{{{ updateRenderingHints() method
  649. private void updateRenderingHints()
  650. {
  651. HashMap hints = new HashMap();
  652. if(antiAlias)
  653. {
  654. hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
  655. hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  656. hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
  657. }
  658. else
  659. {
  660. hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
  661. hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
  662. }
  663. hints.put(RenderingHints.KEY_FRACTIONALMETRICS,
  664. fracFontMetrics ?
  665. RenderingHints.VALUE_FRACTIONALMETRICS_ON
  666. : RenderingHints.VALUE_FRACTIONALMETRICS_OFF);
  667. renderingHints = new RenderingHints(hints);
  668. fontRenderContext = new FontRenderContext(null,antiAlias,
  669. fracFontMetrics);
  670. } //}}}
  671. //{{{ paintLine() method
  672. private int paintLine(Graphics2D gfx, Buffer buffer,
  673. ChunkCache.LineInfo lineInfo, int screenLine,
  674. int x, int y)
  675. {
  676. int physicalLine = lineInfo.physicalLine;
  677. if(physicalLine == -1)
  678. extensionMgr.paintInvalidLine(gfx,screenLine,y);
  679. else
  680. {
  681. boolean collapsedFold = (physicalLine < buffer.getLineCount() - 1
  682. && buffer.isFoldStart(physicalLine)
  683. && !textArea.getFoldVisibilityManager()
  684. .isLineVisible(physicalLine + 1)
  685. && lineInfo.firstSubregion);
  686. int start = textArea.getScreenLineStartOffset(screenLine);
  687. int end = textArea.getScreenLineEndOffset(screenLine);
  688. int caret = textArea.getCaretPosition();
  689. boolean paintLineHighlight = lineHighlight
  690. && caret >= start && caret < end
  691. && textArea.selection.size() == 0;
  692. Color bgColor;
  693. if(paintLineHighlight)
  694. bgColor = lineHighlightColor;
  695. else if(collapsedFold)
  696. bgColor = foldedLineColor;
  697. else
  698. bgColor = getBackground();
  699. if(paintLineHighlight || collapsedFold)
  700. {
  701. gfx.setColor(bgColor);
  702. gfx.fillRect(0,y,getWidth(),fm.getHeight());
  703. }
  704. extensionMgr.paintValidLine(gfx,screenLine,physicalLine,
  705. start,end,y);
  706. Font defaultFont = getFont();
  707. Color defaultColor = getForeground();
  708. gfx.setFont(defaultFont);
  709. gfx.setColor(defaultColor);
  710. float baseLine = y + fm.getHeight()
  711. - fm.getLeading() - fm.getDescent();
  712. if(lineInfo.chunks != null)
  713. {
  714. x += ChunkCache.paintChunkList(
  715. lineInfo.chunks,gfx,x,baseLine,
  716. getWidth(),bgColor,true);
  717. }
  718. gfx.setFont(defaultFont);
  719. gfx.setColor(eolMarkerColor);
  720. if(!lineInfo.lastSubregion)
  721. {
  722. gfx.drawString(":",Math.max(x,
  723. textArea.getHorizontalOffset()
  724. + textArea.wrapMargin),
  725. baseLine);
  726. x += textArea.charWidth;
  727. }
  728. else if(collapsedFold)
  729. {
  730. int nextLine = textArea.getFoldVisibilityManager()
  731. .getNextVisibleLine(physicalLine);
  732. if(nextLine == -1)
  733. nextLine = buffer.getLineCount();
  734. int count = nextLine - physicalLine - 1;
  735. String str = " [" + count + " lines]";
  736. gfx.drawString(str,x,baseLine);
  737. x += (int)(getFont().getStringBounds(
  738. str,fontRenderContext)
  739. .getWidth());
  740. }
  741. else if(eolMarkers)
  742. {
  743. gfx.drawString(".",x,baseLine);
  744. x += textArea.charWidth;
  745. }
  746. paintCaret(gfx,physicalLine,start,end,y,bgColor);
  747. }
  748. return x;
  749. } //}}}
  750. //{{{ paintCaret() method
  751. private void paintCaret(Graphics2D gfx, int physicalLine,
  752. int start, int end, int y, Color bgColor)
  753. {
  754. if(!textArea.isCaretVisible())
  755. return;
  756. int caret = textArea.getCaretPosition();
  757. if(caret < start || caret >= end)
  758. return;
  759. int offset = caret - textArea.getLineStartOffset(physicalLine);
  760. textArea.offsetToXY(physicalLine,offset,textArea.returnValue);
  761. int caretX = textArea.returnValue.x;
  762. int height = fm.getHeight();
  763. gfx.setColor(caretColor);
  764. if(textArea.isOverwriteEnabled())
  765. {
  766. gfx.drawLine(caretX,y + height - 1,
  767. caretX + textArea.charWidth,y + height - 1);
  768. }
  769. else if(blockCaret)
  770. {
  771. // Workaround for bug in Graphics2D in JDK1.4 under
  772. // Windows; calling setPaintMode() does not reset
  773. // graphics mode.
  774. Graphics2D blockgfx = (Graphics2D)gfx.create();
  775. blockgfx.setXORMode(bgColor);
  776. blockgfx.fillRect(caretX,y,textArea.charWidth,height);
  777. blockgfx.dispose();
  778. }
  779. else
  780. {
  781. gfx.drawLine(caretX,y,caretX,y + height - 1);
  782. }
  783. } //}}}
  784. //}}}
  785. //{{{ PaintSelection class
  786. class PaintSelection extends TextAreaExtension
  787. {
  788. //{{{ paintValidLine() method
  789. public void paintValidLine(Graphics2D gfx, int screenLine,
  790. int physicalLine, int start, int end, int y)
  791. {
  792. if(textArea.selection.size() == 0)
  793. return;
  794. gfx.setColor(getSelectionColor());
  795. for(int i = textArea.selection.size() - 1;
  796. i >= 0; i--)
  797. {
  798. paintSelection(gfx,screenLine,
  799. physicalLine,start,end,y,
  800. (Selection)textArea.selection
  801. .get(i));
  802. }
  803. } //}}}
  804. //{{{ paintSelection() method
  805. private void paintSelection(Graphics2D gfx, int screenLine,
  806. int physicalLine, int start, int end, int y, Selection s)
  807. {
  808. if(end <= s.start || start > s.end)
  809. return;
  810. int selStartScreenLine = textArea.getScreenLineOfOffset(s.start);
  811. int selEndScreenLine = textArea.getScreenLineOfOffset(s.end);
  812. int lineStart = textArea.getLineStartOffset(physicalLine);
  813. int x1, x2;
  814. if(s instanceof Selection.Rect)
  815. {
  816. int lineLen = textArea.getLineLength(physicalLine);
  817. x1 = textArea.offsetToXY(physicalLine,Math.min(lineLen,
  818. s.start - textArea.getLineStartOffset(
  819. s.startLine)),textArea.returnValue).x;
  820. x2 = textArea.offsetToXY(physicalLine,Math.min(lineLen,
  821. s.end - textArea.getLineStartOffset(
  822. s.endLine)),textArea.returnValue).x;
  823. if(x1 > x2)
  824. {
  825. int tmp = x2;
  826. x2 = x1;
  827. x1 = tmp;
  828. }
  829. }
  830. else if(selStartScreenLine == selEndScreenLine
  831. && selStartScreenLine != -1)
  832. {
  833. x1 = textArea.offsetToXY(physicalLine,
  834. s.start - lineStart,textArea.returnValue).x;
  835. x2 = textArea.offsetToXY(physicalLine,
  836. s.end - lineStart,textArea.returnValue).x;
  837. }
  838. else if(screenLine == selStartScreenLine)
  839. {
  840. x1 = textArea.offsetToXY(physicalLine,
  841. s.start - lineStart,textArea.returnValue).x;
  842. x2 = getWidth();
  843. }
  844. else if(screenLine == selEndScreenLine)
  845. {
  846. x1 = 0;
  847. x2 = textArea.offsetToXY(physicalLine,
  848. s.end - lineStart,textArea.returnValue).x;
  849. }
  850. else
  851. {
  852. x1 = 0;
  853. x2 = getWidth();
  854. }
  855. if(x1 == x2)
  856. x2++;
  857. gfx.fillRect(x1,y,x2 - x1,fm.getHeight());
  858. } //}}}
  859. } //}}}
  860. //{{{ WrapGuide class
  861. class WrapGuide extends TextAreaExtension
  862. {
  863. public void paintValidLine(Graphics2D gfx, int screenLine,
  864. int physicalLine, int start, int end, int y)
  865. {
  866. paintInvalidLine(gfx,screenLine,y);
  867. }
  868. public void paintInvalidLine(Graphics2D gfx, int screenLine, int y)
  869. {
  870. if(!textArea.wrapToWidth && textArea.wrapMargin != 0
  871. && isWrapGuidePainted())
  872. {
  873. gfx.setColor(getWrapGuideColor());
  874. int x = textArea.getHorizontalOffset() + textArea.wrapMargin;
  875. gfx.drawLine(x,y,x,y + fm.getHeight());
  876. }
  877. }
  878. public String getToolTipText(int x, int y)
  879. {
  880. if(!textArea.wrapToWidth && textArea.wrapMargin != 0
  881. && isWrapGuidePainted())
  882. {
  883. int wrapGuidePos = textArea.wrapMargin
  884. + textArea.getHorizontalOffset();
  885. if(Math.abs(x - wrapGuidePos) < 5)
  886. {
  887. return String.valueOf(textArea.getBuffer()
  888. .getProperty("maxLineLen"));
  889. }
  890. }
  891. return null;
  892. }
  893. } //}}}
  894. //{{{ BracketHighlight class
  895. class BracketHighlight extends TextAreaExtension
  896. {
  897. public void paintValidLine(Graphics2D gfx, int screenLine,
  898. int physicalLine, int start, int end, int y)
  899. {
  900. if(!isBracketHighlightEnabled() || !textArea.isBracketHighlightVisible())
  901. return;
  902. int bracketLine = textArea.getBracketLine();
  903. int bracketOffset = textArea.getBracketPosition();
  904. if(bracketLine == -1 || bracketOffset == -1)
  905. return;
  906. int bracketLineStart = textArea.getLineStartOffset(bracketLine);
  907. if(bracketOffset + bracketLineStart < start
  908. || bracketOffset + bracketLineStart >= end)
  909. return;
  910. textArea.offsetToXY(bracketLine,bracketOffset,textArea.returnValue);
  911. gfx.setColor(getBracketHighlightColor());
  912. // Hack!!! Since there is no fast way to get the character
  913. // from the bracket matching routine, we use ( since all
  914. // brackets probably have the same width anyway
  915. gfx.drawRect(textArea.returnValue.x,y,(int)gfx.getFont().getStringBounds(
  916. "(",getFontRenderContext()).getWidth() - 1,
  917. fm.getHeight() - 1);
  918. }
  919. } //}}}
  920. }