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