Mercurial > projects > dwt-addons
annotate dwtx/jface/internal/text/source/DiffPainter.d @ 192:c3583c6ec027
Added missing default cases for switch statements
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Mon, 03 Nov 2008 22:52:26 +0100 |
parents | 1a5b8f8129df |
children |
rev | line source |
---|---|
129 | 1 /******************************************************************************* |
2 * Copyright (c) 2006 IBM Corporation and others. | |
3 * All rights reserved. This program and the accompanying materials | |
4 * are made available under the terms of the Eclipse Public License v1.0 | |
5 * which accompanies this distribution, and is available at | |
6 * http://www.eclipse.org/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * IBM Corporation - initial API and implementation | |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module dwtx.jface.internal.text.source.DiffPainter; | |
14 | |
131 | 15 |
16 | |
129 | 17 import dwt.dwthelper.utils; |
18 | |
19 | |
20 | |
21 | |
22 import dwt.DWT; | |
23 import dwt.custom.StyledText; | |
24 import dwt.events.DisposeEvent; | |
25 import dwt.events.DisposeListener; | |
26 import dwt.graphics.Color; | |
27 import dwt.graphics.GC; | |
28 import dwt.graphics.RGB; | |
29 import dwt.widgets.Canvas; | |
30 import dwt.widgets.Control; | |
31 import dwt.widgets.Display; | |
32 import dwtx.core.runtime.Assert; | |
33 import dwtx.jface.text.ITextViewer; | |
34 import dwtx.jface.text.JFaceTextUtil; | |
35 import dwtx.jface.text.source.CompositeRuler; | |
36 import dwtx.jface.text.source.IAnnotationHover; | |
37 import dwtx.jface.text.source.IAnnotationModel; | |
38 import dwtx.jface.text.source.IAnnotationModelExtension; | |
39 import dwtx.jface.text.source.IAnnotationModelListener; | |
40 import dwtx.jface.text.source.IChangeRulerColumn; | |
41 import dwtx.jface.text.source.ILineDiffInfo; | |
42 import dwtx.jface.text.source.ILineDiffer; | |
43 import dwtx.jface.text.source.ILineDifferExtension2; | |
44 import dwtx.jface.text.source.ILineRange; | |
45 import dwtx.jface.text.source.ISharedTextColors; | |
46 import dwtx.jface.text.source.IVerticalRulerColumn; | |
47 | |
48 | |
49 /** | |
50 * A strategy for painting the quick diff colors onto the vertical ruler column. It also manages the | |
51 * quick diff hover. | |
159 | 52 * |
129 | 53 * @since 3.2 |
54 */ | |
55 public final class DiffPainter { | |
56 /** | |
57 * Internal listener class that will update the ruler when the underlying model changes. | |
58 */ | |
59 private class AnnotationListener : IAnnotationModelListener { | |
60 /* | |
61 * @see dwtx.jface.text.source.IAnnotationModelListener#modelChanged(dwtx.jface.text.source.IAnnotationModel) | |
62 */ | |
63 public void modelChanged(IAnnotationModel model) { | |
64 postRedraw(); | |
65 } | |
66 } | |
67 | |
68 /** The vertical ruler column that delegates painting to this painter. */ | |
146 | 69 private const IVerticalRulerColumn fColumn; |
129 | 70 /** The parent ruler. */ |
71 private CompositeRuler fParentRuler; | |
72 /** The column's control, typically a {@link Canvas}, possibly <code>null</code>. */ | |
73 private Control fControl; | |
74 /** The text viewer that the column is attached to. */ | |
75 private ITextViewer fViewer; | |
76 /** The viewer's text widget. */ | |
77 private StyledText fWidget; | |
78 /** The line differ extracted from the annotation model. */ | |
79 private ILineDiffer fLineDiffer= null; | |
80 /** Color for changed lines */ | |
81 private Color fAddedColor; | |
82 /** Color for added lines */ | |
83 private Color fChangedColor; | |
84 /** Color for the deleted line indicator */ | |
85 private Color fDeletedColor; | |
86 /** The background color. */ | |
87 private Color fBackground; | |
88 /** The ruler's hover */ | |
89 private IAnnotationHover fHover; | |
90 /** The internal listener */ | |
159 | 91 private const AnnotationListener fAnnotationListener; |
129 | 92 /** The shared color provider, possibly <code>null</code>. */ |
146 | 93 private const ISharedTextColors fSharedColors; |
129 | 94 |
95 /** | |
96 * Creates a new diff painter for a vertical ruler column. | |
159 | 97 * |
129 | 98 * @param column the column that will delegate{@link #paint(GC, ILineRange) painting} to the |
99 * newly created painter. | |
100 * @param sharedColors a shared colors object to store shaded colors in, may be | |
101 * <code>null</code> | |
102 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
103 public this(IVerticalRulerColumn column, ISharedTextColors sharedColors) { |
159 | 104 fAnnotationListener= new AnnotationListener(); |
129 | 105 Assert.isLegal(column !is null); |
106 fColumn= column; | |
107 fSharedColors= sharedColors; | |
108 } | |
109 | |
110 /** | |
111 * Sets the parent ruler - the delegating column must call this method as soon as it creates its | |
112 * control. | |
159 | 113 * |
129 | 114 * @param parentRuler the parent ruler |
115 */ | |
116 public void setParentRuler(CompositeRuler parentRuler) { | |
117 fParentRuler= parentRuler; | |
118 } | |
119 | |
120 /** | |
121 * Sets the quick diff hover later returned by {@link #getHover()}. | |
159 | 122 * |
129 | 123 * @param hover the hover |
124 */ | |
125 public void setHover(IAnnotationHover hover) { | |
126 fHover= hover; | |
127 } | |
128 | |
129 /** | |
130 * Returns the quick diff hover set by {@link #setHover(IAnnotationHover)}. | |
159 | 131 * |
129 | 132 * @return the quick diff hover set by {@link #setHover(IAnnotationHover)} |
133 */ | |
134 public IAnnotationHover getHover() { | |
135 return fHover; | |
136 } | |
137 | |
138 /** | |
139 * Sets the background color. | |
159 | 140 * |
129 | 141 * @param background the background color, <code>null</code> to use the platform's list background |
142 */ | |
143 public void setBackground(Color background) { | |
144 fBackground= background; | |
145 } | |
146 | |
147 /** | |
148 * Delegates the painting of the quick diff colors to this painter. The painter will draw the | |
149 * color boxes onto the passed {@link GC} for all model (document) lines in | |
150 * <code>visibleModelLines</code>. | |
159 | 151 * |
129 | 152 * @param gc the {@link GC} to draw onto |
153 * @param visibleModelLines the lines (in document offsets) that are currently (perhaps only | |
154 * partially) visible | |
155 */ | |
156 public void paint(GC gc, ILineRange visibleModelLines) { | |
157 connectIfNeeded(); | |
158 if (!isConnected()) | |
159 return; | |
160 | |
161 // draw diff info | |
162 final int lastLine= end(visibleModelLines); | |
163 final int width= getWidth(); | |
164 final Color deletionColor= getDeletionColor(); | |
165 for (int line= visibleModelLines.getStartLine(); line < lastLine; line++) { | |
166 paintLine(line, gc, width, deletionColor); | |
167 } | |
168 } | |
169 | |
170 /** | |
171 * Ensures that the column is fully instantiated, i.e. has a control, and that the viewer is | |
172 * visible. | |
173 */ | |
174 private void connectIfNeeded() { | |
175 if (isConnected() || fParentRuler is null) | |
176 return; | |
177 | |
178 fViewer= fParentRuler.getTextViewer(); | |
179 if (fViewer is null) | |
180 return; | |
181 | |
182 fWidget= fViewer.getTextWidget(); | |
183 if (fWidget is null) | |
184 return; | |
185 | |
186 fControl= fColumn.getControl(); | |
187 if (fControl is null) | |
188 return; | |
189 | |
135 | 190 fControl.addDisposeListener(new class() DisposeListener { |
129 | 191 /* |
192 * @see dwt.events.DisposeListener#widgetDisposed(dwt.events.DisposeEvent) | |
193 */ | |
194 public void widgetDisposed(DisposeEvent e) { | |
195 handleDispose(); | |
196 } | |
197 }); | |
198 } | |
199 | |
200 /** | |
201 * Returns <code>true</code> if the column is fully connected. | |
159 | 202 * |
129 | 203 * @return <code>true</code> if the column is fully connected, false otherwise |
204 */ | |
205 private bool isConnected() { | |
206 return fControl !is null; | |
207 } | |
208 | |
209 /** | |
210 * Disposes of this painter and releases any resources. | |
211 */ | |
212 private void handleDispose() { | |
213 if (fLineDiffer !is null) { | |
134 | 214 (cast(IAnnotationModel) fLineDiffer).removeAnnotationModelListener(fAnnotationListener); |
129 | 215 fLineDiffer= null; |
216 } | |
217 } | |
218 | |
219 /** | |
220 * Paints a single model line onto <code>gc</code>. | |
159 | 221 * |
129 | 222 * @param line the model line to paint |
223 * @param gc the {@link GC} to paint onto | |
224 * @param width the width of the column | |
225 * @param deletionColor the background color used to indicate deletions | |
226 */ | |
227 private void paintLine(int line, GC gc, int width, Color deletionColor) { | |
228 int widgetLine= JFaceTextUtil.modelLineToWidgetLine(fViewer, line); | |
229 if (widgetLine is -1) | |
230 return; | |
231 | |
232 ILineDiffInfo info= getDiffInfo(line); | |
233 | |
234 if (info !is null) { | |
235 int y= fWidget.getLinePixel(widgetLine); | |
236 int lineHeight= fWidget.getLineHeight(fWidget.getOffsetAtLine(widgetLine)); | |
237 | |
238 // draw background color if special | |
239 if (hasSpecialColor(info)) { | |
240 gc.setBackground(getColor(info)); | |
241 gc.fillRectangle(0, y, width, lineHeight); | |
242 } | |
243 | |
244 /* Deletion Indicator: Simply a horizontal line */ | |
245 int delBefore= info.getRemovedLinesAbove(); | |
246 int delBelow= info.getRemovedLinesBelow(); | |
247 if (delBefore > 0 || delBelow > 0) { | |
248 gc.setForeground(deletionColor); | |
249 if (delBefore > 0) | |
250 gc.drawLine(0, y, width, y); | |
251 if (delBelow > 0) | |
252 gc.drawLine(0, y + lineHeight - 1, width, y + lineHeight - 1); | |
253 } | |
254 } | |
255 } | |
256 | |
257 /** | |
258 * Returns whether the line background differs from the default. | |
159 | 259 * |
129 | 260 * @param info the info being queried |
261 * @return <code>true</code> if <code>info</code> describes either a changed or an added | |
262 * line. | |
263 */ | |
264 private bool hasSpecialColor(ILineDiffInfo info) { | |
265 return info.getChangeType() is ILineDiffInfo.ADDED || info.getChangeType() is ILineDiffInfo.CHANGED; | |
266 } | |
267 | |
268 /** | |
269 * Retrieves the <code>ILineDiffInfo</code> for <code>line</code> from the model. There are | |
270 * optimizations for direct access and sequential access patterns. | |
159 | 271 * |
129 | 272 * @param line the line we want the info for. |
273 * @return the <code>ILineDiffInfo</code> for <code>line</code>, or <code>null</code>. | |
274 */ | |
275 private ILineDiffInfo getDiffInfo(int line) { | |
276 if (fLineDiffer !is null) | |
277 return fLineDiffer.getLineInfo(line); | |
278 | |
279 return null; | |
280 } | |
281 | |
282 /** | |
283 * Returns the color for deleted lines. | |
159 | 284 * |
129 | 285 * @return the color to be used for the deletion indicator |
286 */ | |
287 private Color getDeletionColor() { | |
288 return fDeletedColor is null ? getBackground() : fDeletedColor; | |
289 } | |
290 | |
291 /** | |
292 * Returns the color for the given line diff info. | |
159 | 293 * |
129 | 294 * @param info the <code>ILineDiffInfo</code> being queried |
295 * @return the correct background color for the line type being described by <code>info</code> | |
296 */ | |
297 private Color getColor(ILineDiffInfo info) { | |
298 Assert.isTrue(info !is null && info.getChangeType() !is ILineDiffInfo.UNCHANGED); | |
299 Color ret= null; | |
300 switch (info.getChangeType()) { | |
301 case ILineDiffInfo.CHANGED: | |
302 ret= getShadedColor(fChangedColor); | |
303 break; | |
304 case ILineDiffInfo.ADDED: | |
305 ret= getShadedColor(fAddedColor); | |
306 break; | |
192
c3583c6ec027
Added missing default cases for switch statements
Frank Benoit <benoit@tionex.de>
parents:
162
diff
changeset
|
307 default: |
129 | 308 } |
309 return ret is null ? getBackground() : ret; | |
310 } | |
311 | |
312 /** | |
313 * Sets the background color for changed lines. | |
159 | 314 * |
129 | 315 * @param color the new color to be used for the changed lines background |
316 * @return the shaded color | |
317 */ | |
318 private Color getShadedColor(Color color) { | |
319 if (color is null) | |
320 return null; | |
321 | |
322 if (fSharedColors is null) | |
323 return color; | |
324 | |
325 RGB baseRGB= color.getRGB(); | |
326 RGB background= getBackground().getRGB(); | |
327 | |
328 bool darkBase= isDark(baseRGB); | |
329 bool darkBackground= isDark(background); | |
330 if (darkBase && darkBackground) | |
331 background= new RGB(255, 255, 255); | |
332 else if (!darkBase && !darkBackground) | |
333 background= new RGB(0, 0, 0); | |
334 | |
335 return fSharedColors.getColor(interpolate(baseRGB, background, 0.6)); | |
336 } | |
337 | |
338 /** | |
339 * Sets the annotation model. | |
159 | 340 * |
129 | 341 * @param model the annotation model, possibly <code>null</code> |
342 * @see IVerticalRulerColumn#setModel(IAnnotationModel) | |
343 */ | |
344 public void setModel(IAnnotationModel model) { | |
345 IAnnotationModel newModel; | |
138 | 346 if ( cast(IAnnotationModelExtension)model ) |
162 | 347 newModel= (cast(IAnnotationModelExtension) model).getAnnotationModel(stringcast(IChangeRulerColumn.QUICK_DIFF_MODEL_ID)); |
129 | 348 else |
349 newModel= model; | |
350 | |
351 setDiffer(newModel); | |
352 } | |
353 | |
354 /** | |
355 * Sets the line differ. | |
159 | 356 * |
129 | 357 * @param differ the line differ |
358 */ | |
359 private void setDiffer(IAnnotationModel differ) { | |
138 | 360 if ( cast(ILineDiffer)differ ) { |
162 | 361 if ( cast(Object)fLineDiffer !is cast(Object)differ) { |
129 | 362 if (fLineDiffer !is null) |
134 | 363 (cast(IAnnotationModel) fLineDiffer).removeAnnotationModelListener(fAnnotationListener); |
364 fLineDiffer= cast(ILineDiffer) differ; | |
129 | 365 if (fLineDiffer !is null) |
134 | 366 (cast(IAnnotationModel) fLineDiffer).addAnnotationModelListener(fAnnotationListener); |
129 | 367 } |
368 } | |
369 } | |
370 | |
371 /** | |
372 * Triggers a redraw in the display thread. | |
373 */ | |
374 private final void postRedraw() { | |
375 if (isConnected() && !fControl.isDisposed()) { | |
376 Display d= fControl.getDisplay(); | |
377 if (d !is null) { | |
135 | 378 d.asyncExec(new class() Runnable { |
129 | 379 public void run() { |
380 redraw(); | |
381 } | |
382 }); | |
383 } | |
384 } | |
385 } | |
386 | |
387 /** | |
388 * Triggers redrawing of the column. | |
389 */ | |
390 private void redraw() { | |
391 fColumn.redraw(); | |
392 } | |
393 | |
394 /** | |
395 * Returns the width of the column. | |
159 | 396 * |
129 | 397 * @return the width of the column |
398 */ | |
399 private int getWidth() { | |
400 return fColumn.getWidth(); | |
401 } | |
402 | |
403 /** | |
404 * Computes the end index of a line range. | |
159 | 405 * |
129 | 406 * @param range a line range |
407 * @return the last line (exclusive) of <code>range</code> | |
408 */ | |
409 private static int end(ILineRange range) { | |
410 return range.getStartLine() + range.getNumberOfLines(); | |
411 } | |
412 | |
413 /** | |
414 * Returns the System background color for list widgets or the set background. | |
159 | 415 * |
129 | 416 * @return the System background color for list widgets |
417 */ | |
418 private Color getBackground() { | |
419 if (fBackground is null) | |
420 return fWidget.getDisplay().getSystemColor(DWT.COLOR_LIST_BACKGROUND); | |
421 return fBackground; | |
422 } | |
423 | |
424 /** | |
425 * Sets the color for added lines. | |
159 | 426 * |
129 | 427 * @param addedColor the color for added lines |
428 * @see dwtx.jface.text.source.IChangeRulerColumn#setAddedColor(dwt.graphics.Color) | |
429 */ | |
430 public void setAddedColor(Color addedColor) { | |
431 fAddedColor= addedColor; | |
432 } | |
433 | |
434 /** | |
435 * Sets the color for changed lines. | |
159 | 436 * |
129 | 437 * @param changedColor the color for changed lines |
438 * @see dwtx.jface.text.source.IChangeRulerColumn#setChangedColor(dwt.graphics.Color) | |
439 */ | |
440 public void setChangedColor(Color changedColor) { | |
441 fChangedColor= changedColor; | |
442 } | |
443 | |
444 /** | |
445 * Sets the color for deleted lines. | |
159 | 446 * |
129 | 447 * @param deletedColor the color for deleted lines |
448 * @see dwtx.jface.text.source.IChangeRulerColumn#setDeletedColor(dwt.graphics.Color) | |
449 */ | |
450 public void setDeletedColor(Color deletedColor) { | |
451 fDeletedColor= deletedColor; | |
452 } | |
453 | |
454 /** | |
455 * Returns <code>true</code> if the receiver can provide a hover for a certain document line. | |
159 | 456 * |
129 | 457 * @param activeLine the document line of interest |
458 * @return <code>true</code> if the receiver can provide a hover | |
459 */ | |
460 public bool hasHover(int activeLine) { | |
461 return true; | |
462 } | |
463 | |
464 /** | |
465 * Returns the display character for the accessibility mode for a certain model line. | |
159 | 466 * |
129 | 467 * @param line the document line of interest |
468 * @return the display character for <code>line</code> | |
469 */ | |
470 public String getDisplayCharacter(int line) { | |
471 return getDisplayCharacter(getDiffInfo(line)); | |
472 } | |
473 | |
474 /** | |
475 * Returns the character to display in character display mode for the given | |
476 * <code>ILineDiffInfo</code> | |
159 | 477 * |
129 | 478 * @param info the <code>ILineDiffInfo</code> being queried |
479 * @return the character indication for <code>info</code> | |
480 */ | |
481 private String getDisplayCharacter(ILineDiffInfo info) { | |
482 if (info is null) | |
483 return " "; //$NON-NLS-1$ | |
484 switch (info.getChangeType()) { | |
485 case ILineDiffInfo.CHANGED: | |
486 return "~"; //$NON-NLS-1$ | |
487 case ILineDiffInfo.ADDED: | |
488 return "+"; //$NON-NLS-1$ | |
192
c3583c6ec027
Added missing default cases for switch statements
Frank Benoit <benoit@tionex.de>
parents:
162
diff
changeset
|
489 default: |
129 | 490 } |
491 return " "; //$NON-NLS-1$ | |
492 } | |
493 | |
494 /** | |
495 * Returns a specification of a color that lies between the given foreground and background | |
496 * color using the given scale factor. | |
159 | 497 * |
129 | 498 * @param fg the foreground color |
499 * @param bg the background color | |
500 * @param scale the scale factor | |
501 * @return the interpolated color | |
502 */ | |
503 private static RGB interpolate(RGB fg, RGB bg, double scale) { | |
134 | 504 return new RGB(cast(int) ((1.0 - scale) * fg.red + scale * bg.red), cast(int) ((1.0 - scale) * fg.green + scale * bg.green), cast(int) ((1.0 - scale) * fg.blue + scale * bg.blue)); |
129 | 505 } |
506 | |
507 /** | |
508 * Returns the grey value in which the given color would be drawn in grey-scale. | |
159 | 509 * |
129 | 510 * @param rgb the color |
511 * @return the grey-scale value | |
512 */ | |
513 private static double greyLevel(RGB rgb) { | |
514 if (rgb.red is rgb.green && rgb.green is rgb.blue) | |
515 return rgb.red; | |
516 return (0.299 * rgb.red + 0.587 * rgb.green + 0.114 * rgb.blue + 0.5); | |
517 } | |
518 | |
519 /** | |
520 * Returns whether the given color is dark or light depending on the colors grey-scale level. | |
159 | 521 * |
129 | 522 * @param rgb the color |
523 * @return <code>true</code> if the color is dark, <code>false</code> if it is light | |
524 */ | |
525 private static bool isDark(RGB rgb) { | |
526 return greyLevel(rgb) > 128; | |
527 } | |
528 | |
529 /** | |
530 * Returns <code>true</code> if diff information is being displayed, <code>false</code> otherwise. | |
159 | 531 * |
129 | 532 * @return <code>true</code> if diff information is being displayed, <code>false</code> otherwise |
533 * @since 3.3 | |
534 */ | |
535 public bool hasInformation() { | |
138 | 536 if ( cast(ILineDifferExtension2)fLineDiffer ) |
134 | 537 return !(cast(ILineDifferExtension2) fLineDiffer).isSuspended(); |
129 | 538 return fLineDiffer !is null; |
539 } | |
540 | |
541 } |