comparison dwtx/jface/text/source/ChangeRulerColumn.d @ 129:eb30df5ca28b

Added JFace Text sources
author Frank Benoit <benoit@tionex.de>
date Sat, 23 Aug 2008 19:10:48 +0200
parents
children c4fb132a086c
comparison
equal deleted inserted replaced
128:8df1d4193877 129:eb30df5ca28b
1 /*******************************************************************************
2 * Copyright (c) 2000, 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.text.source.ChangeRulerColumn;
14
15 import dwt.dwthelper.utils;
16
17
18
19
20
21 import dwt.DWT;
22 import dwt.custom.StyledText;
23 import dwt.events.DisposeEvent;
24 import dwt.events.DisposeListener;
25 import dwt.events.MouseEvent;
26 import dwt.events.MouseListener;
27 import dwt.events.MouseMoveListener;
28 import dwt.events.PaintEvent;
29 import dwt.events.PaintListener;
30 import dwt.graphics.Color;
31 import dwt.graphics.Font;
32 import dwt.graphics.GC;
33 import dwt.graphics.Image;
34 import dwt.graphics.Point;
35 import dwt.graphics.Rectangle;
36 import dwt.widgets.Canvas;
37 import dwt.widgets.Composite;
38 import dwt.widgets.Control;
39 import dwt.widgets.Display;
40 import dwtx.core.runtime.Assert;
41 import dwtx.jface.internal.text.revisions.RevisionPainter;
42 import dwtx.jface.internal.text.source.DiffPainter;
43 import dwtx.jface.text.BadLocationException;
44 import dwtx.jface.text.IDocument;
45 import dwtx.jface.text.IRegion;
46 import dwtx.jface.text.ITextListener;
47 import dwtx.jface.text.ITextViewer;
48 import dwtx.jface.text.ITextViewerExtension5;
49 import dwtx.jface.text.IViewportListener;
50 import dwtx.jface.text.JFaceTextUtil;
51 import dwtx.jface.text.TextEvent;
52 import dwtx.jface.text.revisions.IRevisionRulerColumn;
53 import dwtx.jface.text.revisions.RevisionInformation;
54 import dwtx.jface.viewers.ISelectionProvider;
55
56 /**
57 * A vertical ruler column displaying line numbers and serving as a UI for quick diff.
58 * Clients instantiate and configure object of this class.
59 *
60 * @since 3.0
61 */
62 public final class ChangeRulerColumn : IVerticalRulerColumn, IVerticalRulerInfo, IVerticalRulerInfoExtension, IChangeRulerColumn, IRevisionRulerColumn {
63 /**
64 * Handles all the mouse interaction in this line number ruler column.
65 */
66 private class MouseHandler : MouseListener, MouseMoveListener {
67
68 /*
69 * @see dwt.events.MouseListener#mouseUp(dwt.events.MouseEvent)
70 */
71 public void mouseUp(MouseEvent event) {
72 }
73
74 /*
75 * @see dwt.events.MouseListener#mouseDown(dwt.events.MouseEvent)
76 */
77 public void mouseDown(MouseEvent event) {
78 fParentRuler.setLocationOfLastMouseButtonActivity(event.x, event.y);
79 }
80
81 /*
82 * @see dwt.events.MouseListener#mouseDoubleClick(dwt.events.MouseEvent)
83 */
84 public void mouseDoubleClick(MouseEvent event) {
85 fParentRuler.setLocationOfLastMouseButtonActivity(event.x, event.y);
86 }
87
88 /*
89 * @see dwt.events.MouseMoveListener#mouseMove(dwt.events.MouseEvent)
90 */
91 public void mouseMove(MouseEvent event) {
92 fParentRuler.setLocationOfLastMouseButtonActivity(event.x, event.y);
93 }
94 }
95
96 /**
97 * Internal listener class.
98 */
99 private class InternalListener : IViewportListener, ITextListener {
100
101 /*
102 * @see IViewportListener#viewportChanged(int)
103 */
104 public void viewportChanged(int verticalPosition) {
105 if (verticalPosition !is fScrollPos)
106 redraw();
107 }
108
109 /*
110 * @see ITextListener#textChanged(TextEvent)
111 */
112 public void textChanged(TextEvent event) {
113
114 if (!event.getViewerRedrawState())
115 return;
116
117 if (fSensitiveToTextChanges || event.getDocumentEvent() is null)
118 postRedraw();
119
120 }
121 }
122
123 /**
124 * The view(port) listener.
125 */
126 private final InternalListener fInternalListener= new InternalListener();
127 /**
128 * The mouse handler.
129 * @since 3.2
130 */
131 private final MouseHandler fMouseHandler= new MouseHandler();
132 /**
133 * The revision painter.
134 * @since 3.2
135 */
136 private final RevisionPainter fRevisionPainter;
137 /**
138 * The diff info painter.
139 * @since 3.2
140 */
141 private final DiffPainter fDiffPainter;
142
143 /** This column's parent ruler */
144 private CompositeRuler fParentRuler;
145 /** Cached text viewer */
146 private ITextViewer fCachedTextViewer;
147 /** Cached text widget */
148 private StyledText fCachedTextWidget;
149 /** The columns canvas */
150 private Canvas fCanvas;
151 /** The background color */
152 private Color fBackground;
153 /** The ruler's annotation model. */
154 private IAnnotationModel fAnnotationModel;
155 /** The width of the change ruler column. */
156 private final int fWidth= 5;
157
158 /** Cache for the actual scroll position in pixels */
159 private int fScrollPos;
160 /** The buffer for double buffering */
161 private Image fBuffer;
162 /** Indicates whether this column reacts on text change events */
163 private bool fSensitiveToTextChanges= false;
164
165 /**
166 * Creates a new ruler column.
167 *
168 * @deprecated since 3.2 use {@link #ChangeRulerColumn(ISharedTextColors)} instead
169 */
170 public ChangeRulerColumn() {
171 fRevisionPainter= null;
172 fDiffPainter= new DiffPainter(this, null);
173 }
174
175 /**
176 * Creates a new revision ruler column.
177 *
178 * @param sharedColors the colors to look up RGBs
179 * @since 3.2
180 */
181 public ChangeRulerColumn(ISharedTextColors sharedColors) {
182 Assert.isNotNull(sharedColors);
183 fRevisionPainter= new RevisionPainter(this, sharedColors);
184 fDiffPainter= new DiffPainter(this, null); // no shading
185 }
186
187 /**
188 * Returns the System background color for list widgets.
189 *
190 * @return the System background color for list widgets
191 */
192 private Color getBackground() {
193 if (fBackground is null)
194 return fCachedTextWidget.getDisplay().getSystemColor(DWT.COLOR_LIST_BACKGROUND);
195 return fBackground;
196 }
197
198 /*
199 * @see IVerticalRulerColumn#createControl(CompositeRuler, Composite)
200 */
201 public Control createControl(CompositeRuler parentRuler, Composite parentControl) {
202
203 fParentRuler= parentRuler;
204 fCachedTextViewer= parentRuler.getTextViewer();
205 fCachedTextWidget= fCachedTextViewer.getTextWidget();
206
207 fCanvas= new Canvas(parentControl, DWT.NONE);
208 fCanvas.setBackground(getBackground());
209
210 fCanvas.addPaintListener(new PaintListener() {
211 public void paintControl(PaintEvent event) {
212 if (fCachedTextViewer !is null)
213 doubleBufferPaint(event.gc);
214 }
215 });
216
217 fCanvas.addDisposeListener(new DisposeListener() {
218 public void widgetDisposed(DisposeEvent e) {
219 handleDispose();
220 fCachedTextViewer= null;
221 fCachedTextWidget= null;
222 }
223 });
224
225 fCanvas.addMouseListener(fMouseHandler);
226 fCanvas.addMouseMoveListener(fMouseHandler);
227
228 if (fCachedTextViewer !is null) {
229
230 fCachedTextViewer.addViewportListener(fInternalListener);
231 fCachedTextViewer.addTextListener(fInternalListener);
232 }
233
234 fRevisionPainter.setParentRuler(parentRuler);
235 fDiffPainter.setParentRuler(parentRuler);
236
237 return fCanvas;
238 }
239
240 /**
241 * Disposes the column's resources.
242 */
243 protected void handleDispose() {
244
245 if (fCachedTextViewer !is null) {
246 fCachedTextViewer.removeViewportListener(fInternalListener);
247 fCachedTextViewer.removeTextListener(fInternalListener);
248 }
249
250 if (fBuffer !is null) {
251 fBuffer.dispose();
252 fBuffer= null;
253 }
254 }
255
256 /**
257 * Double buffer drawing.
258 *
259 * @param dest the GC to draw into
260 */
261 private void doubleBufferPaint(GC dest) {
262
263 Point size= fCanvas.getSize();
264
265 if (size.x <= 0 || size.y <= 0)
266 return;
267
268 if (fBuffer !is null) {
269 Rectangle r= fBuffer.getBounds();
270 if (r.width !is size.x || r.height !is size.y) {
271 fBuffer.dispose();
272 fBuffer= null;
273 }
274 }
275 if (fBuffer is null)
276 fBuffer= new Image(fCanvas.getDisplay(), size.x, size.y);
277
278 GC gc= new GC(fBuffer);
279 gc.setFont(fCanvas.getFont());
280
281 try {
282 gc.setBackground(getBackground());
283 gc.fillRectangle(0, 0, size.x, size.y);
284
285 doPaint(gc);
286 } finally {
287 gc.dispose();
288 }
289
290 dest.drawImage(fBuffer, 0, 0);
291 }
292
293 /**
294 * Returns the view port height in lines.
295 *
296 * @return the view port height in lines
297 * @deprecated as of 3.2 the number of lines in the viewport cannot be computed because
298 * StyledText supports variable line heights
299 */
300 protected int getVisibleLinesInViewport() {
301 // Hack to reduce amount of copied code.
302 return LineNumberRulerColumn.getVisibleLinesInViewport(fCachedTextWidget);
303 }
304
305 /**
306 * Returns <code>true</code> if the viewport displays the entire viewer contents, i.e. the
307 * viewer is not vertically scrollable.
308 *
309 * @return <code>true</code> if the viewport displays the entire contents, <code>false</code> otherwise
310 * @since 3.2
311 */
312 protected final bool isViewerCompletelyShown() {
313 return JFaceTextUtil.isShowingEntireContents(fCachedTextWidget);
314 }
315
316 /**
317 * Draws the ruler column.
318 *
319 * @param gc the GC to draw into
320 */
321 private void doPaint(GC gc) {
322 ILineRange visibleModelLines= computeVisibleModelLines();
323 if (visibleModelLines is null)
324 return;
325
326 fSensitiveToTextChanges= isViewerCompletelyShown();
327
328 fScrollPos= fCachedTextWidget.getTopPixel();
329
330 fRevisionPainter.paint(gc, visibleModelLines);
331 if (!fRevisionPainter.hasInformation()) // don't paint quick diff colors if revisions are painted
332 fDiffPainter.paint(gc, visibleModelLines);
333 }
334
335 /*
336 * @see IVerticalRulerColumn#redraw()
337 */
338 public void redraw() {
339
340 if (fCachedTextViewer !is null && fCanvas !is null && !fCanvas.isDisposed()) {
341 GC gc= new GC(fCanvas);
342 doubleBufferPaint(gc);
343 gc.dispose();
344 }
345 }
346
347 /*
348 * @see IVerticalRulerColumn#setFont(Font)
349 */
350 public void setFont(Font font) {
351 }
352
353 /**
354 * Returns the parent (composite) ruler of this ruler column.
355 *
356 * @return the parent ruler
357 * @since 3.0
358 */
359 private CompositeRuler getParentRuler() {
360 return fParentRuler;
361 }
362
363 /*
364 * @see dwtx.jface.text.source.IVerticalRulerInfo#getLineOfLastMouseButtonActivity()
365 */
366 public int getLineOfLastMouseButtonActivity() {
367 return getParentRuler().getLineOfLastMouseButtonActivity();
368 }
369
370 /*
371 * @see dwtx.jface.text.source.IVerticalRulerInfo#toDocumentLineNumber(int)
372 */
373 public int toDocumentLineNumber(int y_coordinate) {
374 return getParentRuler().toDocumentLineNumber(y_coordinate);
375 }
376
377 /*
378 * @see dwtx.jface.text.source.IVerticalRulerInfoExtension#getHover()
379 */
380 public IAnnotationHover getHover() {
381 int activeLine= getParentRuler().getLineOfLastMouseButtonActivity();
382 if (fRevisionPainter.hasHover(activeLine))
383 return fRevisionPainter.getHover();
384 if (fDiffPainter.hasHover(activeLine))
385 return fDiffPainter.getHover();
386 return null;
387 }
388
389 /*
390 * @see dwtx.jface.text.source.IChangeRulerColumn#setHover(dwtx.jface.text.source.IAnnotationHover)
391 */
392 public void setHover(IAnnotationHover hover) {
393 fRevisionPainter.setHover(hover);
394 fDiffPainter.setHover(hover);
395 }
396
397 /*
398 * @see IVerticalRulerColumn#setModel(IAnnotationModel)
399 */
400 public void setModel(IAnnotationModel model) {
401 setAnnotationModel(model);
402 fRevisionPainter.setModel(model);
403 fDiffPainter.setModel(model);
404 }
405
406 private void setAnnotationModel(IAnnotationModel model) {
407 if (fAnnotationModel !is model)
408 fAnnotationModel= model;
409 }
410
411 /*
412 * @see dwtx.jface.text.source.IChangeRulerColumn#setBackground(dwt.graphics.Color)
413 */
414 public void setBackground(Color background) {
415 fBackground= background;
416 if (fCanvas !is null && !fCanvas.isDisposed())
417 fCanvas.setBackground(getBackground());
418 fRevisionPainter.setBackground(background);
419 fDiffPainter.setBackground(background);
420 }
421
422 /*
423 * @see dwtx.jface.text.source.IChangeRulerColumn#setAddedColor(dwt.graphics.Color)
424 */
425 public void setAddedColor(Color addedColor) {
426 fDiffPainter.setAddedColor(addedColor);
427 }
428
429 /*
430 * @see dwtx.jface.text.source.IChangeRulerColumn#setChangedColor(dwt.graphics.Color)
431 */
432 public void setChangedColor(Color changedColor) {
433 fDiffPainter.setChangedColor(changedColor);
434 }
435
436 /*
437 * @see dwtx.jface.text.source.IChangeRulerColumn#setDeletedColor(dwt.graphics.Color)
438 */
439 public void setDeletedColor(Color deletedColor) {
440 fDiffPainter.setDeletedColor(deletedColor);
441 }
442
443 /*
444 * @see dwtx.jface.text.source.IVerticalRulerInfoExtension#getModel()
445 */
446 public IAnnotationModel getModel() {
447 return fAnnotationModel;
448 }
449
450 /*
451 * @see IVerticalRulerColumn#getControl()
452 */
453 public Control getControl() {
454 return fCanvas;
455 }
456
457 /*
458 * @see dwtx.jface.text.source.IVerticalRulerInfo#getWidth()
459 */
460 public int getWidth() {
461 return fWidth;
462 }
463
464 /**
465 * Triggers a redraw in the display thread.
466 */
467 protected final void postRedraw() {
468 if (fCanvas !is null && !fCanvas.isDisposed()) {
469 Display d= fCanvas.getDisplay();
470 if (d !is null) {
471 d.asyncExec(new Runnable() {
472 public void run() {
473 redraw();
474 }
475 });
476 }
477 }
478 }
479
480 /*
481 * @see dwtx.jface.text.source.IVerticalRulerInfoExtension#addVerticalRulerListener(dwtx.jface.text.source.IVerticalRulerListener)
482 */
483 public void addVerticalRulerListener(IVerticalRulerListener listener) {
484 throw new UnsupportedOperationException();
485 }
486
487 /*
488 * @see dwtx.jface.text.source.IVerticalRulerInfoExtension#removeVerticalRulerListener(dwtx.jface.text.source.IVerticalRulerListener)
489 */
490 public void removeVerticalRulerListener(IVerticalRulerListener listener) {
491 throw new UnsupportedOperationException();
492 }
493
494 /**
495 * Computes the document based line range visible in the text widget.
496 *
497 * @return the document based line range visible in the text widget
498 * @since 3.2
499 */
500 private final ILineRange computeVisibleModelLines() {
501 IDocument doc= fCachedTextViewer.getDocument();
502 if (doc is null)
503 return null;
504
505 int topLine;
506 IRegion coverage;
507
508 if (fCachedTextViewer instanceof ITextViewerExtension5) {
509 ITextViewerExtension5 extension= (ITextViewerExtension5) fCachedTextViewer;
510
511 // ITextViewer.getTopIndex returns the fully visible line, but we want the partially
512 // visible one
513 int widgetTopLine= JFaceTextUtil.getPartialTopIndex(fCachedTextWidget);
514 topLine= extension.widgetLine2ModelLine(widgetTopLine);
515
516 coverage= extension.getModelCoverage();
517
518 } else {
519 topLine= JFaceTextUtil.getPartialTopIndex(fCachedTextViewer);
520 coverage= fCachedTextViewer.getVisibleRegion();
521 }
522
523 int bottomLine= fCachedTextViewer.getBottomIndex();
524 if (bottomLine !is -1)
525 ++ bottomLine;
526
527 // clip by coverage window
528 try {
529 int firstLine= doc.getLineOfOffset(coverage.getOffset());
530 if (firstLine > topLine)
531 topLine= firstLine;
532
533 int lastLine= doc.getLineOfOffset(coverage.getOffset() + coverage.getLength());
534 if (lastLine < bottomLine || bottomLine is -1)
535 bottomLine= lastLine;
536 } catch (BadLocationException x) {
537 x.printStackTrace();
538 return null;
539 }
540
541 ILineRange visibleModelLines= new LineRange(topLine, bottomLine - topLine + 1);
542 return visibleModelLines;
543 }
544
545 /*
546 * @see dwtx.jface.text.revisions.IRevisionRulerColumn#setRevisionInformation(dwtx.jface.text.revisions.RevisionInformation)
547 */
548 public void setRevisionInformation(RevisionInformation info) {
549 fRevisionPainter.setRevisionInformation(info);
550 fRevisionPainter.setBackground(getBackground());
551 }
552
553 /**
554 * Returns the revision selection provider.
555 *
556 * @return the revision selection provider
557 * @since 3.2
558 */
559 public ISelectionProvider getRevisionSelectionProvider() {
560 return fRevisionPainter.getRevisionSelectionProvider();
561 }
562 }