comparison org.eclipse.jface.text/src/org/eclipse/jface/text/source/LineNumberRulerColumn.d @ 12:bc29606a740c

Added dwt-addons in original directory structure of eclipse.org
author Frank Benoit <benoit@tionex.de>
date Sat, 14 Mar 2009 18:23:29 +0100
parents
children
comparison
equal deleted inserted replaced
11:43904fec5dca 12:bc29606a740c
1 /*******************************************************************************
2 * Copyright (c) 2000, 2008 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 * Nikolay Botev <bono8106@hotmail.com> - [rulers] Shift clicking in line number column doesn't select range - https://bugs.eclipse.org/bugs/show_bug.cgi?id=32166
11 * Nikolay Botev <bono8106@hotmail.com> - [rulers] Clicking in line number ruler should not trigger annotation ruler - https://bugs.eclipse.org/bugs/show_bug.cgi?id=40889
12 * Port to the D programming language:
13 * Frank Benoit <benoit@tionex.de>
14 *******************************************************************************/
15 module org.eclipse.jface.text.source.LineNumberRulerColumn;
16
17 import org.eclipse.jface.text.source.ISharedTextColors; // packageimport
18 import org.eclipse.jface.text.source.ILineRange; // packageimport
19 import org.eclipse.jface.text.source.IAnnotationPresentation; // packageimport
20 import org.eclipse.jface.text.source.IVerticalRulerInfoExtension; // packageimport
21 import org.eclipse.jface.text.source.ICharacterPairMatcher; // packageimport
22 import org.eclipse.jface.text.source.TextInvocationContext; // packageimport
23 import org.eclipse.jface.text.source.LineChangeHover; // packageimport
24 import org.eclipse.jface.text.source.IChangeRulerColumn; // packageimport
25 import org.eclipse.jface.text.source.IAnnotationMap; // packageimport
26 import org.eclipse.jface.text.source.IAnnotationModelListenerExtension; // packageimport
27 import org.eclipse.jface.text.source.ISourceViewerExtension2; // packageimport
28 import org.eclipse.jface.text.source.IAnnotationHover; // packageimport
29 import org.eclipse.jface.text.source.ContentAssistantFacade; // packageimport
30 import org.eclipse.jface.text.source.IAnnotationAccess; // packageimport
31 import org.eclipse.jface.text.source.IVerticalRulerExtension; // packageimport
32 import org.eclipse.jface.text.source.IVerticalRulerColumn; // packageimport
33 import org.eclipse.jface.text.source.MatchingCharacterPainter; // packageimport
34 import org.eclipse.jface.text.source.IAnnotationModelExtension; // packageimport
35 import org.eclipse.jface.text.source.ILineDifferExtension; // packageimport
36 import org.eclipse.jface.text.source.DefaultCharacterPairMatcher; // packageimport
37 import org.eclipse.jface.text.source.LineNumberChangeRulerColumn; // packageimport
38 import org.eclipse.jface.text.source.IAnnotationAccessExtension; // packageimport
39 import org.eclipse.jface.text.source.ISourceViewer; // packageimport
40 import org.eclipse.jface.text.source.AnnotationModel; // packageimport
41 import org.eclipse.jface.text.source.ILineDifferExtension2; // packageimport
42 import org.eclipse.jface.text.source.IAnnotationModelListener; // packageimport
43 import org.eclipse.jface.text.source.IVerticalRuler; // packageimport
44 import org.eclipse.jface.text.source.DefaultAnnotationHover; // packageimport
45 import org.eclipse.jface.text.source.SourceViewer; // packageimport
46 import org.eclipse.jface.text.source.SourceViewerConfiguration; // packageimport
47 import org.eclipse.jface.text.source.AnnotationBarHoverManager; // packageimport
48 import org.eclipse.jface.text.source.CompositeRuler; // packageimport
49 import org.eclipse.jface.text.source.ImageUtilities; // packageimport
50 import org.eclipse.jface.text.source.VisualAnnotationModel; // packageimport
51 import org.eclipse.jface.text.source.IAnnotationModel; // packageimport
52 import org.eclipse.jface.text.source.ISourceViewerExtension3; // packageimport
53 import org.eclipse.jface.text.source.ILineDiffInfo; // packageimport
54 import org.eclipse.jface.text.source.VerticalRulerEvent; // packageimport
55 import org.eclipse.jface.text.source.ChangeRulerColumn; // packageimport
56 import org.eclipse.jface.text.source.ILineDiffer; // packageimport
57 import org.eclipse.jface.text.source.AnnotationModelEvent; // packageimport
58 import org.eclipse.jface.text.source.AnnotationColumn; // packageimport
59 import org.eclipse.jface.text.source.AnnotationRulerColumn; // packageimport
60 import org.eclipse.jface.text.source.IAnnotationHoverExtension; // packageimport
61 import org.eclipse.jface.text.source.AbstractRulerColumn; // packageimport
62 import org.eclipse.jface.text.source.ISourceViewerExtension; // packageimport
63 import org.eclipse.jface.text.source.AnnotationMap; // packageimport
64 import org.eclipse.jface.text.source.IVerticalRulerInfo; // packageimport
65 import org.eclipse.jface.text.source.IAnnotationModelExtension2; // packageimport
66 import org.eclipse.jface.text.source.LineRange; // packageimport
67 import org.eclipse.jface.text.source.IAnnotationAccessExtension2; // packageimport
68 import org.eclipse.jface.text.source.VerticalRuler; // packageimport
69 import org.eclipse.jface.text.source.JFaceTextMessages; // packageimport
70 import org.eclipse.jface.text.source.IOverviewRuler; // packageimport
71 import org.eclipse.jface.text.source.Annotation; // packageimport
72 import org.eclipse.jface.text.source.IVerticalRulerListener; // packageimport
73 import org.eclipse.jface.text.source.ISourceViewerExtension4; // packageimport
74 import org.eclipse.jface.text.source.AnnotationPainter; // packageimport
75 import org.eclipse.jface.text.source.IAnnotationHoverExtension2; // packageimport
76 import org.eclipse.jface.text.source.OverviewRuler; // packageimport
77 import org.eclipse.jface.text.source.OverviewRulerHoverManager; // packageimport
78
79
80 import java.lang.all;
81 import java.util.Arrays;
82 import java.util.Set;
83
84
85 import org.eclipse.swt.SWT;
86 import org.eclipse.swt.custom.StyledText;
87 import org.eclipse.swt.events.DisposeEvent;
88 import org.eclipse.swt.events.DisposeListener;
89 import org.eclipse.swt.events.MouseEvent;
90 import org.eclipse.swt.events.MouseListener;
91 import org.eclipse.swt.events.MouseMoveListener;
92 import org.eclipse.swt.events.PaintEvent;
93 import org.eclipse.swt.events.PaintListener;
94 import org.eclipse.swt.graphics.Color;
95 import org.eclipse.swt.graphics.Font;
96 import org.eclipse.swt.graphics.FontMetrics;
97 import org.eclipse.swt.graphics.GC;
98 import org.eclipse.swt.graphics.Image;
99 import org.eclipse.swt.graphics.Point;
100 import org.eclipse.swt.graphics.Rectangle;
101 import org.eclipse.swt.widgets.Canvas;
102 import org.eclipse.swt.widgets.Composite;
103 import org.eclipse.swt.widgets.Control;
104 import org.eclipse.swt.widgets.Display;
105 import org.eclipse.swt.widgets.TypedListener;
106 import org.eclipse.jface.text.BadLocationException;
107 import org.eclipse.jface.text.IDocument;
108 import org.eclipse.jface.text.IRegion;
109 import org.eclipse.jface.text.ITextListener;
110 import org.eclipse.jface.text.ITextViewer;
111 import org.eclipse.jface.text.ITextViewerExtension;
112 import org.eclipse.jface.text.ITextViewerExtension5;
113 import org.eclipse.jface.text.IViewportListener;
114 import org.eclipse.jface.text.JFaceTextUtil;
115 import org.eclipse.jface.text.TextEvent;
116
117
118 /**
119 * A vertical ruler column displaying line numbers.
120 * Clients usually instantiate and configure object of this class.
121 *
122 * @since 2.0
123 */
124 public class LineNumberRulerColumn : IVerticalRulerColumn {
125
126 /**
127 * Internal listener class.
128 */
129 class InternalListener : IViewportListener, ITextListener {
130
131 /**
132 * @since 3.1
133 */
134 private bool fCachedRedrawState= true;
135
136 /*
137 * @see IViewportListener#viewportChanged(int)
138 */
139 public void viewportChanged(int verticalPosition) {
140 if (fCachedRedrawState && verticalPosition !is fScrollPos)
141 redraw();
142 }
143
144 /*
145 * @see ITextListener#textChanged(TextEvent)
146 */
147 public void textChanged(TextEvent event) {
148
149 fCachedRedrawState= event.getViewerRedrawState();
150 if (!fCachedRedrawState)
151 return;
152
153 if (updateNumberOfDigits()) {
154 computeIndentations();
155 layout(event.getViewerRedrawState());
156 return;
157 }
158
159 bool viewerCompletelyShown= isViewerCompletelyShown();
160 if (viewerCompletelyShown || fSensitiveToTextChanges || event.getDocumentEvent() is null)
161 postRedraw();
162 fSensitiveToTextChanges= viewerCompletelyShown;
163 }
164 }
165
166 /**
167 * Handles all the mouse interaction in this line number ruler column.
168 */
169 class MouseHandler : MouseListener, MouseMoveListener {
170
171 /** The cached view port size. */
172 private int fCachedViewportSize;
173 /** The area of the line at which line selection started. */
174 private int fStartLineOffset;
175 /** The number of the line at which line selection started. */
176 private int fStartLineNumber;
177 /** The auto scroll direction. */
178 private int fAutoScrollDirection;
179 /* @since 3.2 */
180 private bool fIsListeningForMove= false;
181
182 /*
183 * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent)
184 */
185 public void mouseUp(MouseEvent event) {
186 // see bug 45700
187 if (event.button is 1) {
188 stopSelecting();
189 stopAutoScroll();
190 }
191 }
192
193 /*
194 * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent)
195 */
196 public void mouseDown(MouseEvent event) {
197 fParentRuler.setLocationOfLastMouseButtonActivity(event.x, event.y);
198 // see bug 45700
199 if (event.button is 1) {
200 startSelecting((event.stateMask & SWT.SHIFT) !is 0);
201 }
202 }
203
204 /*
205 * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent)
206 */
207 public void mouseDoubleClick(MouseEvent event) {
208 fParentRuler.setLocationOfLastMouseButtonActivity(event.x, event.y);
209 stopSelecting();
210 stopAutoScroll();
211 }
212
213 /*
214 * @see org.eclipse.swt.events.MouseMoveListener#mouseMove(org.eclipse.swt.events.MouseEvent)
215 */
216 public void mouseMove(MouseEvent event) {
217 if (fIsListeningForMove && !autoScroll(event)) {
218 int newLine= fParentRuler.toDocumentLineNumber(event.y);
219 expandSelection(newLine);
220 }
221 fParentRuler.setLocationOfLastMouseButtonActivity(event.x, event.y);
222 }
223
224 /**
225 * Called when line drag selection started. Adds mouse move and track
226 * listeners to this column's control.
227 *
228 * @param expandExistingSelection if <code>true</code> the existing selection will be expanded,
229 * otherwise a new selection is started
230 */
231 private void startSelecting(bool expandExistingSelection) {
232 try {
233
234 // select line
235 IDocument document= fCachedTextViewer.getDocument();
236 int lineNumber= fParentRuler.getLineOfLastMouseButtonActivity();
237 if (expandExistingSelection && cast(ITextViewerExtension5)fCachedTextViewer
238 && fCachedTextViewer.getTextWidget() !is null) {
239 ITextViewerExtension5 extension5= (cast(ITextViewerExtension5)fCachedTextViewer);
240 // Find model curosr position
241 int widgetCaret= fCachedTextViewer.getTextWidget().getCaretOffset();
242 int modelCaret= extension5.widgetOffset2ModelOffset(widgetCaret);
243 // Find model selection range
244 Point selection= fCachedTextViewer.getSelectedRange();
245 // Start from tail of selection range (opposite of cursor position)
246 int startOffset= modelCaret is selection.x ? selection.x + selection.y : selection.x;
247
248 fStartLineNumber= document.getLineOfOffset(startOffset);
249 fStartLineOffset= startOffset;
250
251 expandSelection(lineNumber);
252 } else {
253 fStartLineNumber= lineNumber;
254 fStartLineOffset= document.getLineInformation(fStartLineNumber).getOffset();
255 fCachedTextViewer.setSelectedRange(fStartLineOffset, 0);
256 }
257 fCachedViewportSize= getVisibleLinesInViewport();
258
259 // prepare for drag selection
260 fIsListeningForMove= true;
261
262 } catch (BadLocationException x) {
263 }
264 }
265
266 /**
267 * Called when line drag selection stopped. Removes all previously
268 * installed listeners from this column's control.
269 */
270 private void stopSelecting() {
271 // drag selection stopped
272 fIsListeningForMove= false;
273 }
274
275 /**
276 * Expands the line selection from the remembered start line to the
277 * given line.
278 *
279 * @param lineNumber the line to which to expand the selection
280 */
281 private void expandSelection(int lineNumber) {
282 try {
283
284 IDocument document= fCachedTextViewer.getDocument();
285 IRegion lineInfo= document.getLineInformation(lineNumber);
286
287 Display display= fCachedTextWidget.getDisplay();
288 Point absolutePosition= display.getCursorLocation();
289 Point relativePosition= fCachedTextWidget.toControl(absolutePosition);
290
291 int offset;
292
293 if (relativePosition.x < 0)
294 offset= lineInfo.getOffset();
295 else {
296 try {
297 int widgetOffset= fCachedTextWidget.getOffsetAtLocation(relativePosition);
298 Point p= fCachedTextWidget.getLocationAtOffset(widgetOffset);
299 if (p.x > relativePosition.x)
300 widgetOffset--;
301
302 // Convert to model offset
303 if ( cast(ITextViewerExtension5)fCachedTextViewer ) {
304 ITextViewerExtension5 extension= cast(ITextViewerExtension5)fCachedTextViewer;
305 offset= extension.widgetOffset2ModelOffset(widgetOffset);
306 } else
307 offset= widgetOffset + fCachedTextViewer.getVisibleRegion().getOffset();
308
309 } catch (IllegalArgumentException ex) {
310 int lineEndOffset= lineInfo.getOffset() + lineInfo.getLength();
311
312 // Convert to widget offset
313 int lineEndWidgetOffset;
314 if ( cast(ITextViewerExtension5)fCachedTextViewer ) {
315 ITextViewerExtension5 extension= cast(ITextViewerExtension5)fCachedTextViewer;
316 lineEndWidgetOffset= extension.modelOffset2WidgetOffset(lineEndOffset);
317 } else
318 lineEndWidgetOffset= lineEndOffset - fCachedTextViewer.getVisibleRegion().getOffset();
319
320 Point p= fCachedTextWidget.getLocationAtOffset(lineEndWidgetOffset);
321 if (p.x < relativePosition.x)
322 offset= lineEndOffset;
323 else
324 offset= lineInfo.getOffset();
325 }
326 }
327
328 int start= Math.min(fStartLineOffset, offset);
329 int end= Math.max(fStartLineOffset, offset);
330
331 if (lineNumber < fStartLineNumber)
332 fCachedTextViewer.setSelectedRange(end, start - end);
333 else
334 fCachedTextViewer.setSelectedRange(start, end - start);
335
336 } catch (BadLocationException x) {
337 }
338 }
339
340 /**
341 * Called when auto scrolling stopped. Clears the auto scroll direction.
342 */
343 private void stopAutoScroll() {
344 fAutoScrollDirection= SWT.NULL;
345 }
346
347 /**
348 * Called on drag selection.
349 *
350 * @param event the mouse event caught by the mouse move listener
351 * @return <code>true</code> if scrolling happened, <code>false</code> otherwise
352 */
353 private bool autoScroll(MouseEvent event) {
354 Rectangle area= fCanvas.getClientArea();
355
356 if (event.y > area.height) {
357 autoScroll(SWT.DOWN);
358 return true;
359 }
360
361 if (event.y < 0) {
362 autoScroll(SWT.UP);
363 return true;
364 }
365
366 stopAutoScroll();
367 return false;
368 }
369
370 /**
371 * Scrolls the viewer into the given direction.
372 *
373 * @param direction the scroll direction
374 */
375 private void autoScroll(int direction) {
376
377 if (fAutoScrollDirection is direction)
378 return;
379
380 final int TIMER_INTERVAL= 5;
381 final Display display= fCanvas.getDisplay();
382 Runnable timer= null;
383 switch (direction) {
384 case SWT.UP:
385 timer= new class() Runnable {
386 public void run() {
387 if (fAutoScrollDirection is SWT.UP) {
388 int top= getInclusiveTopIndex();
389 if (top > 0) {
390 fCachedTextViewer.setTopIndex(top -1);
391 expandSelection(top -1);
392 display.timerExec(TIMER_INTERVAL, this);
393 }
394 }
395 }
396 };
397 break;
398 case SWT.DOWN:
399 timer= new class() Runnable {
400 public void run() {
401 if (fAutoScrollDirection is SWT.DOWN) {
402 int top= getInclusiveTopIndex();
403 fCachedTextViewer.setTopIndex(top +1);
404 expandSelection(top +1 + fCachedViewportSize);
405 display.timerExec(TIMER_INTERVAL, this);
406 }
407 }
408 };
409 break;
410 default:
411 }
412
413 if (timer !is null) {
414 fAutoScrollDirection= direction;
415 display.timerExec(TIMER_INTERVAL, timer);
416 }
417 }
418
419 /**
420 * Returns the viewer's first visible line, even if only partially visible.
421 *
422 * @return the viewer's first visible line
423 */
424 private int getInclusiveTopIndex() {
425 if (fCachedTextWidget !is null && !fCachedTextWidget.isDisposed()) {
426 return JFaceTextUtil.getPartialTopIndex(fCachedTextViewer);
427 }
428 return -1;
429 }
430 }
431
432 /** This column's parent ruler */
433 private CompositeRuler fParentRuler;
434 /** Cached text viewer */
435 private ITextViewer fCachedTextViewer;
436 /** Cached text widget */
437 private StyledText fCachedTextWidget;
438 /** The columns canvas */
439 private Canvas fCanvas;
440 /** Cache for the actual scroll position in pixels */
441 private int fScrollPos;
442 /** The drawable for double buffering */
443 private Image fBuffer;
444 /** The internal listener */
445 private InternalListener fInternalListener;
446 /** The font of this column */
447 private Font fFont;
448 /** The indentation cache */
449 private int[] fIndentation;
450 /** Indicates whether this column reacts on text change events */
451 private bool fSensitiveToTextChanges= false;
452 /** The foreground color */
453 private Color fForeground;
454 /** The background color */
455 private Color fBackground;
456 /** Cached number of displayed digits */
457 private int fCachedNumberOfDigits= -1;
458 /** Flag indicating whether a relayout is required */
459 private bool fRelayoutRequired= false;
460 /**
461 * Redraw runnable lock
462 * @since 3.0
463 */
464 private Object fRunnableLock;
465 /**
466 * Redraw runnable state
467 * @since 3.0
468 */
469 private bool fIsRunnablePosted= false;
470 /**
471 * Redraw runnable
472 * @since 3.0
473 */
474 private Runnable fRunnable;
475 private void fRunnable_init() {
476 fRunnable = new class() Runnable {
477 public void run() {
478 synchronized (fRunnableLock) {
479 fIsRunnablePosted= false;
480 }
481 redraw();
482 }
483 };
484 }
485 /* @since 3.2 */
486 private MouseHandler fMouseHandler;
487
488
489 /**
490 * Constructs a new vertical ruler column.
491 */
492 public this() {
493 fInternalListener= new InternalListener();
494 fRunnableLock= new Object();
495 fRunnable_init();
496 }
497
498 /**
499 * Sets the foreground color of this column.
500 *
501 * @param foreground the foreground color
502 */
503 public void setForeground(Color foreground) {
504 fForeground= foreground;
505 }
506
507 /**
508 * Returns the foreground color being used to print the line numbers.
509 *
510 * @return the configured foreground color
511 * @since 3.0
512 */
513 protected Color getForeground() {
514 return fForeground;
515 }
516
517 /**
518 * Sets the background color of this column.
519 *
520 * @param background the background color
521 */
522 public void setBackground(Color background) {
523 fBackground= background;
524 if (fCanvas !is null && !fCanvas.isDisposed())
525 fCanvas.setBackground(getBackground(fCanvas.getDisplay()));
526 }
527
528 /**
529 * Returns the System background color for list widgets.
530 *
531 * @param display the display
532 * @return the System background color for list widgets
533 */
534 protected Color getBackground(Display display) {
535 if (fBackground is null)
536 return display.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
537 return fBackground;
538 }
539
540 /*
541 * @see IVerticalRulerColumn#getControl()
542 */
543 public Control getControl() {
544 return fCanvas;
545 }
546
547 /*
548 * @see IVerticalRuleColumnr#getWidth
549 */
550 public int getWidth() {
551 return fIndentation[0];
552 }
553
554 /**
555 * Computes the number of digits to be displayed. Returns
556 * <code>true</code> if the number of digits changed compared
557 * to the previous call of this method. If the method is called
558 * for the first time, the return value is also <code>true</code>.
559 *
560 * @return whether the number of digits has been changed
561 * @since 3.0
562 */
563 protected bool updateNumberOfDigits() {
564 if (fCachedTextViewer is null)
565 return false;
566
567 int digits= computeNumberOfDigits();
568
569 if (fCachedNumberOfDigits !is digits) {
570 fCachedNumberOfDigits= digits;
571 return true;
572 }
573
574 return false;
575 }
576
577 /**
578 * Does the real computation of the number of digits. Subclasses may override this method if
579 * they need extra space on the line number ruler.
580 *
581 * @return the number of digits to be displayed on the line number ruler.
582 */
583 protected int computeNumberOfDigits() {
584 IDocument document= fCachedTextViewer.getDocument();
585 int lines= document is null ? 0 : document.getNumberOfLines();
586
587 int digits= 2;
588 while (lines > Math.pow(cast(real)10.0, cast(uint)digits) -1) {
589 ++digits;
590 }
591 return digits;
592 }
593
594 /**
595 * Layouts the enclosing viewer to adapt the layout to changes of the
596 * size of the individual components.
597 *
598 * @param redraw <code>true</code> if this column can be redrawn
599 */
600 protected void layout(bool redraw) {
601 if (!redraw) {
602 fRelayoutRequired= true;
603 return;
604 }
605
606 fRelayoutRequired= false;
607 if ( cast(ITextViewerExtension)fCachedTextViewer ) {
608 ITextViewerExtension extension= cast(ITextViewerExtension) fCachedTextViewer;
609 Control control= extension.getControl();
610 if ( cast(Composite)control && !control.isDisposed()) {
611 Composite composite= cast(Composite) control;
612 composite.layout(true);
613 }
614 }
615 }
616
617 /**
618 * Computes the indentations for the given font and stores them in
619 * <code>fIndentation</code>.
620 */
621 protected void computeIndentations() {
622 if (fCanvas is null || fCanvas.isDisposed())
623 return;
624
625 GC gc= new GC(fCanvas);
626 try {
627
628 gc.setFont(fCanvas.getFont());
629
630 fIndentation= new int[fCachedNumberOfDigits + 1];
631
632 char[] nines= new char[fCachedNumberOfDigits];
633 Arrays.fill(nines, '9');
634 String nineString= new_String(nines);
635 Point p= gc.stringExtent(nineString);
636 fIndentation[0]= p.x;
637
638 for (int i= 1; i <= fCachedNumberOfDigits; i++) {
639 p= gc.stringExtent(nineString.substring(0, i));
640 fIndentation[i]= fIndentation[0] - p.x;
641 }
642
643 } finally {
644 gc.dispose();
645 }
646 }
647
648 /*
649 * @see IVerticalRulerColumn#createControl(CompositeRuler, Composite)
650 */
651 public Control createControl(CompositeRuler parentRuler, Composite parentControl) {
652
653 fParentRuler= parentRuler;
654 fCachedTextViewer= parentRuler.getTextViewer();
655 fCachedTextWidget= fCachedTextViewer.getTextWidget();
656
657 fCanvas= new class(parentControl, SWT.NO_FOCUS ) Canvas {
658 this(Composite c, int s ){
659 super(c,s);
660 }
661 /*
662 * @see org.eclipse.swt.widgets.Control#addMouseListener(org.eclipse.swt.events.MouseListener)
663 * @since 3.4
664 */
665 public void addMouseListener(MouseListener listener) {
666 // see bug 40889, bug 230073 and AnnotationRulerColumn#isPropagatingMouseListener()
667 if (listener is fMouseHandler)
668 super.addMouseListener(listener);
669 else {
670 TypedListener typedListener= null;
671 if (listener !is null)
672 typedListener= new TypedListener(listener);
673 addListener(SWT.MouseDoubleClick, typedListener);
674 }
675 }
676 };
677 fCanvas.setBackground(getBackground(fCanvas.getDisplay()));
678 fCanvas.setForeground(fForeground);
679
680 fCanvas.addPaintListener(new class() PaintListener {
681 public void paintControl(PaintEvent event) {
682 if (fCachedTextViewer !is null)
683 doubleBufferPaint(event.gc);
684 }
685 });
686
687 fCanvas.addDisposeListener(new class() DisposeListener {
688 public void widgetDisposed(DisposeEvent e) {
689 handleDispose();
690 fCachedTextViewer= null;
691 fCachedTextWidget= null;
692 }
693 });
694
695 fMouseHandler= new MouseHandler();
696 fCanvas.addMouseListener(fMouseHandler);
697 fCanvas.addMouseMoveListener(fMouseHandler);
698
699 if (fCachedTextViewer !is null) {
700
701 fCachedTextViewer.addViewportListener(fInternalListener);
702 fCachedTextViewer.addTextListener(fInternalListener);
703
704 if (fFont is null) {
705 if (fCachedTextWidget !is null && !fCachedTextWidget.isDisposed())
706 fFont= fCachedTextWidget.getFont();
707 }
708 }
709
710 if (fFont !is null)
711 fCanvas.setFont(fFont);
712
713 updateNumberOfDigits();
714 computeIndentations();
715 return fCanvas;
716 }
717
718 /**
719 * Disposes the column's resources.
720 */
721 protected void handleDispose() {
722
723 if (fCachedTextViewer !is null) {
724 fCachedTextViewer.removeViewportListener(fInternalListener);
725 fCachedTextViewer.removeTextListener(fInternalListener);
726 }
727
728 if (fBuffer !is null) {
729 fBuffer.dispose();
730 fBuffer= null;
731 }
732 }
733
734 /**
735 * Double buffer drawing.
736 *
737 * @param dest the GC to draw into
738 */
739 private void doubleBufferPaint(GC dest) {
740
741 Point size= fCanvas.getSize();
742
743 if (size.x <= 0 || size.y <= 0)
744 return;
745
746 if (fBuffer !is null) {
747 Rectangle r= fBuffer.getBounds();
748 if (r.width !is size.x || r.height !is size.y) {
749 fBuffer.dispose();
750 fBuffer= null;
751 }
752 }
753 if (fBuffer is null)
754 fBuffer= new Image(fCanvas.getDisplay(), size.x, size.y);
755
756 GC gc= new GC(fBuffer);
757 gc.setFont(fCanvas.getFont());
758 if (fForeground !is null)
759 gc.setForeground(fForeground);
760
761 try {
762 gc.setBackground(getBackground(fCanvas.getDisplay()));
763 gc.fillRectangle(0, 0, size.x, size.y);
764
765 ILineRange visibleLines= JFaceTextUtil.getVisibleModelLines(fCachedTextViewer);
766 if (visibleLines is null)
767 return;
768 fScrollPos= fCachedTextWidget.getTopPixel();
769 doPaint(gc, visibleLines);
770 } finally {
771 gc.dispose();
772 }
773
774 dest.drawImage(fBuffer, 0, 0);
775 }
776
777 /**
778 * Returns the view port height in lines.
779 *
780 * @return the view port height in lines
781 * @deprecated as of 3.2 the number of lines in the viewport cannot be computed because
782 * StyledText supports variable line heights
783 */
784 protected int getVisibleLinesInViewport() {
785 return getVisibleLinesInViewport(fCachedTextWidget);
786 }
787
788
789 /**
790 * Returns <code>true</code> if the viewport displays the entire viewer contents, i.e. the
791 * viewer is not vertically scrollable.
792 *
793 * @return <code>true</code> if the viewport displays the entire contents, <code>false</code> otherwise
794 * @since 3.2
795 */
796 protected final bool isViewerCompletelyShown() {
797 return JFaceTextUtil.isShowingEntireContents(fCachedTextWidget);
798 }
799
800 /**
801 * Draws the ruler column.
802 *
803 * @param gc the GC to draw into
804 * @param visibleLines the visible model lines
805 * @since 3.2
806 */
807 void doPaint(GC gc, ILineRange visibleLines) {
808 Display display= fCachedTextWidget.getDisplay();
809
810 // draw diff info
811 int y= -JFaceTextUtil.getHiddenTopLinePixels(fCachedTextWidget);
812
813 int lastLine= end(visibleLines);
814 for (int line= visibleLines.getStartLine(); line < lastLine; line++) {
815 int widgetLine= JFaceTextUtil.modelLineToWidgetLine(fCachedTextViewer, line);
816 if (widgetLine is -1)
817 continue;
818
819 int lineHeight= fCachedTextWidget.getLineHeight(fCachedTextWidget.getOffsetAtLine(widgetLine));
820 paintLine(line, y, lineHeight, gc, display);
821 y += lineHeight;
822 }
823 }
824
825 /* @since 3.2 */
826 private static int end(ILineRange range) {
827 return range.getStartLine() + range.getNumberOfLines();
828 }
829
830 /**
831 * Computes the string to be printed for <code>line</code>. The default implementation returns
832 * <code>Integer.toString(line + 1)</code>.
833 *
834 * @param line the line number for which the line number string is generated
835 * @return the string to be printed on the line number bar for <code>line</code>
836 * @since 3.0
837 */
838 protected String createDisplayString(int line) {
839 return Integer.toString(line + 1);
840 }
841
842 /**
843 * Returns the difference between the baseline of the widget and the
844 * baseline as specified by the font for <code>gc</code>. When drawing
845 * line numbers, the returned bias should be added to obtain text lined up
846 * on the correct base line of the text widget.
847 *
848 * @param gc the <code>GC</code> to get the font metrics from
849 * @param widgetLine the widget line
850 * @return the baseline bias to use when drawing text that is lined up with
851 * <code>fCachedTextWidget</code>
852 * @since 3.2
853 */
854 private int getBaselineBias(GC gc, int widgetLine) {
855 /*
856 * https://bugs.eclipse.org/bugs/show_bug.cgi?id=62951
857 * widget line height may be more than the font height used for the
858 * line numbers, since font styles (bold, italics...) can have larger
859 * font metrics than the simple font used for the numbers.
860 */
861 int offset= fCachedTextWidget.getOffsetAtLine(widgetLine);
862 int widgetBaseline= fCachedTextWidget.getBaseline(offset);
863
864 FontMetrics fm= gc.getFontMetrics();
865 int fontBaseline= fm.getAscent() + fm.getLeading();
866 int baselineBias= widgetBaseline - fontBaseline;
867 return Math.max(0, baselineBias);
868 }
869
870 /**
871 * Paints the line. After this method is called the line numbers are painted on top
872 * of the result of this method.
873 *
874 * @param line the line of the document which the ruler is painted for
875 * @param y the y-coordinate of the box being painted for <code>line</code>, relative to <code>gc</code>
876 * @param lineheight the height of one line (and therefore of the box being painted)
877 * @param gc the drawing context the client may choose to draw on.
878 * @param display the display the drawing occurs on
879 * @since 3.0
880 */
881 protected void paintLine(int line, int y, int lineheight, GC gc, Display display) {
882 int widgetLine= JFaceTextUtil.modelLineToWidgetLine(fCachedTextViewer, line);
883
884 String s= createDisplayString(line);
885 int indentation= fIndentation[s.length];
886 int baselineBias= getBaselineBias(gc, widgetLine);
887 gc.drawString(s, indentation, y + baselineBias, true);
888 }
889
890 /**
891 * Triggers a redraw in the display thread.
892 *
893 * @since 3.0
894 */
895 protected final void postRedraw() {
896 if (fCanvas !is null && !fCanvas.isDisposed()) {
897 Display d= fCanvas.getDisplay();
898 if (d !is null) {
899 synchronized (fRunnableLock) {
900 if (fIsRunnablePosted)
901 return;
902 fIsRunnablePosted= true;
903 }
904 d.asyncExec(fRunnable);
905 }
906 }
907 }
908
909 /*
910 * @see IVerticalRulerColumn#redraw()
911 */
912 public void redraw() {
913
914 if (fRelayoutRequired) {
915 layout(true);
916 return;
917 }
918
919 if (fCachedTextViewer !is null && fCanvas !is null && !fCanvas.isDisposed()) {
920 GC gc= new GC(fCanvas);
921 doubleBufferPaint(gc);
922 gc.dispose();
923 }
924 }
925
926 /*
927 * @see IVerticalRulerColumn#setModel(IAnnotationModel)
928 */
929 public void setModel(IAnnotationModel model) {
930 }
931
932 /*
933 * @see IVerticalRulerColumn#setFont(Font)
934 */
935 public void setFont(Font font) {
936 fFont= font;
937 if (fCanvas !is null && !fCanvas.isDisposed()) {
938 fCanvas.setFont(fFont);
939 updateNumberOfDigits();
940 computeIndentations();
941 }
942 }
943
944 /**
945 * Returns the parent (composite) ruler of this ruler column.
946 *
947 * @return the parent ruler
948 * @since 3.0
949 */
950 protected CompositeRuler getParentRuler() {
951 return fParentRuler;
952 }
953
954
955 /**
956 * Returns the number of lines in the view port.
957 *
958 * @param textWidget
959 * @return the number of lines visible in the view port <code>-1</code> if there's no client area
960 * @deprecated this method should not be used - it relies on the widget using a uniform line height
961 */
962 static int getVisibleLinesInViewport(StyledText textWidget) {
963 if (textWidget !is null) {
964 Rectangle clArea= textWidget.getClientArea();
965 if (!clArea.isEmpty()) {
966 int firstPixel= 0;
967 int lastPixel= clArea.height - 1; // XXX what about margins? don't take trims as they include scrollbars
968 int first= JFaceTextUtil.getLineIndex(textWidget, firstPixel);
969 int last= JFaceTextUtil.getLineIndex(textWidget, lastPixel);
970 return last - first;
971 }
972 }
973 return -1;
974 }
975
976 }