KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jedit > syntax > TextAreaPainter


1 package org.jedit.syntax;
2
3 /*
4  * TextAreaPainter.java - Paints the text area
5  * Copyright (C) 1999 Slava Pestov
6  *
7  * You may use and modify this package for any purpose. Redistribution is
8  * permitted, in both source and binary form, provided that this notice
9  * remains intact in all source distributions of this package.
10  */

11
12 import javax.swing.ToolTipManager JavaDoc;
13 import javax.swing.text.*;
14 import javax.swing.JComponent JavaDoc;
15 import java.awt.event.MouseEvent JavaDoc;
16 import java.awt.*;
17
18 /**
19  * The text area repaint manager. It performs double buffering and paints
20  * lines of text.
21  * @author Slava Pestov
22  * @version $Id: TextAreaPainter.java,v 1.1 2003/12/14 16:29:49 daggerrz Exp $
23  */

24 public class TextAreaPainter extends JComponent JavaDoc implements TabExpander
25 {
26    /**
27     * Creates a new repaint manager. This should be not be called
28     * directly.
29     */

30    public TextAreaPainter(JEditTextArea textArea, TextAreaDefaults defaults)
31    {
32       this.textArea = textArea;
33
34       setAutoscrolls(true);
35       setDoubleBuffered(true);
36       setOpaque(true);
37
38       ToolTipManager.sharedInstance().registerComponent(this);
39
40       currentLine = new Segment();
41       currentLineIndex = -1;
42
43       setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
44
45       setFont(new Font("Monospaced",Font.PLAIN,14));
46       setForeground(Color.black);
47       setBackground(Color.white);
48
49       blockCaret = defaults.blockCaret;
50       styles = defaults.styles;
51       cols = defaults.cols;
52       rows = defaults.rows;
53       caretColor = defaults.caretColor;
54       selectionColor = defaults.selectionColor;
55       lineHighlightColor = defaults.lineHighlightColor;
56       lineHighlight = defaults.lineHighlight;
57       bracketHighlightColor = defaults.bracketHighlightColor;
58       bracketHighlight = defaults.bracketHighlight;
59       paintInvalid = defaults.paintInvalid;
60       eolMarkerColor = defaults.eolMarkerColor;
61       eolMarkers = defaults.eolMarkers;
62    }
63
64    /**
65     * Returns if this component can be traversed by pressing the
66     * Tab key. This returns false.
67     */

68    public final boolean isManagingFocus()
69    {
70       return false;
71    }
72
73    /**
74     * Returns the syntax styles used to paint colorized text. Entry <i>n</i>
75     * will be used to paint tokens with id = <i>n</i>.
76     * @see org.gjt.sp.jedit.syntax.Token
77     */

78    public final SyntaxStyle[] getStyles()
79    {
80       return styles;
81    }
82
83    /**
84     * Sets the syntax styles used to paint colorized text. Entry <i>n</i>
85     * will be used to paint tokens with id = <i>n</i>.
86     * @param styles The syntax styles
87     * @see org.gjt.sp.jedit.syntax.Token
88     */

89    public final void setStyles(SyntaxStyle[] styles)
90    {
91       this.styles = styles;
92       repaint();
93    }
94
95    /**
96     * Returns the caret color.
97     */

98    public final Color getCaretColor()
99    {
100       return caretColor;
101    }
102
103    /**
104     * Sets the caret color.
105     * @param caretColor The caret color
106     */

107    public final void setCaretColor(Color caretColor)
108    {
109       this.caretColor = caretColor;
110       invalidateSelectedLines();
111    }
112
113    /**
114     * Returns the selection color.
115     */

116    public final Color getSelectionColor()
117    {
118       return selectionColor;
119    }
120
121    /**
122     * Sets the selection color.
123     * @param selectionColor The selection color
124     */

125    public final void setSelectionColor(Color selectionColor)
126    {
127       this.selectionColor = selectionColor;
128       invalidateSelectedLines();
129    }
130
131    /**
132     * Returns the line highlight color.
133     */

134    public final Color getLineHighlightColor()
135    {
136       return lineHighlightColor;
137    }
138
139    /**
140     * Sets the line highlight color.
141     * @param lineHighlightColor The line highlight color
142     */

143    public final void setLineHighlightColor(Color lineHighlightColor)
144    {
145       this.lineHighlightColor = lineHighlightColor;
146       invalidateSelectedLines();
147    }
148
149    /**
150     * Returns true if line highlight is enabled, false otherwise.
151     */

152    public final boolean isLineHighlightEnabled()
153    {
154       return lineHighlight;
155    }
156
157    /**
158     * Enables or disables current line highlighting.
159     * @param lineHighlight True if current line highlight should be enabled,
160     * false otherwise
161     */

162    public final void setLineHighlightEnabled(boolean lineHighlight)
163    {
164       this.lineHighlight = lineHighlight;
165       invalidateSelectedLines();
166    }
167
168    /**
169     * Returns the bracket highlight color.
170     */

171    public final Color getBracketHighlightColor()
172    {
173       return bracketHighlightColor;
174    }
175
176    /**
177     * Sets the bracket highlight color.
178     * @param bracketHighlightColor The bracket highlight color
179     */

180    public final void setBracketHighlightColor(Color bracketHighlightColor)
181    {
182       this.bracketHighlightColor = bracketHighlightColor;
183       invalidateLine(textArea.getBracketLine());
184    }
185
186    /**
187     * Returns true if bracket highlighting is enabled, false otherwise.
188     * When bracket highlighting is enabled, the bracket matching the
189     * one before the caret (if any) is highlighted.
190     */

191    public final boolean isBracketHighlightEnabled()
192    {
193       return bracketHighlight;
194    }
195
196    /**
197     * Enables or disables bracket highlighting.
198     * When bracket highlighting is enabled, the bracket matching the
199     * one before the caret (if any) is highlighted.
200     * @param bracketHighlight True if bracket highlighting should be
201     * enabled, false otherwise
202     */

203    public final void setBracketHighlightEnabled(boolean bracketHighlight)
204    {
205       this.bracketHighlight = bracketHighlight;
206       invalidateLine(textArea.getBracketLine());
207    }
208
209    /**
210     * Returns true if the caret should be drawn as a block, false otherwise.
211     */

212    public final boolean isBlockCaretEnabled()
213    {
214       return blockCaret;
215    }
216
217    /**
218     * Sets if the caret should be drawn as a block, false otherwise.
219     * @param blockCaret True if the caret should be drawn as a block,
220     * false otherwise.
221     */

222    public final void setBlockCaretEnabled(boolean blockCaret)
223    {
224       this.blockCaret = blockCaret;
225       invalidateSelectedLines();
226    }
227
228    /**
229     * Returns the EOL marker color.
230     */

231    public final Color getEOLMarkerColor()
232    {
233       return eolMarkerColor;
234    }
235
236    /**
237     * Sets the EOL marker color.
238     * @param eolMarkerColor The EOL marker color
239     */

240    public final void setEOLMarkerColor(Color eolMarkerColor)
241    {
242       this.eolMarkerColor = eolMarkerColor;
243       repaint();
244    }
245
246    /**
247     * Returns true if EOL markers are drawn, false otherwise.
248     */

249    public final boolean getEOLMarkersPainted()
250    {
251       return eolMarkers;
252    }
253
254    /**
255     * Sets if EOL markers are to be drawn.
256     * @param eolMarkers True if EOL markers should be drawn, false otherwise
257     */

258    public final void setEOLMarkersPainted(boolean eolMarkers)
259    {
260       this.eolMarkers = eolMarkers;
261       repaint();
262    }
263
264    /**
265     * Returns true if invalid lines are painted as red tildes (~),
266     * false otherwise.
267     */

268    public boolean getInvalidLinesPainted()
269    {
270       return paintInvalid;
271    }
272
273    /**
274     * Sets if invalid lines are to be painted as red tildes.
275     * @param paintInvalid True if invalid lines should be drawn, false otherwise
276     */

277    public void setInvalidLinesPainted(boolean paintInvalid)
278    {
279       this.paintInvalid = paintInvalid;
280    }
281
282    /**
283     * Adds a custom highlight painter.
284     * @param highlight The highlight
285     */

286    public void addCustomHighlight(Highlight highlight)
287    {
288       highlight.init(textArea,highlights);
289       highlights = highlight;
290    }
291
292    /**
293     * Highlight interface.
294     */

295    public interface Highlight
296    {
297       /**
298        * Called after the highlight painter has been added.
299        * @param textArea The text area
300        * @param next The painter this one should delegate to
301        */

302       void init(JEditTextArea textArea, Highlight next);
303
304       /**
305        * This should paint the highlight and delgate to the
306        * next highlight painter.
307        * @param gfx The graphics context
308        * @param line The line number
309        * @param y The y co-ordinate of the line
310        */

311       void paintHighlight(Graphics gfx, int line, int y);
312
313       /**
314        * Returns the tool tip to display at the specified
315        * location. If this highlighter doesn't know what to
316        * display, it should delegate to the next highlight
317        * painter.
318        * @param evt The mouse event
319        */

320       String JavaDoc getToolTipText(MouseEvent JavaDoc evt);
321    }
322
323    /**
324     * Returns the tool tip to display at the specified location.
325     * @param evt The mouse event
326     */

327    public String JavaDoc getToolTipText(MouseEvent JavaDoc evt)
328    {
329       if(highlights != null)
330          return highlights.getToolTipText(evt);
331       else
332          return null;
333    }
334
335    /**
336     * Returns the font metrics used by this component.
337     */

338    public FontMetrics getFontMetrics()
339    {
340       return fm;
341    }
342
343    /**
344     * Sets the font for this component. This is overridden to update the
345     * cached font metrics and to recalculate which lines are visible.
346     * @param font The font
347     */

348    public void setFont(Font font)
349    {
350       super.setFont(font);
351       fm = Toolkit.getDefaultToolkit().getFontMetrics(font);
352       textArea.recalculateVisibleLines();
353    }
354
355    /**
356     * Repaints the text.
357     * @param g The graphics context
358     */

359    public void paint(Graphics gfx)
360    {
361       tabSize = fm.charWidth(' ') * ((Integer JavaDoc)textArea
362          .getDocument().getProperty(
363          PlainDocument.tabSizeAttribute)).intValue();
364
365       Rectangle clipRect = gfx.getClipBounds();
366
367       gfx.setColor(getBackground());
368       gfx.fillRect(clipRect.x,clipRect.y,clipRect.width,clipRect.height);
369
370       // We don't use yToLine() here because that method doesn't
371
// return lines past the end of the document
372
int height = fm.getHeight();
373       int firstLine = textArea.getFirstLine();
374       int firstInvalid = firstLine + clipRect.y / height;
375       // Because the clipRect's height is usually an even multiple
376
// of the font height, we subtract 1 from it, otherwise one
377
// too many lines will always be painted.
378
int lastInvalid = firstLine + (clipRect.y + clipRect.height - 1) / height;
379
380       try
381       {
382          TokenMarker tokenMarker = textArea.getDocument()
383             .getTokenMarker();
384          int x = textArea.getHorizontalOffset();
385
386          for(int line = firstInvalid; line <= lastInvalid; line++)
387          {
388             paintLine(gfx,tokenMarker,line,x);
389          }
390
391          if(tokenMarker != null && tokenMarker.isNextLineRequested())
392          {
393             int h = clipRect.y + clipRect.height;
394             repaint(0,h,getWidth(),getHeight() - h);
395          }
396       }
397       catch(Exception JavaDoc e)
398       {
399          System.err.println("Error repainting line"
400             + " range {" + firstInvalid + ","
401             + lastInvalid + "}:");
402          e.printStackTrace();
403       }
404    }
405
406    /**
407     * Marks a line as needing a repaint.
408     * @param line The line to invalidate
409     */

410    public final void invalidateLine(int line)
411    {
412       repaint(0,textArea.lineToY(line) + fm.getMaxDescent() + fm.getLeading(),
413          getWidth(),fm.getHeight());
414    }
415
416    /**
417     * Marks a range of lines as needing a repaint.
418     * @param firstLine The first line to invalidate
419     * @param lastLine The last line to invalidate
420     */

421    public final void invalidateLineRange(int firstLine, int lastLine)
422    {
423       repaint(0,textArea.lineToY(firstLine) + fm.getMaxDescent() + fm.getLeading(),
424          getWidth(),(lastLine - firstLine + 1) * fm.getHeight());
425    }
426
427    /**
428     * Repaints the lines containing the selection.
429     */

430    public final void invalidateSelectedLines()
431    {
432       invalidateLineRange(textArea.getSelectionStartLine(),
433          textArea.getSelectionEndLine());
434    }
435
436    /**
437     * Implementation of TabExpander interface. Returns next tab stop after
438     * a specified point.
439     * @param x The x co-ordinate
440     * @param tabOffset Ignored
441     * @return The next tab stop after <i>x</i>
442     */

443    public float nextTabStop(float x, int tabOffset)
444    {
445       int offset = textArea.getHorizontalOffset();
446       int ntabs = ((int)x - offset) / tabSize;
447       return (ntabs + 1) * tabSize + offset;
448    }
449
450    /**
451     * Returns the painter's preferred size.
452     */

453    public Dimension getPreferredSize()
454    {
455       Dimension dim = new Dimension();
456       dim.width = fm.charWidth('w') * cols;
457       dim.height = fm.getHeight() * rows;
458       return dim;
459    }
460
461
462    /**
463     * Returns the painter's minimum size.
464     */

465    public Dimension getMinimumSize()
466    {
467       return getPreferredSize();
468    }
469
470    // package-private members
471
int currentLineIndex;
472    Token currentLineTokens;
473    Segment currentLine;
474
475    // protected members
476
protected JEditTextArea textArea;
477    
478    protected SyntaxStyle[] styles;
479    protected Color caretColor;
480    protected Color selectionColor;
481    protected Color lineHighlightColor;
482    protected Color bracketHighlightColor;
483    protected Color eolMarkerColor;
484
485    protected boolean blockCaret;
486    protected boolean lineHighlight;
487    protected boolean bracketHighlight;
488    protected boolean paintInvalid;
489    protected boolean eolMarkers;
490    protected int cols;
491    protected int rows;
492    
493    protected int tabSize;
494    protected FontMetrics fm;
495
496    protected Highlight highlights;
497
498    protected void paintLine(Graphics gfx, TokenMarker tokenMarker,
499       int line, int x)
500    {
501       Font defaultFont = getFont();
502       Color defaultColor = getForeground();
503
504       currentLineIndex = line;
505       int y = textArea.lineToY(line);
506
507       if(line < 0 || line >= textArea.getLineCount())
508       {
509          if(paintInvalid)
510          {
511             paintHighlight(gfx,line,y);
512             styles[Token.INVALID].setGraphicsFlags(gfx,defaultFont);
513             gfx.drawString("~",0,y + fm.getHeight());
514          }
515       }
516       else if(tokenMarker == null)
517       {
518          paintPlainLine(gfx,line,defaultFont,defaultColor,x,y);
519       }
520       else
521       {
522          paintSyntaxLine(gfx,tokenMarker,line,defaultFont,
523             defaultColor,x,y);
524       }
525    }
526
527    protected void paintPlainLine(Graphics gfx, int line, Font defaultFont,
528       Color defaultColor, int x, int y)
529    {
530       paintHighlight(gfx,line,y);
531       textArea.getLineText(line,currentLine);
532
533       gfx.setFont(defaultFont);
534       gfx.setColor(defaultColor);
535
536       y += fm.getHeight();
537       x = Utilities.drawTabbedText(currentLine,x,y,gfx,this,0);
538
539       if(eolMarkers)
540       {
541          gfx.setColor(eolMarkerColor);
542          gfx.drawString(".",x,y);
543       }
544    }
545
546    protected void paintSyntaxLine(Graphics gfx, TokenMarker tokenMarker,
547       int line, Font defaultFont, Color defaultColor, int x, int y)
548    {
549       textArea.getLineText(currentLineIndex,currentLine);
550       currentLineTokens = tokenMarker.markTokens(currentLine,
551          currentLineIndex);
552
553       paintHighlight(gfx,line,y);
554
555       gfx.setFont(defaultFont);
556       gfx.setColor(defaultColor);
557       y += fm.getHeight();
558       x = SyntaxUtilities.paintSyntaxLine(currentLine,
559          currentLineTokens,styles,this,gfx,x,y);
560
561       if(eolMarkers)
562       {
563          gfx.setColor(eolMarkerColor);
564          gfx.drawString(".",x,y);
565       }
566    }
567
568    protected void paintHighlight(Graphics gfx, int line, int y)
569    {
570       if(line >= textArea.getSelectionStartLine()
571          && line <= textArea.getSelectionEndLine())
572          paintLineHighlight(gfx,line,y);
573
574       if(highlights != null)
575          highlights.paintHighlight(gfx,line,y);
576
577       if(bracketHighlight && line == textArea.getBracketLine())
578          paintBracketHighlight(gfx,line,y);
579
580       if(line == textArea.getCaretLine())
581          paintCaret(gfx,line,y);
582    }
583
584    protected void paintLineHighlight(Graphics gfx, int line, int y)
585    {
586       int height = fm.getHeight();
587       y += fm.getLeading() + fm.getMaxDescent();
588
589       int selectionStart = textArea.getSelectionStart();
590       int selectionEnd = textArea.getSelectionEnd();
591
592       if(selectionStart == selectionEnd)
593       {
594          if(lineHighlight)
595          {
596             gfx.setColor(lineHighlightColor);
597             gfx.fillRect(0,y,getWidth(),height);
598          }
599       }
600       else
601       {
602          gfx.setColor(selectionColor);
603
604          int selectionStartLine = textArea.getSelectionStartLine();
605          int selectionEndLine = textArea.getSelectionEndLine();
606          int lineStart = textArea.getLineStartOffset(line);
607
608          int x1, x2;
609          if(textArea.isSelectionRectangular())
610          {
611             int lineLen = textArea.getLineLength(line);
612             x1 = textArea._offsetToX(line,Math.min(lineLen,
613                selectionStart - textArea.getLineStartOffset(
614                selectionStartLine)));
615             x2 = textArea._offsetToX(line,Math.min(lineLen,
616                selectionEnd - textArea.getLineStartOffset(
617                selectionEndLine)));
618             if(x1 == x2)
619                x2++;
620          }
621          else if(selectionStartLine == selectionEndLine)
622          {
623             x1 = textArea._offsetToX(line,
624                selectionStart - lineStart);
625             x2 = textArea._offsetToX(line,
626                selectionEnd - lineStart);
627          }
628          else if(line == selectionStartLine)
629          {
630             x1 = textArea._offsetToX(line,
631                selectionStart - lineStart);
632             x2 = getWidth();
633          }
634          else if(line == selectionEndLine)
635          {
636             x1 = 0;
637             x2 = textArea._offsetToX(line,
638                selectionEnd - lineStart);
639          }
640          else
641          {
642             x1 = 0;
643             x2 = getWidth();
644          }
645
646          // "inlined" min/max()
647
gfx.fillRect(x1 > x2 ? x2 : x1,y,x1 > x2 ?
648             (x1 - x2) : (x2 - x1),height);
649       }
650
651    }
652
653    protected void paintBracketHighlight(Graphics gfx, int line, int y)
654    {
655       int position = textArea.getBracketPosition();
656       if(position == -1)
657          return;
658       y += fm.getLeading() + fm.getMaxDescent();
659       int x = textArea._offsetToX(line,position);
660       gfx.setColor(bracketHighlightColor);
661       // Hack!!! Since there is no fast way to get the character
662
// from the bracket matching routine, we use ( since all
663
// brackets probably have the same width anyway
664
gfx.drawRect(x,y,fm.charWidth('(') - 1,
665          fm.getHeight() - 1);
666    }
667
668    protected void paintCaret(Graphics gfx, int line, int y)
669    {
670       if(textArea.isCaretVisible())
671       {
672          int offset = textArea.getCaretPosition()
673             - textArea.getLineStartOffset(line);
674          int caretX = textArea._offsetToX(line,offset);
675          int caretWidth = ((blockCaret ||
676             textArea.isOverwriteEnabled()) ?
677             fm.charWidth('w') : 1);
678          y += fm.getLeading() + fm.getMaxDescent();
679          int height = fm.getHeight();
680          
681          gfx.setColor(caretColor);
682
683          if(textArea.isOverwriteEnabled())
684          {
685             gfx.fillRect(caretX,y + height - 1,
686                caretWidth,1);
687          }
688          else
689          {
690             gfx.drawRect(caretX,y,caretWidth - 1,height - 1);
691          }
692       }
693    }
694 }
695
Popular Tags