editor now updatable via updateSite
[taxeditor.git] / taxeditor-editor / src / main / java / eu / etaxonomy / taxeditor / editor / LineWrapSquigglesStrategy.java
1 /**
2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9
10 package eu.etaxonomy.taxeditor.editor;
11
12 import org.eclipse.jface.text.source.Annotation;
13 import org.eclipse.jface.text.source.AnnotationPainter.SquigglesStrategy;
14 import org.eclipse.swt.SWT;
15 import org.eclipse.swt.custom.StyledText;
16 import org.eclipse.swt.graphics.Color;
17 import org.eclipse.swt.graphics.GC;
18 import org.eclipse.swt.graphics.Point;
19
20 /**
21 * Adds ability to draw multiline squiggles when a <code>StyledText</code>
22 * contains line-wrapping.
23 *
24 * @author p.ciardelli
25 * @created 21.11.2008
26 * @version 1.0
27 */
28 public class LineWrapSquigglesStrategy extends SquigglesStrategy {
29
30 public static final String ID = "linewrap_squigglesstrategy";
31
32 private GC gc;
33
34 private Color color;
35
36 private int lineHeight;
37
38 private int baseline;
39
40 private StyledText textWidget;
41
42 private int offset;
43
44 /* (non-Javadoc)
45 * @see org.eclipse.jface.text.source.AnnotationPainter$SquigglesStrategy#draw(org.eclipse.jface.text.source.Annotation, org.eclipse.swt.graphics.GC, org.eclipse.swt.custom.StyledText, int, int, org.eclipse.swt.graphics.Color)
46 */
47 public void draw(Annotation annotation, GC gc, StyledText textWidget, int offset, int length, Color color) {
48
49 this.gc = gc;
50 this.color = color;
51 this.textWidget = textWidget;
52 this.offset = offset;
53
54 if (gc != null) {
55
56 if (length < 1)
57 return;
58
59 baseline = textWidget.getBaseline(offset);
60 lineHeight = textWidget.getLineHeight(offset);
61
62 Point right = null;
63 int offsetNewline = offset;
64 int end = offset + length;
65
66 // Go through the length one character at a time
67 for (int i = offset; i <= end; i++) {
68
69 // If the y of the current offset is different from that of the last offset,
70 // we are on a new line
71 if (right != null && textWidget.getLocationAtOffset(i).y > right.y) {
72
73 // Draw a line of squigglies
74 drawPolyline(offsetNewline, right);
75
76 // Save offset of line break
77 offsetNewline = i;
78 }
79
80 // Get x,y position in case the next char is on a new line
81 right = textWidget.getLocationAtOffset(i);
82
83 }
84
85 // Draw the last line of squigglies
86 drawPolyline(offsetNewline, right);
87
88 } else {
89 textWidget.redrawRange(offset, length, true);
90 }
91 }
92
93 /**
94 * Draws a squiggly line from the offset <code>offsetNewline</code> to
95 * the x,y coordinates at <code>right</code>.
96 *
97 * @param offsetNewline
98 * @param right
99 */
100 private void drawPolyline(int offsetNewline, Point right) {
101
102 // Get offset at last line break
103 Point left = textWidget.getLocationAtOffset(offsetNewline);
104
105 // Prevent solitary red dot from appearing at EOL
106 if (left.equals(right)) {
107 return;
108 }
109
110 // Only start drawing from 0 if not on the first line
111 if (offsetNewline != offset) {
112
113 // Offset.x is at the end of the first letter of the new line, not at 0
114 left.x = 0;
115 }
116
117 int[] polyline= computePolyline(left, right, baseline, lineHeight);
118
119 gc.setLineWidth(0); // NOTE: 0 means width is 1 but with optimized performance
120 gc.setLineStyle(SWT.LINE_SOLID);
121 gc.setForeground(color);
122 gc.drawPolyline(polyline);
123 }
124
125 /**
126 * Copied verbatim from {@link org.eclipse.jface.text.source.AnnotationPainter$SquigglesStrategy}
127 *
128 * @see org.eclipse.jface.text.source.AnnotationPainter$SquigglesStrategy
129 *
130 * @param left
131 * @param right
132 * @param baseline
133 * @param lineHeight
134 * @return
135 */
136 private int[] computePolyline(Point left, Point right, int baseline, int lineHeight) {
137
138 final int WIDTH= 4; // must be even
139 final int HEIGHT= 2; // can be any number
140
141 int peaks= (right.x - left.x) / WIDTH;
142 if (peaks == 0 && right.x - left.x > 2)
143 peaks= 1;
144
145 int leftX= left.x;
146
147 // compute (number of point) * 2
148 int length= ((2 * peaks) + 1) * 2;
149 if (length < 0)
150 return new int[0];
151
152 int[] coordinates= new int[length];
153
154 // cache peeks' y-coordinates
155 int top= left.y + Math.min(baseline + 1, lineHeight - HEIGHT - 1);
156 int bottom= top + HEIGHT;
157
158 // populate array with peek coordinates
159 for (int i= 0; i < peaks; i++) {
160 int index= 4 * i;
161 coordinates[index]= leftX + (WIDTH * i);
162 coordinates[index+1]= bottom;
163 coordinates[index+2]= coordinates[index] + WIDTH/2;
164 coordinates[index+3]= top;
165 }
166
167 // the last down flank is missing
168 coordinates[length-2]= Math.min(Math.max(0, right.x - 1), left.x + (WIDTH * peaks));
169 coordinates[length-1]= bottom;
170
171 return coordinates;
172 }
173 }