KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * Copyright (C) 2005 - 2006 JasperSoft Corporation. All rights reserved.
3  * http://www.jaspersoft.com.
4  *
5  * Unless you have purchased a commercial license agreement from JasperSoft,
6  * the following license terms apply:
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as published by
10  * the Free Software Foundation.
11  *
12  * This program is distributed WITHOUT ANY WARRANTY; and without the
13  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see http://www.gnu.org/licenses/gpl.txt
18  * or write to:
19  *
20  * Free Software Foundation, Inc.,
21  * 59 Temple Place - Suite 330,
22  * Boston, MA USA 02111-1307
23  *
24  *
25  *
26  *
27  * TextAreaPainter.java
28  *
29  */

30
31 package org.syntax.jedit;
32
33 import org.syntax.jedit.tokenmarker.*;
34 import javax.swing.ToolTipManager JavaDoc;
35 import javax.swing.text.*;
36 import javax.swing.JComponent JavaDoc;
37 import java.awt.event.MouseEvent JavaDoc;
38 import java.awt.*;
39
40 /**
41  * The text area repaint manager. It performs double buffering and paints
42  * lines of text.
43  * @author Slava Pestov
44  * @version $Id: TextAreaPainter.java 932 2006-10-20 09:32:45Z gtoffoli $
45  */

