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