KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jface > text > source > VerticalRuler


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  *******************************************************************************/

11 package org.eclipse.jface.text.source;
12
13
14 import java.util.Iterator JavaDoc;
15
16 import org.eclipse.swt.SWT;
17 import org.eclipse.swt.custom.StyledText;
18 import org.eclipse.swt.events.DisposeEvent;
19 import org.eclipse.swt.events.DisposeListener;
20 import org.eclipse.swt.events.MouseEvent;
21 import org.eclipse.swt.events.MouseListener;
22 import org.eclipse.swt.events.PaintEvent;
23 import org.eclipse.swt.events.PaintListener;
24 import org.eclipse.swt.graphics.Font;
25 import org.eclipse.swt.graphics.GC;
26 import org.eclipse.swt.graphics.Image;
27 import org.eclipse.swt.graphics.Point;
28 import org.eclipse.swt.graphics.Rectangle;
29 import org.eclipse.swt.widgets.Canvas;
30 import org.eclipse.swt.widgets.Composite;
31 import org.eclipse.swt.widgets.Control;
32 import org.eclipse.swt.widgets.Display;
33
34
35 import org.eclipse.jface.text.BadLocationException;
36 import org.eclipse.jface.text.IDocument;
37 import org.eclipse.jface.text.IRegion;
38 import org.eclipse.jface.text.ITextListener;
39 import org.eclipse.jface.text.ITextViewer;
40 import org.eclipse.jface.text.ITextViewerExtension5;
41 import org.eclipse.jface.text.IViewportListener;
42 import org.eclipse.jface.text.JFaceTextUtil;
43 import org.eclipse.jface.text.Position;
44 import org.eclipse.jface.text.Region;
45 import org.eclipse.jface.text.TextEvent;
46
47
48 /**
49  * A vertical ruler which is connected to a text viewer. Single column standard
50  * implementation of {@link org.eclipse.jface.text.source.IVerticalRuler}.
51  * <p>
52  * The same can be achieved by using <code>CompositeRuler</code> configured
53  * with an <code>AnnotationRulerColumn</code>. Clients may use this class as
54  * is.
55  *
56  * @see org.eclipse.jface.text.ITextViewer
57  */

