p2izing the editor
[taxeditor.git] / eclipseprojects / eu.etaxonomy.taxeditor.prototype2 / src / eu / etaxonomy / taxeditor / prototype2 / view / NameViewer_.java
1 package eu.etaxonomy.taxeditor.prototype2.view;
2
3 import java.beans.PropertyChangeListener;
4 import java.beans.PropertyChangeSupport;
5 import java.util.List;
6 import java.util.Scanner;
7
8 import org.eclipse.core.databinding.Binding;
9 import org.eclipse.core.databinding.DataBindingContext;
10 import org.eclipse.core.databinding.beans.BeansObservables;
11 import org.eclipse.core.databinding.observable.value.IObservableValue;
12 import org.eclipse.core.resources.IMarker;
13 import org.eclipse.core.runtime.Assert;
14 import org.eclipse.jface.text.BadLocationException;
15 import org.eclipse.jface.text.Document;
16 import org.eclipse.jface.text.IDocument;
17 import org.eclipse.jface.text.IDocumentPartitioner;
18 import org.eclipse.jface.text.ITypedRegion;
19 import org.eclipse.jface.text.Position;
20 import org.eclipse.jface.text.TypedRegion;
21 import org.eclipse.jface.text.rules.DefaultPartitioner;
22 import org.eclipse.jface.text.rules.FastPartitioner;
23 import org.eclipse.jface.text.rules.IPartitionTokenScanner;
24 import org.eclipse.jface.text.source.Annotation;
25 import org.eclipse.jface.text.source.AnnotationModel;
26 import org.eclipse.jface.text.source.AnnotationPainter;
27 import org.eclipse.jface.text.source.IAnnotationAccess;
28 import org.eclipse.jface.text.source.IAnnotationAccessExtension;
29 import org.eclipse.jface.text.source.ImageUtilities;
30 import org.eclipse.jface.text.source.SourceViewer;
31 import org.eclipse.swt.SWT;
32 import org.eclipse.swt.custom.StyleRange;
33 import org.eclipse.swt.custom.StyledText;
34 import org.eclipse.swt.events.FocusEvent;
35 import org.eclipse.swt.events.FocusListener;
36 import org.eclipse.swt.events.KeyAdapter;
37 import org.eclipse.swt.events.KeyEvent;
38 import org.eclipse.swt.graphics.Color;
39 import org.eclipse.swt.graphics.GC;
40 import org.eclipse.swt.graphics.Image;
41 import org.eclipse.swt.graphics.RGB;
42 import org.eclipse.swt.graphics.Rectangle;
43 import org.eclipse.swt.layout.GridData;
44 import org.eclipse.swt.widgets.Canvas;
45 import org.eclipse.swt.widgets.Composite;
46 import org.eclipse.swt.widgets.Display;
47
48 import com.swtdesigner.SWTResourceManager;
49
50 import eu.etaxonomy.taxeditor.prototype2.view.nameviewersupport.AnnotationMarkerAccess;
51 import eu.etaxonomy.taxeditor.prototype2.view.nameviewersupport.ErrorAnnotation;
52 import eu.etaxonomy.taxeditor.prototype2.view.nameviewersupport.NamePartitionScanner_;
53
54 /**
55 * Creates zero-length fieldPartitions for Genus, Specific Epithet, etc., then fills them
56 * as data is added.
57 *
58 * Partition data are bound to their respective model properties.
59 *
60 * @author p.ciardelli
61 *
62 */
63 /**
64 * @author p.ciardelli
65 *
66 */
67 public class NameViewer_ extends SourceViewer {
68
69 final Document document;
70 final IDocumentPartitioner partitioner;
71 private TaxonName taxonName;
72 private DataBindingContext bindingContext;
73 protected Composite parent;
74
75 private BoundPartition[] fieldPartitions;
76
77 StyledText styledText;
78
79 // error identifiers, images and colors
80 public static String ERROR_TYPE = "error.type";
81 public static Image ERROR_IMAGE;
82 public static final RGB ERROR_RGB = new RGB(255, 0, 0);
83
84 // annotation model
85 private AnnotationModel fAnnotationModel = new AnnotationModel();
86
87 NameViewer_(TaxonName taxonName, DataBindingContext bindingContext, Composite parent) {
88 super(parent, null, SWT.WRAP | SWT.MULTI | SWT.RESIZE); // null -> no vertical ruler
89
90 this.taxonName = taxonName;
91 this.bindingContext = bindingContext;
92 this.parent = parent;
93
94 Assert.isNotNull(bindingContext,
95 "NameViewer_'s binding context must be explicitly set.");
96
97 fieldPartitions = new BoundPartition[] {
98 new BoundPartition("genus", SWT.ITALIC),
99 new BoundPartition("specificEpithet", SWT.BOLD)
100 };
101
102 document = new Document(taxonName.getGenus() + " " + taxonName.getSpecificEpithet());
103
104 partitioner = new NamePartitioner(new NamePartitionScanner_(),
105 NamePartitionScanner_.PARTITION_TYPES);
106
107 partitioner.connect(document);
108 document.setDocumentPartitioner(partitioner);
109
110 this.setDocument(document, fAnnotationModel); // put this back in nameeditorview so that it functions more like TextViewer
111
112 styledText = this.getTextWidget();
113 // styledText.setIndent(8);
114 styledText.addFocusListener(new FocusListener() {
115
116 public void focusGained(FocusEvent e) {
117 ((StyledText) e.widget).setBackground((Display.getCurrent().getSystemColor(SWT.COLOR_GRAY)));
118
119 }
120
121 public void focusLost(FocusEvent e) {
122 ((StyledText) e.widget).setBackground((Display.getCurrent().getSystemColor(SWT.COLOR_WHITE)));
123 }
124
125 });
126
127 // annotations section
128 IAnnotationAccess fAnnotationAccess = new AnnotationMarkerAccess();
129
130 // to paint the annotations
131 AnnotationPainter ap = new AnnotationPainter(this, fAnnotationAccess);
132 ap.addAnnotationType(ERROR_TYPE);
133 ap.setAnnotationTypeColor(ERROR_TYPE, new Color(Display.getDefault(), ERROR_RGB));
134
135 // this will draw the squigglies under the text
136 this.addPainter(ap);
137
138 // add an annotation
139 ErrorAnnotation errorAnnotation = new ErrorAnnotation(1, "Learn how to spell \"text!\"");
140
141 // lets underline the word "texst"
142 fAnnotationModel.addAnnotation(errorAnnotation, new Position(1, 5));
143
144 };
145
146
147 /**
148 * Separate out properties that are different for accepted and related names
149 */
150 private void setViewerLayoutExtras() {
151 styledText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1));
152 styledText.setFont(SWTResourceManager.getFont("Georgia", 12, SWT.NONE));
153 }
154
155 public void setBindingContext(DataBindingContext bindingContext) {
156 this.bindingContext = bindingContext;
157 }
158
159 class NamePartitioner extends FastPartitioner {
160
161 List<ITypedRegion> wordPartitions;
162
163 public NamePartitioner(IPartitionTokenScanner scanner,
164 String[] legalContentTypes) {
165 super(scanner, legalContentTypes);
166 }
167
168 public ITypedRegion[] computePartitioning(int offset, int length, boolean includeZeroLengthPartitions) {
169
170 int fieldIndex = 0;
171
172 // System.out.print("Start re-partition at: " + offset + " -");
173 // for (int i = 0; i < fieldPartitions.length; i++) {
174 // System.out.print(" " + fieldPartitions[i].getOffset());
175 // }
176 // System.out.println();
177 //
178 // // find where the affected partitions begin
179 // while (fieldPartitions[fieldIndex].getOffset() < offset) {
180 // System.out.println(fieldPartitions[fieldIndex].getOffset() + " " + offset);
181 // fieldIndex++;
182 // }
183
184 // ITypedRegion[] regions = super.computePartitioning(offset, document.getLength() - offset,
185 // includeZeroLengthPartitions);
186 ITypedRegion[] regions = super.computePartitioning(0, document.getLength(),
187 includeZeroLengthPartitions);
188
189 for (int i = 0; i < regions.length; i++) {
190 if (regions[i].getType() == NamePartitionScanner_.SINGLE_WORD) {
191 // for now, assign first word to first fieldPartition, etc.
192 fieldPartitions[fieldIndex].setRegion(regions[i]);
193 fieldIndex++;
194 }
195 }
196
197 // put zero-length regions in remaining fieldPartitions
198 for (int i = fieldIndex; i < fieldPartitions.length; i++) {
199 fieldPartitions[fieldIndex].setRegion(
200 new TypedRegion(document.getLength(), 0,
201 NamePartitionScanner_.SINGLE_WORD));
202 }
203 return regions;
204 }
205
206
207 public void connect(IDocument document, boolean delayInitialise)
208 {
209 super.connect(document, delayInitialise);
210 // computePartitioning(0, document.getLength(), false);
211 }
212 }
213
214 class BoundPartition {
215 private ITypedRegion region;
216 private Binding binding;
217 private String field; // the name field to track
218 private String value; // the current value in this partition
219 private int length;
220 private int offset;
221 private StyleRange style = new StyleRange();
222
223 BoundPartition (String field) {
224 this.field = field;
225 this.length = 0;
226 this.offset = 0;
227
228 bindPartition();
229 }
230
231 BoundPartition (String field, int fontStyle) {
232 this(field);
233 style.fontStyle = fontStyle;
234 }
235
236 private void bindPartition() {
237 IObservableValue observePartitionValue =
238 BeansObservables.observeValue(this, "text");
239 IObservableValue observeModelValue =
240 BeansObservables.observeValue(taxonName, field);
241 this.binding = bindingContext.bindValue(
242 observePartitionValue, observeModelValue,
243 null, null);
244 }
245
246 public void setRegion (ITypedRegion region) {
247 this.region = region;
248 this.length = region.getLength();
249 this.offset = region.getOffset();
250
251 String oldValue = this.value;
252 try {
253 this.value = document.get(this.offset, this.length);
254 } catch (BadLocationException e) {
255 // TODO Auto-generated catch block
256 e.printStackTrace();
257 }
258 firePropertyChange("text",oldValue,this.value);
259
260 this.style.start = this.offset;
261 this.style.length = this.length;
262 styledText.setStyleRange(this.style);
263 }
264
265 public int getLength () {
266 return this.length;
267 }
268
269 public int getOffset () {
270 return this.offset;
271 }
272
273 public void setText(String newText) {
274 try {
275 document.replace(region.getOffset(), region.getLength(), newText);
276 } catch (BadLocationException e) {
277 // TODO Auto-generated catch block
278 e.printStackTrace();
279 }
280 }
281
282 public String getText() {
283 return this.value;
284 }
285
286 protected final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);
287 public void addPropertyChangeListener(PropertyChangeListener listener) {
288 propertyChangeSupport.addPropertyChangeListener(listener);
289 }
290
291 public void addPropertyChangeListener(String propertyName,
292 PropertyChangeListener listener) {
293 propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
294 }
295
296 public void removePropertyChangeListener(PropertyChangeListener listener) {
297 propertyChangeSupport.removePropertyChangeListener(listener);
298 }
299
300 public void removePropertyChangeListener(String propertyName,
301 PropertyChangeListener listener) {
302 propertyChangeSupport.removePropertyChangeListener(propertyName,
303 listener);
304 }
305
306 protected void firePropertyChange(String propertyName, Object oldValue,
307 Object newValue) {
308 propertyChangeSupport.firePropertyChange(propertyName, oldValue,
309 newValue);
310 }
311
312 // public StyleRange getStyle() {
313 // return style;
314 // }
315 //
316 // public void setStyle(StyleRange style) {
317 // this.style = style;
318 // }
319 }
320
321 // class AnnotationMarkerAccess implements IAnnotationAccess, IAnnotationAccessExtension {
322 // public Object getType(Annotation annotation) {
323 // return annotation.getType();
324 // }
325 //
326 // public boolean isMultiLine(Annotation annotation) {
327 // return true;
328 // }
329 //
330 // public boolean isTemporary(Annotation annotation) {
331 // return !annotation.isPersistent();
332 // }
333 //
334 // public String getTypeLabel(Annotation annotation) {
335 // if (annotation instanceof ErrorAnnotation)
336 // return "Errors";
337 //
338 // return null;
339 // }
340 //
341 // public int getLayer(Annotation annotation) {
342 // if (annotation instanceof ErrorAnnotation)
343 // return ((ErrorAnnotation)annotation).getLayer();
344 //
345 // return 0;
346 // }
347 //
348 // public void paint(Annotation annotation, GC gc, Canvas canvas, Rectangle bounds) {
349 // ImageUtilities.drawImage(((ErrorAnnotation)annotation).getImage(),
350 // gc, canvas, bounds, SWT.CENTER, SWT.TOP);
351 // }
352 //
353 // public boolean isPaintable(Annotation annotation) {
354 // if (annotation instanceof ErrorAnnotation)
355 // return ((ErrorAnnotation)annotation).getImage() != null;
356 //
357 // return false;
358 // }
359 //
360 // public boolean isSubtype(Object annotationType, Object potentialSupertype) {
361 // if (annotationType.equals(potentialSupertype))
362 // return true;
363 //
364 // return false;
365 //
366 // }
367 //
368 // public Object[] getSupertypes(Object annotationType) {
369 // return new Object[0];
370 // }
371 // }
372
373 // one error annotation
374 // class ErrorAnnotation extends Annotation {
375 // private IMarker marker;
376 // private String text;
377 // private int line;
378 // private Position position;
379 //
380 // public ErrorAnnotation(IMarker marker) {
381 // this.marker = marker;
382 // }
383 //
384 // public ErrorAnnotation(int line, String text) {
385 // super(ERROR_TYPE, true, null);
386 // this.marker = null;
387 // this.line = line;
388 // this.text = text;
389 // }
390 //
391 // public IMarker getMarker() {
392 // return marker;
393 // }
394 //
395 // public int getLine() {
396 // return line;
397 // }
398 //
399 // public String getText() {
400 // return text;
401 // }
402 //
403 // public Image getImage() {
404 // return ERROR_IMAGE;
405 // }
406 //
407 // public int getLayer() {
408 // return 3;
409 // }
410 //
411 // public String getType() {
412 // return ERROR_TYPE;
413 // }
414 //
415 // public Position getPosition() {
416 // return position;
417 // }
418 //
419 // public void setPosition(Position position) {
420 // this.position = position;
421 // }
422 // }
423
424 }