1 11 package org.eclipse.jface.internal.text.source; 12 13 import org.eclipse.swt.SWT; 14 import org.eclipse.swt.custom.StyledText; 15 import org.eclipse.swt.events.DisposeEvent; 16 import org.eclipse.swt.events.DisposeListener; 17 import org.eclipse.swt.graphics.Color; 18 import org.eclipse.swt.graphics.GC; 19 import org.eclipse.swt.graphics.RGB; 20 import org.eclipse.swt.widgets.Canvas; 21 import org.eclipse.swt.widgets.Control; 22 import org.eclipse.swt.widgets.Display; 23 24 import org.eclipse.core.runtime.Assert; 25 26 import org.eclipse.jface.text.ITextViewer; 27 import org.eclipse.jface.text.JFaceTextUtil; 28 import org.eclipse.jface.text.source.CompositeRuler; 29 import org.eclipse.jface.text.source.IAnnotationHover; 30 import org.eclipse.jface.text.source.IAnnotationModel; 31 import org.eclipse.jface.text.source.IAnnotationModelExtension; 32 import org.eclipse.jface.text.source.IAnnotationModelListener; 33 import org.eclipse.jface.text.source.IChangeRulerColumn; 34 import org.eclipse.jface.text.source.ILineDiffInfo; 35 import org.eclipse.jface.text.source.ILineDiffer; 36 import org.eclipse.jface.text.source.ILineDifferExtension2; 37 import org.eclipse.jface.text.source.ILineRange; 38 import org.eclipse.jface.text.source.ISharedTextColors; 39 import org.eclipse.jface.text.source.IVerticalRulerColumn; 40 41 42 48 public final class DiffPainter { 49 52 private class AnnotationListener implements IAnnotationModelListener { 53 56 public void modelChanged(IAnnotationModel model) { 57 postRedraw(); 58 } 59 } 60 61 62 private final IVerticalRulerColumn fColumn; 63 64 private CompositeRuler fParentRuler; 65 66 private Control fControl; 67 68 private ITextViewer fViewer; 69 70 private StyledText fWidget; 71 72 private ILineDiffer fLineDiffer= null; 73 74 private Color fAddedColor; 75 76 private Color fChangedColor; 77 78 private Color fDeletedColor; 79 80 private Color fBackground; 81 82 private IAnnotationHover fHover; 83 84 private final AnnotationListener fAnnotationListener= new AnnotationListener(); 85 86 private final ISharedTextColors fSharedColors; 87 88 96 public DiffPainter(IVerticalRulerColumn column, ISharedTextColors sharedColors) { 97 Assert.isLegal(column != null); 98 fColumn= column; 99 fSharedColors= sharedColors; 100 } 101 102 108 public void setParentRuler(CompositeRuler parentRuler) { 109 fParentRuler= parentRuler; 110 } 111 112 117 public void setHover(IAnnotationHover hover) { 118 fHover= hover; 119 } 120 121 126 public IAnnotationHover getHover() { 127 return fHover; 128 } 129 130 135 public void setBackground(Color background) { 136 fBackground= background; 137 } 138 139 148 public void paint(GC gc, ILineRange visibleModelLines) { 149 connectIfNeeded(); 150 if (!isConnected()) 151 return; 152 153 final int lastLine= end(visibleModelLines); 155 final int width= getWidth(); 156 final Color deletionColor= getDeletionColor(); 157 for (int line= visibleModelLines.getStartLine(); line < lastLine; line++) { 158 paintLine(line, gc, width, deletionColor); 159 } 160 } 161 162 166 private void connectIfNeeded() { 167 if (isConnected() || fParentRuler == null) 168 return; 169 170 fViewer= fParentRuler.getTextViewer(); 171 if (fViewer == null) 172 return; 173 174 fWidget= fViewer.getTextWidget(); 175 if (fWidget == null) 176 return; 177 178 fControl= fColumn.getControl(); 179 if (fControl == null) 180 return; 181 182 fControl.addDisposeListener(new DisposeListener() { 183 186 public void widgetDisposed(DisposeEvent e) { 187 handleDispose(); 188 } 189 }); 190 } 191 192 197 private boolean isConnected() { 198 return fControl != null; 199 } 200 201 204 private void handleDispose() { 205 if (fLineDiffer != null) { 206 ((IAnnotationModel) fLineDiffer).removeAnnotationModelListener(fAnnotationListener); 207 fLineDiffer= null; 208 } 209 } 210 211 219 private void paintLine(int line, GC gc, int width, Color deletionColor) { 220 int widgetLine= JFaceTextUtil.modelLineToWidgetLine(fViewer, line); 221 if (widgetLine == -1) 222 return; 223 224 ILineDiffInfo info= getDiffInfo(line); 225 226 if (info != null) { 227 int y= fWidget.getLinePixel(widgetLine); 228 int lineHeight= fWidget.getLineHeight(fWidget.getOffsetAtLine(widgetLine)); 229 230 if (hasSpecialColor(info)) { 232 gc.setBackground(getColor(info)); 233 gc.fillRectangle(0, y, width, lineHeight); 234 } 235 236 237 int delBefore= info.getRemovedLinesAbove(); 238 int delBelow= info.getRemovedLinesBelow(); 239 if (delBefore > 0 || delBelow > 0) { 240 gc.setForeground(deletionColor); 241 if (delBefore > 0) 242 gc.drawLine(0, y, width, y); 243 if (delBelow > 0) 244 gc.drawLine(0, y + lineHeight - 1, width, y + lineHeight - 1); 245 } 246 } 247 } 248 249 256 private boolean hasSpecialColor(ILineDiffInfo info) { 257 return info.getChangeType() == ILineDiffInfo.ADDED || info.getChangeType() == ILineDiffInfo.CHANGED; 258 } 259 260 267 private ILineDiffInfo getDiffInfo(int line) { 268 if (fLineDiffer != null) 269 return fLineDiffer.getLineInfo(line); 270 271 return null; 272 } 273 274 279 private Color getDeletionColor() { 280 return fDeletedColor == null ? getBackground() : fDeletedColor; 281 } 282 283 289 private Color getColor(ILineDiffInfo info) { 290 Assert.isTrue(info != null && info.getChangeType() != ILineDiffInfo.UNCHANGED); 291 Color ret= null; 292 switch (info.getChangeType()) { 293 case ILineDiffInfo.CHANGED: 294 ret= getShadedColor(fChangedColor); 295 break; 296 case ILineDiffInfo.ADDED: 297 ret= getShadedColor(fAddedColor); 298 break; 299 } 300 return ret == null ? getBackground() : ret; 301 } 302 303 309 private Color getShadedColor(Color color) { 310 if (color == null) 311 return null; 312 313 if (fSharedColors == null) 314 return color; 315 316 RGB baseRGB= color.getRGB(); 317 RGB background= getBackground().getRGB(); 318 319 boolean darkBase= isDark(baseRGB); 320 boolean darkBackground= isDark(background); 321 if (darkBase && darkBackground) 322 background= new RGB(255, 255, 255); 323 else if (!darkBase && !darkBackground) 324 background= new RGB(0, 0, 0); 325 326 return fSharedColors.getColor(interpolate(baseRGB, background, 0.6)); 327 } 328 329 335 public void setModel(IAnnotationModel model) { 336 IAnnotationModel newModel; 337 if (model instanceof IAnnotationModelExtension) 338 newModel= ((IAnnotationModelExtension) model).getAnnotationModel(IChangeRulerColumn.QUICK_DIFF_MODEL_ID); 339 else 340 newModel= model; 341 342 setDiffer(newModel); 343 } 344 345 350 private void setDiffer(IAnnotationModel differ) { 351 if (differ instanceof ILineDiffer) { 352 if (fLineDiffer != differ) { 353 if (fLineDiffer != null) 354 ((IAnnotationModel) fLineDiffer).removeAnnotationModelListener(fAnnotationListener); 355 fLineDiffer= (ILineDiffer) differ; 356 if (fLineDiffer != null) 357 ((IAnnotationModel) fLineDiffer).addAnnotationModelListener(fAnnotationListener); 358 } 359 } 360 } 361 362 365 private final void postRedraw() { 366 if (isConnected() && !fControl.isDisposed()) { 367 Display d= fControl.getDisplay(); 368 if (d != null) { 369 d.asyncExec(new Runnable () { 370 public void run() { 371 redraw(); 372 } 373 }); 374 } 375 } 376 } 377 378 381 private void redraw() { 382 fColumn.redraw(); 383 } 384 385 390 private int getWidth() { 391 return fColumn.getWidth(); 392 } 393 394 400 private static int end(ILineRange range) { 401 return range.getStartLine() + range.getNumberOfLines(); 402 } 403 404 409 private Color getBackground() { 410 if (fBackground == null) 411 return fWidget.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND); 412 return fBackground; 413 } 414 415 421 public void setAddedColor(Color addedColor) { 422 fAddedColor= addedColor; 423 } 424 425 431 public void setChangedColor(Color changedColor) { 432 fChangedColor= changedColor; 433 } 434 435 441 public void setDeletedColor(Color deletedColor) { 442 fDeletedColor= deletedColor; 443 } 444 445 451 public boolean hasHover(int activeLine) { 452 return true; 453 } 454 455 461 public String getDisplayCharacter(int line) { 462 return getDisplayCharacter(getDiffInfo(line)); 463 } 464 465 472 private String getDisplayCharacter(ILineDiffInfo info) { 473 if (info == null) 474 return " "; switch (info.getChangeType()) { 476 case ILineDiffInfo.CHANGED: 477 return "~"; case ILineDiffInfo.ADDED: 479 return "+"; } 481 return " "; } 483 484 493 private static RGB interpolate(RGB fg, RGB bg, double scale) { 494 return new RGB((int) ((1.0 - scale) * fg.red + scale * bg.red), (int) ((1.0 - scale) * fg.green + scale * bg.green), (int) ((1.0 - scale) * fg.blue + scale * bg.blue)); 495 } 496 497 503 private static double greyLevel(RGB rgb) { 504 if (rgb.red == rgb.green && rgb.green == rgb.blue) 505 return rgb.red; 506 return (0.299 * rgb.red + 0.587 * rgb.green + 0.114 * rgb.blue + 0.5); 507 } 508 509 515 private static boolean isDark(RGB rgb) { 516 return greyLevel(rgb) > 128; 517 } 518 519 525 public boolean hasInformation() { 526 if (fLineDiffer instanceof ILineDifferExtension2) 527 return !((ILineDifferExtension2) fLineDiffer).isSuspended(); 528 return fLineDiffer != null; 529 } 530 531 } 532 | Popular Tags |