Fixed bug #1404228: Crash on <?php // comment ?>
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / phpeditor / LinePainter.java
1 package net.sourceforge.phpeclipse.phpeditor;
2
3 /*
4  * (c) Copyright IBM Corp. 2000, 2001.
5  * All Rights Reserved.
6  */
7
8 import org.eclipse.jface.text.BadLocationException;
9 import org.eclipse.jface.text.IDocument;
10 import org.eclipse.jface.text.Position;
11 import org.eclipse.jface.text.source.ISourceViewer;
12 import org.eclipse.swt.custom.LineBackgroundEvent;
13 import org.eclipse.swt.custom.LineBackgroundListener;
14 import org.eclipse.swt.custom.StyledText;
15 import org.eclipse.swt.graphics.Color;
16 import org.eclipse.swt.graphics.Point;
17
18 public class LinePainter implements IPainter, LineBackgroundListener {
19
20         private final ISourceViewer fViewer;
21         private Color fHighlightColor;
22         private IPositionManager fPositionManager;
23
24         // positions to keep track of beginning and end of line to be painted or cleared
25         private Position fCurrentLine= new Position(0, 0);
26         private Position fLastLine= new Position(0, 0);
27         // used to keep track of the last line painted
28         private int fLastLineNumber= -1;
29         private boolean fIsActive;
30
31         public LinePainter(ISourceViewer sourceViewer) {
32                 fViewer= sourceViewer;
33         }
34
35         public void setHighlightColor(Color highlightColor) {
36                 fHighlightColor= highlightColor;
37         }
38
39         /*
40          * @see LineBackgroundListener#lineGetBackground(LineBackgroundEvent)
41          */
42         public void lineGetBackground(LineBackgroundEvent event) {
43                 // don't use cached line information because of asynch painting
44
45                 StyledText textWidget= fViewer.getTextWidget();
46                 if (textWidget != null) {
47                         
48                         int caret= textWidget.getCaretOffset();
49                         int length= event.lineText.length();
50
51                         if (event.lineOffset <= caret && caret <= event.lineOffset + length)
52                                 event.lineBackground= fHighlightColor;
53                         else
54                                 event.lineBackground= textWidget.getBackground();
55                 }
56         }
57
58         private boolean updateHighlightLine() {
59                 try {
60
61                         IDocument document= fViewer.getDocument();
62
63                         int offset= fViewer.getTextWidget().getCaretOffset() + fViewer.getVisibleRegion().getOffset();
64                         int lineNumber= document.getLineOfOffset(offset);
65                                                 
66                         // redraw if the current line number is different from the last line number we painted
67                         // initially fLastLineNumber is -1
68                         if (lineNumber != fLastLineNumber) {
69                                 
70                                 fLastLine.offset= fCurrentLine.offset;
71                                 fLastLine.length= fCurrentLine.length;
72                                 fLastLine.isDeleted= fCurrentLine.isDeleted;
73
74                                 fCurrentLine.isDeleted= false;
75                                 fCurrentLine.offset= document.getLineOffset(lineNumber);
76                                 if (lineNumber == document.getNumberOfLines() - 1)
77                                         fCurrentLine.length= document.getLength() - fCurrentLine.offset;
78                                 else
79                                         fCurrentLine.length=    document.getLineOffset(lineNumber + 1) - fCurrentLine.offset;
80                                 
81                                 fLastLineNumber= lineNumber;
82                                 return true;
83                                 
84                         }
85                         
86                 } catch (BadLocationException e) {
87                 }
88
89                 return false;
90         }
91
92         private void drawHighlightLine(Position position, int visibleOffset) {
93                 StyledText textWidget= fViewer.getTextWidget();
94                 
95                 // if the position that is about to be drawn was deleted then we can't
96                 if (position.isDeleted())
97                         return;         
98                 
99                 int delta= position.offset - visibleOffset;
100                 if (0 <= delta && delta <= fViewer.getVisibleRegion().getLength()) {
101                         Point upperLeft= textWidget.getLocationAtOffset(delta);
102                         int width= textWidget.getClientArea().width + textWidget.getHorizontalPixel();
103                         int height= textWidget.getLineHeight();
104                         textWidget.redraw(upperLeft.x, upperLeft.y, width, height, false);
105                 }
106         }
107
108         /*
109          * @see IPainter#deactivate(boolean)
110          */
111         public void deactivate(boolean redraw) {
112                 if (fIsActive) {
113                         fIsActive= false;
114                         
115                         /* on turning off the feature one has to paint the currently 
116                          * highlighted line with the standard background color 
117                          */
118                         if (redraw)
119                                 drawHighlightLine(fCurrentLine, fViewer.getVisibleRegion().getOffset());
120                                 
121                         fViewer.getTextWidget().removeLineBackgroundListener(this);
122                         
123                         if (fPositionManager != null)
124                                 fPositionManager.removeManagedPosition(fCurrentLine);
125                                 
126                         fLastLineNumber= -1;
127                 }
128         }
129
130         /*
131          * @see IPainter#dispose()
132          */
133         public void dispose() {
134         }
135
136         /*
137          * @see IPainter#paint(int)
138          */
139         public void paint(int reason) {
140                 
141                 // check selection
142                 Point selection= fViewer.getTextWidget().getSelectionRange();
143                 if (selection.y > 0) {
144                         deactivate(true);
145                         return;
146                 }
147                 
148                 // initialization
149                 if (!fIsActive) {
150                         fViewer.getTextWidget().addLineBackgroundListener(this);
151                         fPositionManager.addManagedPosition(fCurrentLine);
152                         fIsActive= true;
153                 }
154                 
155                 //redraw line highlight only if it hasn't been drawn yet on the respective line
156                 if (updateHighlightLine()) {
157                         // used to handle segmented view of source files
158                         int visibleRegionOffset= fViewer.getVisibleRegion().getOffset();
159                         // clear last line
160                         drawHighlightLine(fLastLine, visibleRegionOffset);
161                         // draw new line
162                         drawHighlightLine(fCurrentLine, visibleRegionOffset);
163                 }
164         }
165
166         /*
167          * @see IPainter#setPositionManager(IPositionManager)
168          */
169         public void setPositionManager(IPositionManager manager) {
170                 fPositionManager = manager;
171         }
172 }