1 11 package org.eclipse.jface.text; 12 13 import org.eclipse.swt.custom.StyleRange; 14 import org.eclipse.swt.custom.StyledText; 15 import org.eclipse.swt.custom.StyledTextContent; 16 import org.eclipse.swt.events.PaintEvent; 17 import org.eclipse.swt.events.PaintListener; 18 import org.eclipse.swt.graphics.Color; 19 import org.eclipse.swt.graphics.FontMetrics; 20 import org.eclipse.swt.graphics.GC; 21 import org.eclipse.swt.graphics.Point; 22 23 24 30 public class WhitespaceCharacterPainter implements IPainter, PaintListener { 31 32 private static final char SPACE_SIGN= '\u00b7'; 33 private static final char IDEOGRAPHIC_SPACE_SIGN= '\u00b0'; 34 private static final char TAB_SIGN= '\u00bb'; 35 private static final char CARRIAGE_RETURN_SIGN= '\u00a4'; 36 private static final char LINE_FEED_SIGN= '\u00b6'; 37 38 39 private boolean fIsActive= false; 40 41 private ITextViewer fTextViewer; 42 43 private StyledText fTextWidget; 44 45 private boolean fIsAdvancedGraphicsPresent; 46 47 52 public WhitespaceCharacterPainter(ITextViewer textViewer) { 53 super(); 54 fTextViewer= textViewer; 55 fTextWidget= textViewer.getTextWidget(); 56 GC gc= new GC(fTextWidget); 57 gc.setAdvanced(true); 58 fIsAdvancedGraphicsPresent= gc.getAdvanced(); 59 gc.dispose(); 60 } 61 62 65 public void dispose() { 66 fTextViewer= null; 67 fTextWidget= null; 68 } 69 70 73 public void paint(int reason) { 74 IDocument document= fTextViewer.getDocument(); 75 if (document == null) { 76 deactivate(false); 77 return; 78 } 79 if (!fIsActive) { 80 fIsActive= true; 81 fTextWidget.addPaintListener(this); 82 redrawAll(true); 83 } else if (reason == CONFIGURATION || reason == INTERNAL) { 84 redrawAll(false); 85 } else if (reason == TEXT_CHANGE) { 86 try { 88 IRegion lineRegion = 89 document.getLineInformationOfOffset(getDocumentOffset(fTextWidget.getCaretOffset())); 90 int widgetOffset= getWidgetOffset(lineRegion.getOffset()); 91 int charCount= fTextWidget.getCharCount(); 92 int redrawLength= Math.min(lineRegion.getLength(), charCount - widgetOffset); 93 if (widgetOffset >= 0 && redrawLength > 0) { 94 fTextWidget.redrawRange(widgetOffset, redrawLength, true); 95 } 96 } catch (BadLocationException e) { 97 } 99 } 100 } 101 102 105 public void deactivate(boolean redraw) { 106 if (fIsActive) { 107 fIsActive= false; 108 fTextWidget.removePaintListener(this); 109 if (redraw) { 110 redrawAll(true); 111 } 112 } 113 } 114 115 118 public void setPositionManager(IPaintPositionManager manager) { 119 } 121 122 125 public void paintControl(PaintEvent event) { 126 if (fTextWidget != null) { 127 handleDrawRequest(event.gc, event.x, event.y, event.width, event.height); 128 } 129 } 130 131 140 private void handleDrawRequest(GC gc, int x, int y, int w, int h) { 141 int lineCount= fTextWidget.getLineCount(); 142 int startLine= (y + fTextWidget.getTopPixel()) / fTextWidget.getLineHeight(); 143 int endLine= (y + h - 1 + fTextWidget.getTopPixel()) / fTextWidget.getLineHeight(); 144 if (startLine <= endLine && startLine < lineCount) { 145 int startOffset= fTextWidget.getOffsetAtLine(startLine); 146 int endOffset = 147 endLine < lineCount - 1 ? fTextWidget.getOffsetAtLine(endLine + 1) : fTextWidget.getCharCount(); 148 149 if (fIsAdvancedGraphicsPresent) { 150 int alpha= gc.getAlpha(); 151 gc.setAlpha(100); 152 handleDrawRequest(gc, startOffset, endOffset); 153 gc.setAlpha(alpha); 154 } else 155 handleDrawRequest(gc, startOffset, endOffset); 156 } 157 } 158 159 166 private void handleDrawRequest(GC gc, int startOffset, int endOffset) { 167 StyledTextContent content= fTextWidget.getContent(); 168 int length= endOffset - startOffset; 169 String text= content.getTextRange(startOffset, length); 170 StyleRange styleRange= null; 171 Color fg= null; 172 Point selection= fTextWidget.getSelection(); 173 StringBuffer visibleChar= new StringBuffer (10); 174 for (int textOffset= 0; textOffset <= length; ++textOffset) { 175 int delta= 0; 176 boolean eol= false; 177 if (textOffset < length) { 178 delta= 1; 179 char c= text.charAt(textOffset); 180 switch (c) { 181 case ' ' : 182 visibleChar.append(SPACE_SIGN); 183 break; 186 case '\u3000' : visibleChar.append(IDEOGRAPHIC_SPACE_SIGN); 188 break; 191 case '\t' : 192 visibleChar.append(TAB_SIGN); 193 break; 194 case '\r' : 195 visibleChar.append(CARRIAGE_RETURN_SIGN); 196 if (textOffset >= length - 1 || text.charAt(textOffset + 1) != '\n') { 197 eol= true; 198 break; 199 } 200 continue; 201 case '\n' : 202 visibleChar.append(LINE_FEED_SIGN); 203 eol= true; 204 break; 205 default : 206 delta= 0; 207 break; 208 } 209 } 210 if (visibleChar.length() > 0) { 211 int widgetOffset= startOffset + textOffset - visibleChar.length() + delta; 212 if (!eol || !isFoldedLine(content.getLineAtOffset(widgetOffset))) { 213 if (widgetOffset >= selection.x && widgetOffset < selection.y) { 214 fg= fTextWidget.getSelectionForeground(); 215 } else if (styleRange == null || styleRange.start + styleRange.length <= widgetOffset) { 216 styleRange= fTextWidget.getStyleRangeAtOffset(widgetOffset); 217 if (styleRange == null || styleRange.foreground == null) { 218 fg= fTextWidget.getForeground(); 219 } else { 220 fg= styleRange.foreground; 221 } 222 } 223 draw(gc, widgetOffset, visibleChar.toString(), fg); 224 } 225 visibleChar.delete(0, visibleChar.length()); 226 } 227 } 228 } 229 230 236 private boolean isFoldedLine(int widgetLine) { 237 if (fTextViewer instanceof ITextViewerExtension5) { 238 ITextViewerExtension5 extension= (ITextViewerExtension5)fTextViewer; 239 int modelLine= extension.widgetLine2ModelLine(widgetLine); 240 int widgetLine2= extension.modelLine2WidgetLine(modelLine + 1); 241 return widgetLine2 == -1; 242 } 243 return false; 244 } 245 246 251 private void redrawAll(boolean redrawBackground) { 252 int startLine= fTextWidget.getTopPixel() / fTextWidget.getLineHeight(); 253 int startOffset= fTextWidget.getOffsetAtLine(startLine); 254 int endLine= 1 + (fTextWidget.getTopPixel() + fTextWidget.getClientArea().height) / fTextWidget.getLineHeight(); 255 int endOffset; 256 if (endLine >= fTextWidget.getLineCount()) { 257 endOffset= fTextWidget.getCharCount(); 258 } else { 259 endOffset= fTextWidget.getOffsetAtLine(endLine); 260 } 261 if (startOffset < endOffset) { 262 endOffset= Math.min(endOffset + 2, fTextWidget.getCharCount()); 264 int redrawOffset= startOffset; 265 int redrawLength= endOffset - redrawOffset; 266 fTextWidget.redrawRange(startOffset, redrawLength, redrawBackground); 267 } 268 } 269 270 278 private void draw(GC gc, int offset, String s, Color fg) { 279 int baseline= fTextWidget.getBaseline(offset); 281 FontMetrics fontMetrics= gc.getFontMetrics(); 282 int fontBaseline= fontMetrics.getAscent() + fontMetrics.getLeading(); 283 int baslineDelta= baseline - fontBaseline; 284 285 Point pos= fTextWidget.getLocationAtOffset(offset); 286 gc.setForeground(fg); 287 gc.drawString(s, pos.x, pos.y + baslineDelta, true); 288 } 289 290 296 private int getWidgetOffset(int documentOffset) { 297 if (fTextViewer instanceof ITextViewerExtension5) { 298 ITextViewerExtension5 extension= (ITextViewerExtension5)fTextViewer; 299 return extension.modelOffset2WidgetOffset(documentOffset); 300 } 301 IRegion visible= fTextViewer.getVisibleRegion(); 302 int widgetOffset= documentOffset - visible.getOffset(); 303 if (widgetOffset > visible.getLength()) { 304 return -1; 305 } 306 return widgetOffset; 307 } 308 309 315 private int getDocumentOffset(int widgetOffset) { 316 if (fTextViewer instanceof ITextViewerExtension5) { 317 ITextViewerExtension5 extension= (ITextViewerExtension5)fTextViewer; 318 return extension.widgetOffset2ModelOffset(widgetOffset); 319 } 320 IRegion visible= fTextViewer.getVisibleRegion(); 321 if (widgetOffset > visible.getLength()) { 322 return -1; 323 } 324 return widgetOffset + visible.getOffset(); 325 } 326 327 } 328 | Popular Tags |