Massive refactoring of the methodology in former class UiUtils
[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.commands.ExecutionException;
17 import org.eclipse.core.commands.operations.IOperationHistory;
18 import org.eclipse.core.commands.operations.IUndoContext;
19 import org.eclipse.core.commands.operations.IUndoableOperation;
20 import org.eclipse.core.runtime.Assert;
21 import org.eclipse.core.runtime.IStatus;
22 import org.eclipse.jface.action.Action;
23 import org.eclipse.swt.events.DisposeEvent;
24 import org.eclipse.swt.events.DisposeListener;
25 import org.eclipse.swt.events.FocusAdapter;
26 import org.eclipse.swt.events.FocusEvent;
27 import org.eclipse.swt.graphics.Font;
28 import org.eclipse.swt.graphics.Image;
29 import org.eclipse.swt.widgets.Composite;
30 import org.eclipse.ui.forms.IManagedForm;
31 import org.eclipse.ui.views.properties.IPropertySource;
32
33 import eu.etaxonomy.cdm.model.name.BotanicalName;
34 import eu.etaxonomy.cdm.model.name.NonViralName;
35 import eu.etaxonomy.cdm.model.name.TaxonNameBase;
36 import eu.etaxonomy.cdm.model.name.ZoologicalName;
37 import eu.etaxonomy.cdm.model.reference.StrictReferenceBase;
38 import eu.etaxonomy.cdm.model.taxon.TaxonBase;
39 import eu.etaxonomy.taxeditor.ITaxEditorConstants;
40 import eu.etaxonomy.taxeditor.TaxEditorPlugin;
41 import eu.etaxonomy.taxeditor.controller.EditorController;
42 import eu.etaxonomy.taxeditor.controller.GlobalController;
43 import eu.etaxonomy.taxeditor.editor.EditorGroupedComposite;
44 import eu.etaxonomy.taxeditor.editor.LineBreakListener;
45 import eu.etaxonomy.taxeditor.editor.ParseListener;
46 import eu.etaxonomy.taxeditor.model.CdmUtil;
47 import eu.etaxonomy.taxeditor.operations.name.CreateSynonymInNewGroupOperation;
48 import eu.etaxonomy.taxeditor.propertysheet.name.BotanicalNamePropertySource;
49 import eu.etaxonomy.taxeditor.propertysheet.name.NonViralNamePropertySource;
50 import eu.etaxonomy.taxeditor.propertysheet.name.ZoologicalNamePropertySource;
51
52 /**
53 * Formats an <code>EditorGroupedComposite</code> to display <code>TaxonNameBase</code> elements
54 * in a <code>NameViewer</code>.
55 *
56 * @author p.ciardelli
57 * @created 02.06.2008
58 * @version 1.0
59 */
60 public abstract class NameComposite extends EditorGroupedComposite {
61 private static final Logger logger = Logger.getLogger(NameComposite.class);
62
63 /**
64 * ************ COMPOSITE TYPES ************
65 */
66 public String compositeType;
67 public static final String ACCEPTED_TAXON = "accepted_name_composite";
68 public static final String HOMOTYPIC_SYNONYM = "homotypic_name_composite";
69 public static final String HETEROTYPIC_SYNONYM = "heterotypic_name_composite";
70 public static final String MISAPPLIED_NAME = "misappliedname_name_composite";
71
72 /**
73 * ************ INDENTATIONS ************
74 */
75 public static final int ACCEPTED_INDENT = 0;
76 public static final int SYNONYM_INDENT = 15;
77 public static final int MISAPPLIEDNAME_INDENT = 15;
78
79 /**
80 * ************ FONTS ************
81 */
82 public static final Font ACCEPTED_FONT = TaxEditorPlugin.getDefault()
83 .getFont(ITaxEditorConstants.ACCEPTED_TAXON_FONT);
84 public static final Font SYNONYM_FONT = TaxEditorPlugin.getDefault()
85 .getFont(ITaxEditorConstants.SYNONYM_FONT);
86 public static final Font MISAPPLIEDNAME_FONT = TaxEditorPlugin.getDefault()
87 .getFont(ITaxEditorConstants.MISAPPLIEDNAME_FONT);
88
89 /**
90 * ************ ICONS ************
91 */
92 public static final Image ACCEPTED_ICON = TaxEditorPlugin.getDefault()
93 .getImage(ITaxEditorConstants.BLACK_SQUARE_ICON);
94 public static final Image HOMOTYPIC_SYNONYM_ICON = TaxEditorPlugin
95 .getDefault().getImage(ITaxEditorConstants.HOMOTYPIC_SYN_ICON);
96 public static final Image HOMOTYPIC_SYNONYM_ORIGINAL_COMBINATION_ICON = TaxEditorPlugin
97 .getDefault().getImage(
98 ITaxEditorConstants.HOMOTYPIC_SYN_ORIGINAL_ICON);
99 public static final Image HETEROTYPIC_SYNONYM_ICON = TaxEditorPlugin
100 .getDefault().getImage(ITaxEditorConstants.HETEROTYPIC_SYN_ICON);
101 public static final Image HETEROTYPIC_SYNONYM_ORIGINAL_COMBINATION_ICON = TaxEditorPlugin
102 .getDefault().getImage(
103 ITaxEditorConstants.HETEROTYPIC_SYN_ORIGINAL_ICON);
104 public static final Image MISAPPLIEDNAME_ICON = TaxEditorPlugin
105 .getDefault().getImage(ITaxEditorConstants.MISAPPLIED_NAME_ICON);
106 public static final Image AUTONYM_ICON = TaxEditorPlugin.getDefault()
107 .getImage(ITaxEditorConstants.AUTONYM_ICON);
108 public static final Image BASIONYM_ICON = TaxEditorPlugin.getDefault()
109 .getImage(ITaxEditorConstants.BASIONYM_ICON);
110 public static final Image MOVE = TaxEditorPlugin.getDefault().getImage(
111 ITaxEditorConstants.MOVE_ICON);
112
113 /**
114 * ************ TRANSFORMATIONS ************
115 */
116 public static final String ADD_GROUP_BASIONYM = "add_group_basionym";
117 public static final String REMOVE_GROUP_BASIONYM = "remove_group_basionym";
118
119 /**
120 * ************ MENU ACTIONS ************
121 */
122 public Action CHANGE_TAXON_TO_SYNONYM_ACTION;
123
124 private static final String EMPTY_NAME_PROMPT = "Click to add name";
125
126 /**
127 * Used to turn parser on and off.
128 *
129 * @see activateParser
130 * @see deactivateParser
131 */
132 private boolean isUseParser = false;
133
134 protected boolean isParsing;
135
136 private NameViewer nameViewer;
137
138 /**
139 * The constructor for a DescriptionElementComposite. Takes a parent Composite on which to
140 * create itself, and an IManagedForm for Composite life cycle methods, i.e.
141 * drawing borders, creating other Composites, creating line wrap support,
142 * etc.
143 *
144 * @param parent
145 * @param managedForm
146 */
147 public NameComposite(Composite parent, IManagedForm managedForm,
148 String compositeType, TaxonBase taxonBase) {
149 super(parent, managedForm);
150
151 createNameViewer();
152 createBorderSupport();
153 createLineWrapSupport();
154
155 setData(taxonBase);
156
157 createParser();
158 createEmptyViewerPrompt(EMPTY_NAME_PROMPT);
159 setFocus();
160
161 // NOTE: placing this after setFocus() inexplicably solved a strange bug where if the first action
162 // during a session was to open a new taxon, the empty name prompt didn't work
163 createNameListener(taxonBase.getName());
164 }
165
166 protected String getEmptyTextPrompt() {
167 return EMPTY_NAME_PROMPT;
168 }
169
170 /**
171 * Listens for changes to this name's <code>fullTitleCache</code>.
172 *
173 * @param data
174 */
175 private void createNameListener(final TaxonNameBase name) {
176
177 if (name == null) {
178 return;
179 }
180
181 final PropertyChangeListener listener = new PropertyChangeListener() {
182 public void propertyChange(PropertyChangeEvent evt) {
183
184 if (isParsing) {
185 return;
186 }
187
188 if (EditorController.isSaving()) {
189 return;
190 }
191
192 deactivateParser();
193 ((NameViewer) getTextViewer()).setText(name.getFullTitleCache());
194 activateParser();
195 }
196 };
197
198 // TODO clean this part up
199 name.addPropertyChangeListener("fullTitleCache", listener);
200 name.addPropertyChangeListener("nomenclaturalMicroReference", listener);
201
202 // name.addPropertyChangeListener(ITaxEditorConstants.REFRESH_NAMEVIEWER, listener);
203
204 StrictReferenceBase reference = (StrictReferenceBase) name.getNomenclaturalReference();
205 if (reference != null) {
206 reference.addPropertyChangeListener("titleCache", listener);
207 }
208 }
209
210 protected void initNameViewer(TaxonBase taxonBase) {
211 String text = CdmUtil.getDisplayNameWithRef(taxonBase);
212 if (text.length() == 0) {
213 initEmptyText();
214 } else {
215 getTextViewer().getTextWidget().setText(text);
216
217 if (getTextViewer() instanceof NameViewer) {
218
219 ((NameViewer) getTextViewer()).setCursorToEOL();
220
221 TaxonNameBase name = taxonBase.getName();
222 if (name != null) {
223
224 boolean hasProblem = name.getHasProblem();
225 ((NameViewer) getTextViewer()).setShowError(name);
226 }
227 }
228 }
229 }
230
231 private void createParser() {
232 ((NameViewer) getTextViewer()).addParseListener(new ParseListener() {
233
234 @Override
235 public void parse(String text) {
236
237 // Either composite is not yet fully built, or
238 // the property sheet is writing to it
239 if (!isUseParser) {
240 return;
241 }
242
243 // Let others know the parser is active
244 isParsing = true;
245
246 // Get the name from the composite's data field
247 TaxonBase taxonBase = (TaxonBase) getData();
248 NonViralName nonViralName = (NonViralName) taxonBase.getName();
249
250 // Parse the name and paint the text field w any errors
251 if (nonViralName != null) {
252 CdmParserController.parseFullReference(nonViralName, text);
253 ((NameViewer) getTextViewer()).setShowError(nonViralName);
254 }
255
256 // Any entry of text means the taxon has been changed
257 setDirty(true);
258
259 // The parser is no longer active
260 isParsing = false;
261
262 // Manually refresh the property sheet to reflect changes
263 setSelection();
264 }
265 });
266 activateParser();
267 }
268
269 public void activateParser() {
270 isUseParser = true;
271 }
272
273 public void deactivateParser() {
274 isUseParser = false;
275 }
276
277 private NameViewer createNameViewer() {
278 // nameViewer = new NameViewer(this);
279 // nameViewer.setLineBreakListener(new LineBreakListener() {
280
281 setTextViewer(new NameViewer(this));
282 getTextViewer().addLineBreakListener(new LineBreakListener() {
283
284 @Override
285 public void handleSplitText(String text) {
286
287 // Create a synonym in a new homotypic group using text as name
288 IUndoContext undoContext = EditorController.getUndoContext(taxon);
289 IUndoableOperation operation = new CreateSynonymInNewGroupOperation
290 ("new heterotypic synonym", undoContext, taxon, text); //$NON-NLS-1$
291
292 GlobalController.executeOperation(operation);
293
294 // getTextViewer().removeLineBreakListener(this);
295 }
296
297 });
298
299 getTextViewer().getTextWidget().addFocusListener(new FocusAdapter() {
300 public void focusGained(FocusEvent e) {
301 setFocus();
302 }
303 });
304
305 getTextViewer().getTextWidget().addDisposeListener(new DisposeListener() {
306
307 @Override
308 public void widgetDisposed(DisposeEvent e) {
309 logger.warn("disposing text widget");
310 }
311 });
312
313 // createLineWrapSupport(nameViewer);
314
315 getTextViewer().getTextWidget().setBackground(TaxEditorPlugin.getDefault().
316 getColor(ITaxEditorConstants.GROUP_GRAY_BKG_COLOR));
317
318 return (NameViewer) getTextViewer();
319 }
320
321 public void setText(String text) {
322 Assert.isNotNull(getTextViewer(),
323 "Cannot set text for a TextViewer that has not yet been initialized.");
324 Assert.isNotNull(getTextViewer().getDocument(),
325 "Cannot set text for a TextViewer whose Document has not yet been initialized.");
326 getTextViewer().getDocument().set(text);
327 }
328
329 public NameViewer getTextViewer() {
330 return this.nameViewer;
331 }
332
333 public void setTextViewer(NameViewer textViewer) {
334 this.nameViewer = textViewer;
335 }
336
337 protected IPropertySource getPropertySourceByName(TaxonNameBase name) {
338 if (name == null) {
339 return null;
340 }
341
342 if (name.getClass() == BotanicalName.class) {
343 return new BotanicalNamePropertySource((BotanicalName) name);
344 }
345 if (name.getClass() == ZoologicalName.class) {
346 return new ZoologicalNamePropertySource((ZoologicalName) name);
347 }
348 if (name instanceof NonViralName) {
349 return new NonViralNamePropertySource((NonViralName) name);
350 }
351
352 return null;
353 }
354 }