58 public final class VerticalRuler implements IVerticalRuler, IVerticalRulerExtension {
59
60     /**
61      * Internal listener class.
62      */

63     class InternalListener implements IViewportListener, IAnnotationModelListener, ITextListener {
64
65         /*
66          * @see IViewportListener#viewportChanged(int)
67          */

68         public void viewportChanged(int verticalPosition) {
69             if (verticalPosition != fScrollPos)
70                 redraw();
71         }
72
73         /*
74          * @see IAnnotationModelListener#modelChanged(IAnnotationModel)
75          */

76         public void modelChanged(IAnnotationModel model) {
77             update();
78         }
79
80         /*
81          * @see ITextListener#textChanged(TextEvent)
82          */

83         public void textChanged(TextEvent e) {
84             if (fTextViewer != null && e.getViewerRedrawState())
85                 redraw();
86         }
87     }
88
89     /** The vertical ruler's text viewer */
90     private ITextViewer fTextViewer;
91     /** The ruler's canvas */
92     private Canvas fCanvas;
93     /** The vertical ruler's model */
94     private IAnnotationModel fModel;
95     /** Cache for the actual scroll position in pixels */
96     private int fScrollPos;
97     /** The buffer for double buffering */
98     private Image fBuffer;
99     /** The line of the last mouse button activity */
100     private int fLastMouseButtonActivityLine= -1;
101     /** The internal listener */
102     private InternalListener fInternalListener= new InternalListener();
103     /** The width of this vertical ruler */
104     private int fWidth;
105     /**
106      * The annotation access of this vertical ruler
107      * @since 3.0
108      */

109     private IAnnotationAccess fAnnotationAccess;
110
111     /**
112      * Constructs a vertical ruler with the given width.
113      *
114      * @param width the width of the vertical ruler
115      */

116     public VerticalRuler(int width) {
117         this(width, null);
118     }
119
120     /**
121      * Constructs a vertical ruler with the given width and the given annotation
122      * access.
123      *
124      * @param width the width of the vertical ruler
125      * @param annotationAcccess the annotation access
126      * @since 3.0
127      */

128     public VerticalRuler(int width, IAnnotationAccess annotationAcccess) {
129         fWidth= width;
130         fAnnotationAccess= annotationAcccess;
131     }
132
133     /*
134      * @see IVerticalRuler#getControl()
135      */

136     public Control getControl() {
137         return fCanvas;
138     }
139
140     /*
141      * @see IVerticalRuler#createControl(Composite, ITextViewer)
142      */

143     public Control createControl(Composite parent, ITextViewer textViewer) {
144
145         fTextViewer= textViewer;
146
147         fCanvas= new Canvas(parent, SWT.NO_BACKGROUND);
148
149         fCanvas.addPaintListener(new PaintListener() {
150             public void paintControl(PaintEvent event) {
151                 if (fTextViewer != null)
152                     doubleBufferPaint(event.gc);
153             }
154         });
155
156         fCanvas.addDisposeListener(new DisposeListener() {
157             public void widgetDisposed(DisposeEvent e) {
158                 handleDispose();
159                 fTextViewer= null;
160             }
161         });
162
163         fCanvas.addMouseListener(new MouseListener() {
164             public void mouseUp(MouseEvent event) {
165             }
166
167             public void mouseDown(MouseEvent event) {
168                 fLastMouseButtonActivityLine= toDocumentLineNumber(event.y);
169             }
170
171             public void mouseDoubleClick(MouseEvent event) {
172                 fLastMouseButtonActivityLine= toDocumentLineNumber(event.y);
173             }
174         });
175
176         if (fTextViewer != null) {
177             fTextViewer.addViewportListener(fInternalListener);
178             fTextViewer.addTextListener(fInternalListener);
179         }
180
181         return fCanvas;
182     }
183
184     /**
185      * Disposes the ruler's resources.
186      */

187     private void handleDispose() {
188
189         if (fTextViewer != null) {
190             fTextViewer.removeViewportListener(fInternalListener);
191             fTextViewer.removeTextListener(fInternalListener);
192             fTextViewer= null;
193         }
194
195         if (fModel != null)
196             fModel.removeAnnotationModelListener(fInternalListener);
197
198         if (fBuffer != null) {
199             fBuffer.dispose();
200             fBuffer= null;
201         }
202     }
203
204
205     /**
206      * Double buffer drawing.
207      *
208      * @param dest the GC to draw into
209      */

210     private void doubleBufferPaint(GC dest) {
211
212         Point size= fCanvas.getSize();
213
214         if (size.x <= 0 || size.y <= 0)
215             return;
216
217         if (fBuffer != null) {
218             Rectangle r= fBuffer.getBounds();
219             if (r.width != size.x || r.height != size.y) {
220                 fBuffer.dispose();
221                 fBuffer= null;
222             }
223         }
224         if (fBuffer == null)
225             fBuffer= new Image(fCanvas.getDisplay(), size.x, size.y);
226
227         GC gc= new GC(fBuffer);
228         gc.setFont(fTextViewer.getTextWidget().getFont());
229         try {
230             gc.setBackground(fCanvas.getBackground());
231             gc.fillRectangle(0, 0, size.x, size.y);
232
233             if (fTextViewer instanceof ITextViewerExtension5)
234                 doPaint1(gc);
235             else
236                 doPaint(gc);
237
238         } finally {
239             gc.dispose();
240         }
241
242         dest.drawImage(fBuffer, 0, 0);
243     }
244
245     /**
246      * Returns the document offset of the upper left corner of the
247      * widgets view port, possibly including partially visible lines.
248      *
249      * @return the document offset of the upper left corner including partially visible lines
250      * @since 2.0
251      */

252     private int getInclusiveTopIndexStartOffset() {
253
254         StyledText textWidget= fTextViewer.getTextWidget();
255         if (textWidget != null && !textWidget.isDisposed()) {
256             int top= JFaceTextUtil.getPartialTopIndex(fTextViewer);
257             try {
258                 IDocument document= fTextViewer.getDocument();
259                 return document.getLineOffset(top);
260             } catch (BadLocationException x) {
261             }
262         }
263
264         return -1;
265     }
266
267
268
269     /**
270      * Draws the vertical ruler w/o drawing the Canvas background.
271      *
272      * @param gc the GC to draw into
273      */

274     protected void doPaint(GC gc) {
275
276         if (fModel == null || fTextViewer == null)
277             return;
278
279         IAnnotationAccessExtension annotationAccessExtension= null;
280         if (fAnnotationAccess instanceof IAnnotationAccessExtension)
281             annotationAccessExtension= (IAnnotationAccessExtension) fAnnotationAccess;
282
283         StyledText styledText= fTextViewer.getTextWidget();
284         IDocument doc= fTextViewer.getDocument();
285
286         int topLeft= getInclusiveTopIndexStartOffset();
287         int bottomRight= fTextViewer.getBottomIndexEndOffset();
288         int viewPort= bottomRight - topLeft;
289
290         Point d= fCanvas.getSize();
291         fScrollPos= styledText.getTopPixel();
292
293         int topLine= -1, bottomLine= -1;
294         try {
295             IRegion region= fTextViewer.getVisibleRegion();
296             topLine= doc.getLineOfOffset(region.getOffset());
297             bottomLine= doc.getLineOfOffset(region.getOffset() + region.getLength());
298         } catch (BadLocationException x) {
299             return;
300         }
301
302         // draw Annotations
303
Rectangle r= new Rectangle(0, 0, 0, 0);
304         int maxLayer= 1; // loop at least once though layers.
305

306         for (int layer= 0; layer < maxLayer; layer++) {
307             Iterator JavaDoc iter= fModel.getAnnotationIterator();
308             while (iter.hasNext()) {
309                 IAnnotationPresentation annotationPresentation= null;
310                 Annotation annotation= (Annotation) iter.next();
311
312                 int lay= IAnnotationAccessExtension.DEFAULT_LAYER;
313                 if (annotationAccessExtension != null)
314                     lay= annotationAccessExtension.getLayer(annotation);
315                 else if (annotation instanceof IAnnotationPresentation) {
316                     annotationPresentation= (IAnnotationPresentation)annotation;
317                     lay= annotationPresentation.getLayer();
318                 }
319                 maxLayer= Math.max(maxLayer, lay+1); // dynamically update layer maximum
320
if (lay != layer) // wrong layer: skip annotation
321
continue;
322
323                 Position position= fModel.getPosition(annotation);
324                 if (position == null)
325                     continue;
326
327                 if (!position.overlapsWith(topLeft, viewPort))
328                     continue;
329
330                 try {
331
332                     int offset= position.getOffset();
333                     int length= position.getLength();
334
335                     int startLine= doc.getLineOfOffset(offset);
336                     if (startLine < topLine)
337                         startLine= topLine;
338
339                     int endLine= startLine;
340                     if (length > 0)
341                         endLine= doc.getLineOfOffset(offset + length - 1);
342                     if (endLine > bottomLine)
343                         endLine= bottomLine;
344
345                     startLine -= topLine;
346                     endLine -= topLine;
347
348                     r.x= 0;
349                     r.y= JFaceTextUtil.computeLineHeight(styledText, 0, startLine, startLine) - fScrollPos;
350                     
351                     r.width= d.x;
352                     int lines= endLine - startLine;
353                     
354                     r.height= JFaceTextUtil.computeLineHeight(styledText, startLine, endLine + 1, (lines+1));
355
356                     if (r.y < d.y && annotationAccessExtension != null) // annotation within visible area
357
annotationAccessExtension.paint(annotation, gc, fCanvas, r);
358                     else if (annotationPresentation != null)
359                         annotationPresentation.paint(gc, fCanvas, r);
360
361                 } catch (BadLocationException e) {
362                 }
363             }
364         }
365     }
366
367     /**
368      * Draws the vertical ruler w/o drawing the Canvas background. Uses
369      * <code>ITextViewerExtension5</code> for its implementation. Will replace
370      * <code>doPaint(GC)</code>.
371      *
372      * @param gc the GC to draw into
373      */

374     protected void doPaint1(GC gc) {
375
376         if (fModel == null || fTextViewer == null)
377             return;
378
379         IAnnotationAccessExtension annotationAccessExtension= null;
380         if (fAnnotationAccess instanceof IAnnotationAccessExtension)
381             annotationAccessExtension= (IAnnotationAccessExtension) fAnnotationAccess;
382
383         ITextViewerExtension5 extension= (ITextViewerExtension5) fTextViewer;
384         StyledText textWidget= fTextViewer.getTextWidget();
385
386         fScrollPos= textWidget.getTopPixel();
387         Point dimension= fCanvas.getSize();
388
389         // draw Annotations
390
Rectangle r= new Rectangle(0, 0, 0, 0);
391         int maxLayer= 1; // loop at least once through layers.
392

393         for (int layer= 0; layer < maxLayer; layer++) {
394             Iterator JavaDoc iter= fModel.getAnnotationIterator();
395             while (iter.hasNext()) {
396                 IAnnotationPresentation annotationPresentation= null;
397                 Annotation annotation= (Annotation) iter.next();
398
399                 int lay= IAnnotationAccessExtension.DEFAULT_LAYER;
400                 if (annotationAccessExtension != null)
401                     lay= annotationAccessExtension.getLayer(annotation);
402                 else if (annotation instanceof IAnnotationPresentation) {
403                     annotationPresentation= (IAnnotationPresentation)annotation;
404                     lay= annotationPresentation.getLayer();
405                 }
406                 maxLayer= Math.max(maxLayer, lay+1); // dynamically update layer maximum
407
if (lay != layer) // wrong layer: skip annotation
408
continue;
409
410                 Position position= fModel.getPosition(annotation);
411                 if (position == null)
412                     continue;
413
414                 IRegion widgetRegion= extension.modelRange2WidgetRange(new Region(position.getOffset(), position.getLength()));
415                 if (widgetRegion == null)
416                     continue;
417
418                 int startLine= extension.widgetLineOfWidgetOffset(widgetRegion.getOffset());
419                 if (startLine == -1)
420                     continue;
421
422                 int endLine= extension.widgetLineOfWidgetOffset(widgetRegion.getOffset() + Math.max(widgetRegion.getLength() -1, 0));
423                 if (endLine == -1)
424                     continue;
425
426                 r.x= 0;
427                 r.y= JFaceTextUtil.computeLineHeight(textWidget, 0, startLine, startLine) - fScrollPos;
428                 
429                 r.width= dimension.x;
430                 int lines= endLine - startLine;
431                 
432                 r.height= JFaceTextUtil.computeLineHeight(textWidget, startLine, endLine + 1, lines+1);
433
434                 if (r.y < dimension.y && annotationAccessExtension != null) // annotation within visible area
435
annotationAccessExtension.paint(annotation, gc, fCanvas, r);
436                 else if (annotationPresentation != null)
437                     annotationPresentation.paint(gc, fCanvas, r);
438             }
439         }
440     }
441
442     /**
443      * Thread-safe implementation.
444      * Can be called from any thread.
445      */

446     /*
447      * @see IVerticalRuler#update()
448      */

449     public void update() {
450         if (fCanvas != null && !fCanvas.isDisposed()) {
451             Display d= fCanvas.getDisplay();
452             if (d != null) {
453                 d.asyncExec(new Runnable JavaDoc() {
454                     public void run() {
455                         redraw();
456                     }
457                 });
458             }
459         }
460     }
461
462     /**
463      * Redraws the vertical ruler.
464      */

465     private void redraw() {
466         if (fCanvas != null && !fCanvas.isDisposed()) {
467             GC gc= new GC(fCanvas);
468             doubleBufferPaint(gc);
469             gc.dispose();
470         }
471     }
472
473     /*
474      * @see IVerticalRuler#setModel(IAnnotationModel)
475      */

476     public void setModel(IAnnotationModel model) {
477         if (model != fModel) {
478
479             if (fModel != null)
480                 fModel.removeAnnotationModelListener(fInternalListener);
481
482             fModel= model;
483
484             if (fModel != null)
485                 fModel.addAnnotationModelListener(fInternalListener);
486
487             update();
488         }
489     }
490
491     /*
492      * @see IVerticalRuler#getModel()
493      */

494     public IAnnotationModel getModel() {
495         return fModel;
496     }
497
498     /*
499      * @see IVerticalRulerInfo#getWidth()
500      */

501     public int getWidth() {
502         return fWidth;
503     }
504
505     /*
506      * @see IVerticalRulerInfo#getLineOfLastMouseButtonActivity()
507      */

508     public int getLineOfLastMouseButtonActivity() {
509         return fLastMouseButtonActivityLine;
510     }
511
512     /*
513      * @see IVerticalRulerInfo#toDocumentLineNumber(int)
514      */

515     public int toDocumentLineNumber(int y_coordinate) {
516         if (fTextViewer == null || y_coordinate == -1)
517             return -1;
518
519         StyledText text= fTextViewer.getTextWidget();
520         int line= text.getLineIndex(y_coordinate);
521         
522         if (line == text.getLineCount() - 1) {
523             // check whether y_coordinate exceeds last line
524
if (y_coordinate > text.getLinePixel(line + 1))
525                 return -1;
526         }
527         
528         return widgetLine2ModelLine(fTextViewer, line);
529     }
530
531     /**
532      * Returns the line of the viewer's document that corresponds to the given widget line.
533      *
534      * @param viewer the viewer
535      * @param widgetLine the widget line
536      * @return the corresponding line of the viewer's document
537      * @since 2.1
538      */

539     protected final static int widgetLine2ModelLine(ITextViewer viewer, int widgetLine) {
540
541         if (viewer instanceof ITextViewerExtension5) {
542             ITextViewerExtension5 extension= (ITextViewerExtension5) viewer;
543             return extension.widgetLine2ModelLine(widgetLine);
544         }
545
546         try {
547             IRegion r= viewer.getVisibleRegion();
548             IDocument d= viewer.getDocument();
549             return widgetLine += d.getLineOfOffset(r.getOffset());
550         } catch (BadLocationException x) {
551         }
552         return widgetLine;
553     }
554
555     /*
556      * @see IVerticalRulerExtension#setFont(Font)
557      * @since 2.0
558      */

559     public void setFont(Font font) {
560     }
561
562     /*
563      * @see IVerticalRulerExtension#setLocationOfLastMouseButtonActivity(int, int)
564      * @since 2.0
565      */

566     public void setLocationOfLastMouseButtonActivity(int x, int y) {
567         fLastMouseButtonActivityLine= toDocumentLineNumber(y);
568     }
569
570     /**
571      * Adds the given mouse listener.
572      *
573      * @param listener the listener to be added
574      * @deprecated will be removed
575      * @since 2.0
576      */

577     public void addMouseListener(MouseListener listener) {
578         if (fCanvas != null && !fCanvas.isDisposed())
579             fCanvas.addMouseListener(listener);
580     }
581
582     /**
583      * Removes the given mouse listener.
584      *
585      * @param listener the listener to be removed
586      * @deprecated will be removed
587      * @since 2.0
588      */

589     public void removeMouseListener(MouseListener listener) {
590         if (fCanvas != null && !fCanvas.isDisposed())
591             fCanvas.removeMouseListener(listener);
592     }
593 }
594
Popular Tags