46 public class TextAreaPainter extends JComponent JavaDoc implements TabExpander
47 {
48     /**
49      * Creates a new repaint manager. This should be not be called
50      * directly.
51      */

52     public TextAreaPainter(JEditTextArea textArea, TextAreaDefaults defaults)
53     {
54         this.textArea = textArea;
55
56         setAutoscrolls(true);
57         setDoubleBuffered(true);
58         setOpaque(true);
59
60         ToolTipManager.sharedInstance().registerComponent(this);
61
62         currentLine = new Segment();
63         currentLineIndex = -1;
64
65         setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
66
67         setFont(new Font("Monospaced",Font.PLAIN,14));
68         setForeground(Color.black);
69         setBackground(Color.white);
70
71         blockCaret = defaults.blockCaret;
72         styles = defaults.styles;
73         cols = defaults.cols;
74         rows = defaults.rows;
75         caretColor = defaults.caretColor;
76         selectionColor = defaults.selectionColor;
77         lineHighlightColor = defaults.lineHighlightColor;
78         lineHighlight = defaults.lineHighlight;
79         bracketHighlightColor = defaults.bracketHighlightColor;
80         bracketHighlight = defaults.bracketHighlight;
81         paintInvalid = defaults.paintInvalid;
82         eolMarkerColor = defaults.eolMarkerColor;
83         eolMarkers = defaults.eolMarkers;
84     }
85
86     /**
87      * Returns if this component can be traversed by pressing the
88      * Tab key. This returns false.
89      */

90     public final boolean isManagingFocus()
91     {
92         return false;
93     }
94
95     /**
96      * Returns the syntax styles used to paint colorized text. Entry <i>n</i>
97      * will be used to paint tokens with id = <i>n</i>.
98      * @see org.syntax.jedit.Token
99      */

100     public final SyntaxStyle[] getStyles()
101     {
102         return styles;
103     }
104
105     /**
106      * Sets the syntax styles used to paint colorized text. Entry <i>n</i>
107      * will be used to paint tokens with id = <i>n</i>.
108      * @param styles The syntax styles
109      * @see org.syntax.jedit.Token
110      */

111     public final void setStyles(SyntaxStyle[] styles)
112     {
113         this.styles = styles;
114         repaint();
115     }
116
117     /**
118      * Returns the caret color.
119      */

120     public final Color getCaretColor()
121     {
122         return caretColor;
123     }
124
125     /**
126      * Sets the caret color.
127      * @param caretColor The caret color
128      */

129     public final void setCaretColor(Color caretColor)
130     {
131         this.caretColor = caretColor;
132         invalidateSelectedLines();
133     }
134
135     /**
136      * Returns the selection color.
137      */

138     public final Color getSelectionColor()
139     {
140         return selectionColor;
141     }
142
143     /**
144      * Sets the selection color.
145      * @param selectionColor The selection color
146      */

147     public final void setSelectionColor(Color selectionColor)
148     {
149         this.selectionColor = selectionColor;
150         invalidateSelectedLines();
151     }
152
153     /**
154      * Returns the line highlight color.
155      */

156     public final Color getLineHighlightColor()
157     {
158         return lineHighlightColor;
159     }
160
161     /**
162      * Sets the line highlight color.
163      * @param lineHighlightColor The line highlight color
164      */

165     public final void setLineHighlightColor(Color lineHighlightColor)
166     {
167         this.lineHighlightColor = lineHighlightColor;
168         invalidateSelectedLines();
169     }
170
171     /**
172      * Returns true if line highlight is enabled, false otherwise.
173      */

174     public final boolean isLineHighlightEnabled()
175     {
176         return lineHighlight;
177     }
178
179     /**
180      * Enables or disables current line highlighting.
181      * @param lineHighlight True if current line highlight should be enabled,
182      * false otherwise
183      */

184     public final void setLineHighlightEnabled(boolean lineHighlight)
185     {
186         this.lineHighlight = lineHighlight;
187         invalidateSelectedLines();
188     }
189
190     /**
191      * Returns the bracket highlight color.
192      */

193     public final Color getBracketHighlightColor()
194     {
195         return bracketHighlightColor;
196     }
197
198     /**
199      * Sets the bracket highlight color.
200      * @param bracketHighlightColor The bracket highlight color
201      */

202     public final void setBracketHighlightColor(Color bracketHighlightColor)
203     {
204         this.bracketHighlightColor = bracketHighlightColor;
205         invalidateLine(textArea.getBracketLine());
206     }
207
208     /**
209      * Returns true if bracket highlighting is enabled, false otherwise.
210      * When bracket highlighting is enabled, the bracket matching the
211      * one before the caret (if any) is highlighted.
212      */

213     public final boolean isBracketHighlightEnabled()
214     {
215         return bracketHighlight;
216     }
217
218     /**
219      * Enables or disables bracket highlighting.
220      * When bracket highlighting is enabled, the bracket matching the
221      * one before the caret (if any) is highlighted.
222      * @param bracketHighlight True if bracket highlighting should be
223      * enabled, false otherwise
224      */

225     public final void setBracketHighlightEnabled(boolean bracketHighlight)
226     {
227         this.bracketHighlight = bracketHighlight;
228         invalidateLine(textArea.getBracketLine());
229     }
230
231     /**
232      * Returns true if the caret should be drawn as a block, false otherwise.
233      */

234     public final boolean isBlockCaretEnabled()
235     {
236         return blockCaret;
237     }
238
239     /**
240      * Sets if the caret should be drawn as a block, false otherwise.
241      * @param blockCaret True if the caret should be drawn as a block,
242      * false otherwise.
243      */

244     public final void setBlockCaretEnabled(boolean blockCaret)
245     {
246         this.blockCaret = blockCaret;
247         invalidateSelectedLines();
248     }
249
250     /**
251      * Returns the EOL marker color.
252      */

253     public final Color getEOLMarkerColor()
254     {
255         return eolMarkerColor;
256     }
257
258     /**
259      * Sets the EOL marker color.
260      * @param eolMarkerColor The EOL marker color
261      */

262     public final void setEOLMarkerColor(Color eolMarkerColor)
263     {
264         this.eolMarkerColor = eolMarkerColor;
265         repaint();
266     }
267
268     /**
269      * Returns true if EOL markers are drawn, false otherwise.
270      */

271     public final boolean getEOLMarkersPainted()
272     {
273         return eolMarkers;
274     }
275
276     /**
277      * Sets if EOL markers are to be drawn.
278      * @param eolMarkers True if EOL markers should be drawn, false otherwise
279      */

280     public final void setEOLMarkersPainted(boolean eolMarkers)
281     {
282         this.eolMarkers = eolMarkers;
283         repaint();
284     }
285
286     /**
287      * Returns true if invalid lines are painted as red tildes (~),
288      * false otherwise.
289      */

290     public boolean getInvalidLinesPainted()
291     {
292         return paintInvalid;
293     }
294
295     /**
296      * Sets if invalid lines are to be painted as red tildes.
297      * @param paintInvalid True if invalid lines should be drawn, false otherwise
298      */

299     public void setInvalidLinesPainted(boolean paintInvalid)
300     {
301         this.paintInvalid = paintInvalid;
302     }
303
304     /**
305      * Adds a custom highlight painter.
306      * @param highlight The highlight
307      */

308     public void addCustomHighlight(Highlight highlight)
309     {
310         highlight.init(textArea,highlights);
311         highlights = highlight;
312     }
313
314     /**
315      * Highlight interface.
316      */

317     public interface Highlight
318     {
319         /**
320          * Called after the highlight painter has been added.
321          * @param textArea The text area
322          * @param next The painter this one should delegate to
323          */

324         void init(JEditTextArea textArea, Highlight next);
325
326         /**
327          * This should paint the highlight and delgate to the
328          * next highlight painter.
329          * @param gfx The graphics context
330          * @param line The line number
331          * @param y The y co-ordinate of the line
332          */

333         void paintHighlight(Graphics gfx, int line, int y);
334
335         /**
336          * Returns the tool tip to display at the specified
337          * location. If this highlighter doesn't know what to
338          * display, it should delegate to the next highlight
339          * painter.
340          * @param evt The mouse event
341          */

342         String JavaDoc getToolTipText(MouseEvent JavaDoc evt);
343     }
344
345     /**
346      * Returns the tool tip to display at the specified location.
347      * @param evt The mouse event
348      */

349     public String JavaDoc getToolTipText(MouseEvent JavaDoc evt)
350     {
351         if(highlights != null)
352             return highlights.getToolTipText(evt);
353         else
354             return null;
355     }
356
357     /**
358      * Returns the font metrics used by this component.
359      */

360     public FontMetrics getFontMetrics()
361     {
362         return fm;
363     }
364
365     /**
366      * Sets the font for this component. This is overridden to update the
367      * cached font metrics and to recalculate which lines are visible.
368      * @param font The font
369      */

370     public void setFont(Font font)
371     {
372         super.setFont(font);
373         fm = Toolkit.getDefaultToolkit().getFontMetrics(font);
374         textArea.recalculateVisibleLines();
375     }
376
377     /**
378      * Repaints the text.
379      * @param g The graphics context
380      */

381     public void paint(Graphics gfx)
382     {
383         tabSize = fm.charWidth(' ') * ((Integer JavaDoc)textArea
384             .getDocument().getProperty(
385             PlainDocument.tabSizeAttribute)).intValue();
386
387         Rectangle clipRect = gfx.getClipBounds();
388
389         gfx.setColor(getBackground());
390         gfx.fillRect(clipRect.x,clipRect.y,clipRect.width,clipRect.height);
391
392         // We don't use yToLine() here because that method doesn't
393
// return lines past the end of the document
394
int height = fm.getHeight();
395         int firstLine = textArea.getFirstLine();
396         int firstInvalid = firstLine + clipRect.y / height;
397         // Because the clipRect's height is usually an even multiple
398
// of the font height, we subtract 1 from it, otherwise one
399
// too many lines will always be painted.
400
int lastInvalid = firstLine + (clipRect.y + clipRect.height - 1) / height;
401
402         try
403         {
404             TokenMarker tokenMarker = textArea.getDocument()
405                 .getTokenMarker();
406             int x = textArea.getHorizontalOffset();
407
408             for(int line = firstInvalid; line <= lastInvalid; line++)
409             {
410                 paintLine(gfx,tokenMarker,line,x);
411             }
412
413             if(tokenMarker != null && tokenMarker.isNextLineRequested())
414             {
415                 int h = clipRect.y + clipRect.height;
416                 repaint(0,h,getWidth(),getHeight() - h);
417             }
418         }
419         catch(Exception JavaDoc e)
420         {
421             System.err.println("Error repainting line"
422                 + " range {" + firstInvalid + ","
423                 + lastInvalid + "}:");
424             e.printStackTrace();
425         }
426     }
427
428     /**
429      * Marks a line as needing a repaint.
430      * @param line The line to invalidate
431      */

432     public final void invalidateLine(int line)
433     {
434         repaint(0,textArea.lineToY(line) + fm.getMaxDescent() + fm.getLeading(),
435             getWidth(),fm.getHeight());
436     }
437
438     /**
439      * Marks a range of lines as needing a repaint.
440      * @param firstLine The first line to invalidate
441      * @param lastLine The last line to invalidate
442      */

443     public final void invalidateLineRange(int firstLine, int lastLine)
444     {
445         repaint(0,textArea.lineToY(firstLine) + fm.getMaxDescent() + fm.getLeading(),
446             getWidth(),(lastLine - firstLine + 1) * fm.getHeight());
447     }
448
449     /**
450      * Repaints the lines containing the selection.
451      */

452     public final void invalidateSelectedLines()
453     {
454         invalidateLineRange(textArea.getSelectionStartLine(),
455             textArea.getSelectionEndLine());
456     }
457
458     /**
459      * Implementation of TabExpander interface. Returns next tab stop after
460      * a specified point.
461      * @param x The x co-ordinate
462      * @param tabOffset Ignored
463      * @return The next tab stop after <i>x</i>
464      */

465     public float nextTabStop(float x, int tabOffset)
466     {
467         int offset = textArea.getHorizontalOffset();
468                 int ntabs=0;
469                 if (tabSize > 0)
470          ntabs = ((int)x - offset) / tabSize;
471         return (ntabs + 1) * tabSize + offset;
472     }
473
474     /**
475      * Returns the painter's preferred size.
476      */

477     public Dimension getPreferredSize()
478     {
479         Dimension dim = new Dimension();
480         dim.width = fm.charWidth('w') * cols;
481         dim.height = fm.getHeight() * rows;
482         return dim;
483     }
484
485
486     /**
487      * Returns the painter's minimum size.
488      */

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