Added ability to color individual property sheet fields, which are implemented as...
[taxeditor.git] / eclipseprojects / eu.etaxonomy.taxeditor / src / eu / etaxonomy / taxeditor / editor / name / NameComposite.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;
11
12 import java.beans.PropertyChangeEvent;
13 import java.beans.PropertyChangeListener;
14
15 import org.apache.log4j.Logger;
16 import org.eclipse.core.runtime.Assert;
17 import org.eclipse.jface.action.Action;
18 import org.eclipse.jface.util.IPropertyChangeListener;
19 import org.eclipse.swt.events.DisposeEvent;
20 import org.eclipse.swt.events.DisposeListener;
21 import org.eclipse.swt.events.FocusAdapter;
22 import org.eclipse.swt.events.FocusEvent;
23 import org.eclipse.swt.graphics.Font;
24 import org.eclipse.swt.graphics.Image;
25 import org.eclipse.swt.widgets.Composite;
26 import org.eclipse.ui.forms.IManagedForm;
27
28 import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
29 import eu.etaxonomy.cdm.model.name.NonViralName;
30 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
31 import eu.etaxonomy.cdm.model.reference.StrictReferenceBase;
32 import eu.etaxonomy.cdm.model.taxon.Synonym;
33 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
34 import eu.etaxonomy.taxeditor.ITaxEditorConstants;
35 import eu.etaxonomy.taxeditor.TaxEditorPlugin;
36 import eu.etaxonomy.taxeditor.UiUtil;
37 import eu.etaxonomy.taxeditor.actions.ui.AdaptCompositeToGroupAction;
38 import eu.etaxonomy.taxeditor.actions.ui.AddBasionymCompositeAction;
39 import eu.etaxonomy.taxeditor.actions.ui.ChangeCompositeToMisappliedNameAction;
40 import eu.etaxonomy.taxeditor.actions.ui.ChangeCompositeToNewTaxonAction;
41 import eu.etaxonomy.taxeditor.actions.ui.ChangeSynonymToTaxonUiAction;
42 import eu.etaxonomy.taxeditor.actions.ui.ChangeTaxonToSynonymAction;
43 import eu.etaxonomy.taxeditor.actions.ui.CreateNewHeterotypicCompositeAction;
44 import eu.etaxonomy.taxeditor.actions.ui.DeleteMisappliedNameCompositeAction;
45 import eu.etaxonomy.taxeditor.actions.ui.DeleteSynonymCompositeAction;
46 import eu.etaxonomy.taxeditor.actions.ui.MoveCompositeToMisappliedCompositeAction;
47 import eu.etaxonomy.taxeditor.actions.ui.MoveTaxonDialogAction;
48 import eu.etaxonomy.taxeditor.actions.ui.RemoveBasionymCompositeAction;
49 import eu.etaxonomy.taxeditor.editor.ContextMenu;
50 import eu.etaxonomy.taxeditor.editor.EditorGroupComposite;
51 import eu.etaxonomy.taxeditor.editor.EditorGroupedComposite;
52 import eu.etaxonomy.taxeditor.editor.LineBreakListener;
53 import eu.etaxonomy.taxeditor.editor.ParseListener;
54 import eu.etaxonomy.taxeditor.model.CdmUtil;
55
56 /**
57 * Formats an <code>EditorGroupedComposite</code> to display <code>TaxonNameBase</code> elements
58 * in a <code>NameViewer</code>.
59 *
60 * <code>Composite.getData()</code> returns <code>TaxonBase</code>. Therefore, the method
61 * <code>setSelection()</code> is overriden to send the property sheet <code>TaxonBase.getName()</code>.
62 *
63 * @author p.ciardelli
64 * @created 02.06.2008
65 * @version 1.0
66 */
67 public class NameComposite extends EditorGroupedComposite {
68 private static final Logger logger = Logger.getLogger(NameComposite.class);
69
70 /**
71 * ************ COMPOSITE TYPES ************
72 */
73 public String compositeType;
74 public static final String ACCEPTED_TAXON = "accepted_name_composite";
75 public static final String HOMOTYPIC_SYNONYM = "homotypic_name_composite";
76 public static final String HETEROTYPIC_SYNONYM = "heterotypic_name_composite";
77 public static final String MISAPPLIED_NAME = "misappliedname_name_composite";
78
79 /**
80 * ************ INDENTATIONS ************
81 */
82 public static final int ACCEPTED_INDENT = 0;
83 public static final int SYNONYM_INDENT = 15;
84 public static final int MISAPPLIEDNAME_INDENT = 15;
85
86 /**
87 * ************ FONTS ************
88 */
89 public static final Font ACCEPTED_FONT = TaxEditorPlugin.getDefault()
90 .getFont(ITaxEditorConstants.ACCEPTED_TAXON_FONT);
91 public static final Font SYNONYM_FONT = TaxEditorPlugin.getDefault()
92 .getFont(ITaxEditorConstants.SYNONYM_FONT);
93 public static final Font MISAPPLIEDNAME_FONT = TaxEditorPlugin.getDefault()
94 .getFont(ITaxEditorConstants.MISAPPLIEDNAME_FONT);
95
96 /**
97 * ************ ICONS ************
98 */
99 public static final Image ACCEPTED_ICON = TaxEditorPlugin.getDefault()
100 .getImage(ITaxEditorConstants.BLACK_SQUARE_ICON);
101 public static final Image HOMOTYPIC_SYNONYM_ICON = TaxEditorPlugin
102 .getDefault().getImage(ITaxEditorConstants.HOMOTYPIC_SYN_ICON);
103 public static final Image HOMOTYPIC_SYNONYM_ORIGINAL_COMBINATION_ICON = TaxEditorPlugin
104 .getDefault().getImage(
105 ITaxEditorConstants.HOMOTYPIC_SYN_ORIGINAL_ICON);
106 public static final Image HETEROTYPIC_SYNONYM_ICON = TaxEditorPlugin
107 .getDefault().getImage(ITaxEditorConstants.HETEROTYPIC_SYN_ICON);
108 public static final Image HETEROTYPIC_SYNONYM_ORIGINAL_COMBINATION_ICON = TaxEditorPlugin
109 .getDefault().getImage(
110 ITaxEditorConstants.HETEROTYPIC_SYN_ORIGINAL_ICON);
111 public static final Image MISAPPLIEDNAME_ICON = TaxEditorPlugin
112 .getDefault().getImage(ITaxEditorConstants.MISAPPLIED_NAME_ICON);
113 public static final Image AUTONYM_ICON = TaxEditorPlugin.getDefault()
114 .getImage(ITaxEditorConstants.AUTONYM_ICON);
115 public static final Image BASIONYM_ICON = TaxEditorPlugin.getDefault()
116 .getImage(ITaxEditorConstants.BASIONYM_ICON);
117 public static final Image MOVE = TaxEditorPlugin.getDefault().getImage(
118 ITaxEditorConstants.MOVE_ICON);
119
120 /**
121 * ************ TRANSFORMATIONS ************
122 */
123 public static final String ADD_GROUP_BASIONYM = "add_group_basionym";
124 public static final String REMOVE_GROUP_BASIONYM = "remove_group_basionym";
125
126 /**
127 * ************ MENU ACTIONS ************
128 */
129 public Action CHANGE_TAXON_TO_SYNONYM_ACTION;
130
131 private static final String EMPTY_NAME_PROMPT = "Click to add name";
132
133 // private NameViewer nameViewer;
134 // private NameViewer textViewer;
135
136 /**
137 * Used to turn parser on and off.
138 *
139 * @see activateParser
140 * @see deactivateParser
141 */
142 private boolean isUseParser = false;
143
144 protected boolean isParsing;
145
146 private NameViewer nameViewer;
147
148 /**
149 * The constructor for a DescriptionElementComposite. Takes a parent Composite on which to
150 * create itself, and an IManagedForm for Composite life cycle methods, i.e.
151 * drawing borders, creating other Composites, creating line wrap support,
152 * etc.
153 *
154 * @param parent
155 * @param managedForm
156 */
157 public NameComposite(Composite parent, IManagedForm managedForm, String compositeType, TaxonBase data) {
158 super(parent, managedForm);
159
160 createNameViewer();
161 createBorderSupport();
162 createLineWrapSupport();
163
164 setData(data);
165
166 createNameListener(data);
167
168 transform(compositeType);
169
170 createEmptyViewerPrompt(EMPTY_NAME_PROMPT);
171 createParser();
172
173 setFocus();
174 }
175
176 /**
177 * Listens for changes to this name's <code>fullTitleCache</code>.
178 *
179 * @param data
180 */
181 private void createNameListener(TaxonBase taxonBase) {
182 if (taxonBase.getName() == null) {
183 return;
184 }
185
186 final TaxonNameBase name = taxonBase.getName();
187
188 final PropertyChangeListener listener = new PropertyChangeListener() {
189 public void propertyChange(PropertyChangeEvent evt) {
190
191 if (isParsing) {
192 return;
193 }
194
195 deactivateParser();
196 ((NameViewer) getTextViewer()).setText(name.getFullTitleCache());
197 activateParser();
198 }
199 };
200
201 name.addPropertyChangeListener("fullTitleCache", listener);
202 name.addPropertyChangeListener("nomenclaturalMicroReference", listener);
203
204 name.addPropertyChangeListener(ITaxEditorConstants.REFRESH_NAMEVIEWER, listener);
205
206 StrictReferenceBase reference = (StrictReferenceBase) name.getNomenclaturalReference();
207 if (reference != null) {
208 reference.addPropertyChangeListener("titleCache", listener);
209 }
210
211 this.addDisposeListener(new DisposeListener() {
212
213 public void widgetDisposed(DisposeEvent e) {
214 // name.removePropertyChangeListener(listener);
215 }
216 });
217 }
218
219 /**
220 * All cosmetic - non-data-related, i.e. icons, fonts, etc. -
221 * transformations take place in this method.
222 *
223 * @param transformation
224 */
225 public void transform(String transformation) {
226
227 if (transformation.equals(ADD_GROUP_BASIONYM)) {
228 if (compositeType.equals(HOMOTYPIC_SYNONYM)) {
229 setIcon(HOMOTYPIC_SYNONYM_ORIGINAL_COMBINATION_ICON);
230 } else {
231 setIcon(HETEROTYPIC_SYNONYM_ORIGINAL_COMBINATION_ICON);
232 }
233 }
234
235 if (transformation.equals(REMOVE_GROUP_BASIONYM)) {
236 if (compositeType.equals(HOMOTYPIC_SYNONYM)) {
237 setIcon(HOMOTYPIC_SYNONYM_ICON);
238 } else {
239 setIcon(HETEROTYPIC_SYNONYM_ICON);
240 }
241 }
242
243 if (transformation.equals(ACCEPTED_TAXON)) {
244 setDraggable(false);
245 setIcon(ACCEPTED_ICON);
246 setFont(ACCEPTED_FONT);
247 setIndent(ACCEPTED_INDENT);
248
249 createAcceptedMenu();
250
251 compositeType = ACCEPTED_TAXON;
252 }
253
254 if (transformation.equals(HOMOTYPIC_SYNONYM)
255 || transformation.equals(HETEROTYPIC_SYNONYM)) {
256 setDraggable(true);
257 setFont(SYNONYM_FONT);
258 setIndent(SYNONYM_INDENT);
259
260 createSynonymMenu();
261 }
262
263 if (transformation.equals(HOMOTYPIC_SYNONYM)) {
264 if (!(getData() instanceof Synonym)) {
265 return;
266 }
267 Synonym synonym = (Synonym) getData();
268 if (CdmUtil.isNameGroupBasionym(synonym.getName())) {
269 setIcon(HOMOTYPIC_SYNONYM_ORIGINAL_COMBINATION_ICON);
270 } else {
271 setIcon(HOMOTYPIC_SYNONYM_ICON);
272 }
273 compositeType = HOMOTYPIC_SYNONYM;
274 }
275
276 if (transformation.equals(HETEROTYPIC_SYNONYM)) {
277 if (!(getData() instanceof Synonym)) {
278 return;
279 }
280 Synonym synonym = (Synonym) getData();
281 if (CdmUtil.isNameGroupBasionym(synonym.getName())) {
282 setIcon(HETEROTYPIC_SYNONYM_ORIGINAL_COMBINATION_ICON);
283 } else {
284 setIcon(HETEROTYPIC_SYNONYM_ICON);
285 }
286 compositeType = HETEROTYPIC_SYNONYM;
287 }
288
289 if (transformation.equals(MISAPPLIED_NAME)) {
290
291 setDraggable(true);
292 setIcon(MISAPPLIEDNAME_ICON);
293 setFont(MISAPPLIEDNAME_FONT);
294 setIndent(MISAPPLIEDNAME_INDENT);
295
296 createMisappliedNameMenu();
297
298 compositeType = MISAPPLIED_NAME;
299 }
300
301 setDirty(true);
302 managedForm.getForm().layout();
303 }
304
305 /**
306 * Override of Composite.setData() which passes data along to
307 * <code>NameComposite</code>'s <code>TextViewer</code> where appropriate.
308 *
309 * @see org.eclipse.swt.widgets.Widget#setData(java.lang.Object)
310 */
311 public void setData(Object data) {
312 super.setData(data);
313
314 Assert.isTrue((data instanceof TaxonBase),
315 "NameComposite's data field must contain a TaxonBase object");
316
317 String text = CdmUtil.getDisplayNameAndRef((TaxonBase) data);
318 getTextViewer().getTextWidget().setText(text);
319
320 if (getTextViewer() instanceof NameViewer) {
321 ((NameViewer) getTextViewer()).setCursorToEOL();
322
323 if (((TaxonBase) data).getName() != null) {
324 boolean hasProblem = ((TaxonBase) data).getName()
325 .getHasProblem();
326 ((NameViewer) getTextViewer()).setShowError(hasProblem);
327 }
328 }
329
330 }
331
332 /* (non-Javadoc)
333 * @see eu.etaxonomy.taxeditor.editor.name.EditorGroupedComposite#setSelection()
334 */
335 protected void setSelection() {
336 if (getData() instanceof TaxonBase) {
337
338 Object selectionInput = null;
339
340 if (compositeType.equals(MISAPPLIED_NAME)) {
341
342 // A misapplied name's property sheet must display both name and sec. ref.
343 selectionInput = getData();
344 } else {
345
346 // All other composite types display only their name in property sheet
347 selectionInput = ((TaxonBase) getData()).getName();
348 }
349
350 // Send input to the property sheet via the managed form
351 managedForm.setInput(selectionInput);
352 } else {
353 super.setSelection();
354 }
355 }
356
357 private void createParser() {
358 ((NameViewer) getTextViewer()).setParseListener(new ParseListener() {
359
360 @Override
361 public void parse(String text) {
362
363 isParsing = true;
364
365 if (!isUseParser) {
366 return;
367 }
368
369 TaxonBase taxonBase = (TaxonBase) getData();
370 NonViralName nonViralName = (NonViralName) taxonBase.getName();
371
372 if (nonViralName != null) {
373 CdmUtil.parseFullReference(nonViralName, text, null, true);
374 ((NameViewer) getTextViewer()).setShowError(nonViralName.getHasProblem());
375 }
376
377 setDirty(true);
378
379 isParsing = false;
380
381 UiUtil.getPropertySheetPage().refresh();
382 }
383 });
384 activateParser();
385 }
386
387 public void activateParser() {
388 isUseParser = true;
389 }
390
391 public void deactivateParser() {
392 isUseParser = false;
393 }
394
395 private NameViewer createNameViewer() {
396 // nameViewer = new NameViewer(this);
397 // nameViewer.setLineBreakListener(new LineBreakListener() {
398
399 setTextViewer(new NameViewer(this));
400 getTextViewer().setLineBreakListener(new LineBreakListener() {
401
402 @Override
403 public void handleSplitText(String text) {
404
405 Composite parent = getParent();
406 final Composite grandParent = parent.getParent();
407
408 new CreateNewHeterotypicCompositeAction(text, managedForm)
409 .run();
410
411 // setDirty(true);
412 }
413
414 });
415
416 // nameViewer.getTextWidget().addFocusListener(new FocusAdapter() {
417 getTextViewer().getTextWidget().addFocusListener(new FocusAdapter() {
418 public void focusGained(FocusEvent e) {
419 setFocus();
420 }
421 });
422
423 // createLineWrapSupport(nameViewer);
424 //
425 // this.textViewer = nameViewer;
426 // nameViewer.getTextWidget().setBackground(TaxEditorPlugin.getDefault().
427 // getColor(ITaxEditorConstants.GROUP_GRAY_BKG_COLOR));
428 getTextViewer().getTextWidget().setBackground(TaxEditorPlugin.getDefault().
429 getColor(ITaxEditorConstants.GROUP_GRAY_BKG_COLOR));
430
431 return (NameViewer) getTextViewer();
432 }
433
434 /**
435 * @param nameComposite
436 */
437 private void createSynonymMenu() {
438
439 if (!(getData() instanceof Synonym)) {
440 return;
441 }
442
443 Synonym synonym = (Synonym) getData();
444 ContextMenu contextMenu = createContextMenu();
445
446 Action misappliedNameAction = new MoveCompositeToMisappliedCompositeAction(
447 this, managedForm);
448 contextMenu.addAction(misappliedNameAction);
449
450 Action deleteSynonymAction = new DeleteSynonymCompositeAction(this,
451 getTaxon());
452 contextMenu.addAction(deleteSynonymAction);
453
454 contextMenu.addSeparator();
455
456 final Action addBasionymAction = new AddBasionymCompositeAction(this);
457 contextMenu.addAction(addBasionymAction);
458
459 final Action removeBasionymAction = new RemoveBasionymCompositeAction(
460 this);
461 contextMenu.addAction(removeBasionymAction);
462
463 addBasionymAction
464 .addPropertyChangeListener(new IPropertyChangeListener() {
465 public void propertyChange(
466 org.eclipse.jface.util.PropertyChangeEvent event) {
467 if (event.getProperty().equals(
468 ITaxEditorConstants.BASIONYM)) {
469 removeBasionymAction.setEnabled(true);
470 transform(NameComposite.ADD_GROUP_BASIONYM);
471 }
472 }
473 });
474
475 removeBasionymAction
476 .addPropertyChangeListener(new IPropertyChangeListener() {
477 public void propertyChange(
478 org.eclipse.jface.util.PropertyChangeEvent event) {
479 if (event.getProperty().equals(
480 ITaxEditorConstants.BASIONYM)) {
481 addBasionymAction.setEnabled(true);
482 transform(NameComposite.REMOVE_GROUP_BASIONYM);
483 }
484 }
485 });
486
487 contextMenu.addSeparator();
488
489 Action changeToThisTaxon = new ChangeSynonymToTaxonUiAction(synonym,
490 getTaxon());
491 contextMenu.addAction(changeToThisTaxon);
492
493 Action changeToNewAccepted = new ChangeCompositeToNewTaxonAction(this,
494 getTaxon());
495 contextMenu.addAction(changeToNewAccepted);
496 }
497
498 /**
499 * @param nameComposite
500 */
501 private void createAcceptedMenu() {
502
503 ContextMenu contextMenu = createContextMenu();
504
505 // TODO Make action "Create autonym and subspecies"
506
507 Action changeTaxonAction = new ChangeTaxonToSynonymAction(getTaxon());
508 contextMenu.addAction(changeTaxonAction);
509
510 Action moveTaxonAction = new MoveTaxonDialogAction(getTaxon());
511 contextMenu.addAction(moveTaxonAction);
512 }
513
514 /**
515 * @param nameComposite
516 */
517 private void createMisappliedNameMenu() {
518
519 ContextMenu contextMenu = createContextMenu();
520
521 Action deleteMisappliedNameAction = new DeleteMisappliedNameCompositeAction(
522 this, getTaxon());
523 contextMenu.addAction(deleteMisappliedNameAction);
524 }
525
526 public boolean setParent(Composite parent) {
527
528 if (super.setParent(parent)) {
529
530 // Has this been moved to the misapplied names group?
531 if (parent.getData(ITaxEditorConstants.MISAPPLIED_NAME) != null) {
532 new ChangeCompositeToMisappliedNameAction(this, managedForm)
533 .run();
534 }
535
536 // Has this been moved to a HomotypicalGroup?
537 if (parent.getData() instanceof HomotypicalGroup) {
538 new AdaptCompositeToGroupAction(this,
539 (EditorGroupComposite) parent).run();
540 }
541 return true;
542
543 }
544 return false;
545 }
546
547 public void setText(String text) {
548 Assert.isNotNull(getTextViewer(),
549 "Cannot set text for a TextViewer that has not yet been initialized.");
550 Assert.isNotNull(getTextViewer().getDocument(),
551 "Cannot set text for a TextViewer whose Document has not yet been initialized.");
552 getTextViewer().getDocument().set(text);
553 }
554
555 public NameViewer getTextViewer() {
556 return this.nameViewer;
557 }
558
559 public void setTextViewer(NameViewer textViewer) {
560 this.nameViewer = textViewer;
561 }
562 }