0e6533fcc7acd23511ebc1de5b24a5c7158a684a
[taxeditor.git] / taxeditor-editor / src / main / java / eu / etaxonomy / taxeditor / editor / name / TaxonNameEditor.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 import java.util.HashMap;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Set;
18
19 import org.apache.log4j.Logger;
20 import org.eclipse.core.commands.operations.IUndoableOperation;
21 import org.eclipse.core.runtime.Assert;
22 import org.eclipse.core.runtime.IProgressMonitor;
23 import org.eclipse.swt.dnd.DND;
24 import org.eclipse.swt.dnd.DropTarget;
25 import org.eclipse.swt.dnd.DropTargetAdapter;
26 import org.eclipse.swt.dnd.DropTargetEvent;
27 import org.eclipse.swt.dnd.Transfer;
28 import org.eclipse.swt.widgets.Composite;
29 import org.eclipse.swt.widgets.Control;
30 import org.eclipse.swt.widgets.Event;
31 import org.eclipse.swt.widgets.Listener;
32 import org.eclipse.ui.IEditorInput;
33 import org.eclipse.ui.IEditorSite;
34 import org.eclipse.ui.PartInitException;
35 import org.eclipse.ui.forms.widgets.FormToolkit;
36
37 import eu.etaxonomy.cdm.model.name.HomotypicalGroup;
38 import eu.etaxonomy.cdm.model.taxon.Synonym;
39 import eu.etaxonomy.cdm.model.taxon.Taxon;
40 import eu.etaxonomy.cdm.model.taxon.TaxonRelationship;
41 import eu.etaxonomy.cdm.model.taxon.TaxonRelationshipType;
42 import eu.etaxonomy.taxeditor.editor.AbstractTaxonEditor;
43 import eu.etaxonomy.taxeditor.editor.CompositeBorderDecorator;
44 import eu.etaxonomy.taxeditor.editor.EditorUtil;
45 import eu.etaxonomy.taxeditor.editor.GroupComposite;
46 import eu.etaxonomy.taxeditor.editor.GroupedComposite;
47 import eu.etaxonomy.taxeditor.editor.MultiPageTaxonEditor;
48 import eu.etaxonomy.taxeditor.editor.WidgetTransfer;
49 import eu.etaxonomy.taxeditor.model.Resources;
50 import eu.etaxonomy.taxeditor.operations.ChangeConceptToSynonymOperation;
51 import eu.etaxonomy.taxeditor.operations.ChangeHomotypicGroupOperation;
52
53 /**
54 * @author p.ciardelli
55 * @created 15.05.2008
56 * @version 1.0
57 */
58 public class TaxonNameEditor extends AbstractTaxonEditor
59 implements INameEditorCompositeRepository {
60 private static final Logger logger = Logger.getLogger(TaxonNameEditor.class);
61
62 private static final String ID = "eu.etaxonomy.taxeditor.taxonNameEditor";
63
64
65 public TaxonNameEditor(MultiPageTaxonEditor editor){
66 super(editor);
67 }
68
69 /**
70 * Shared listener that sets dirty state to true
71 * when any registered property changes
72 */
73 private PropertyChangeListener taxonChangeListener = new PropertyChangeListener() {
74 public void propertyChange(PropertyChangeEvent event) {
75 if (event.getPropertyName().equals(Resources.PROPERTY_SHEET_CHANGE)) {
76 firePropertyChange(PROP_DIRTY);
77 }
78 }
79 };
80
81 private Map<HomotypicalGroup, HomotypicalGroupComposite> homotypicGroupComposites;
82
83 private MisappliedGroupComposite misappliedGroupComposite;
84
85 private ConceptGroupComposite conceptGroupComposite;
86
87 @Override
88 public void doSave(IProgressMonitor monitor) {}
89
90 @Override
91 public void doSaveAs() {}
92
93 @Override
94 public void init(IEditorSite site, IEditorInput input)
95 throws PartInitException {
96
97 super.init(site, input);
98
99 // Register listeners for any change in accepted name or set of relations
100 taxon.getName().addPropertyChangeListener(taxonChangeListener);
101 taxon.addPropertyChangeListener(taxonChangeListener);
102 }
103
104 @Override
105 public boolean isDirty() {
106 return false;
107 }
108
109 @Override
110 public boolean isSaveAsAllowed() {
111 return false;
112 }
113
114 @Override
115 protected void createManagedForm(Composite composite) {
116
117 super.createManagedForm(composite);
118
119 Taxon taxon = getTaxon();
120
121 firstGroupedComposite = createAcceptedTaxon();
122
123 // Draw homotypic group synonyms
124 HomotypicalGroup homotypicGroup = taxon.getHomotypicGroup();
125
126 if (homotypicGroup != null) {
127 List<Synonym> homotypicSynonyms = homotypicGroup.getSynonymsInGroup(taxon.getSec());
128 for (Synonym synonym : homotypicSynonyms) {
129
130 // Make sure synonym belongs to the taxon
131 if (synonym.getAcceptedTaxa().contains(taxon)) {
132 createSynonym(synonym);
133 }
134 }
135 }
136
137 // Draw heterotypic synonym groups
138 List<HomotypicalGroup> heterotypicGroups = taxon.getHeterotypicSynonymyGroups();
139 for (HomotypicalGroup heterotypicGroup : heterotypicGroups) {
140
141 // Make sure this is not the taxon's homotypic group
142 if (!heterotypicGroup.equals(homotypicGroup)) {
143
144 List<Synonym> heterotypicSynonyms = heterotypicGroup.
145 getSynonymsInGroup(taxon.getSec());
146 for (Synonym synonym : heterotypicSynonyms) {
147
148 // Make sure synonym belongs to the taxon
149 if (synonym.getAcceptedTaxa().contains(taxon)) {
150 createSynonym(synonym);
151 }
152 }
153 }
154 }
155
156 // Draw misapplied name elements
157 for(Taxon misappliedName : taxon.getMisappliedNames()){
158 createMisappliedName(misappliedName);
159 }
160
161 // Draw concept relation elements
162 Set<TaxonRelationship> taxonRelations = taxon.getTaxonRelations();
163 for (TaxonRelationship relationship : taxonRelations) {
164
165 if (relationship.getType().equals(TaxonRelationshipType.MISAPPLIED_NAME_FOR()) ||
166 relationship.getType().equals(TaxonRelationshipType.TAXONOMICALLY_INCLUDED_IN())) {
167 continue;
168 }
169
170 createConcept(relationship);
171 }
172
173 createDragSupport();
174
175 setFocus();
176
177 // Redraw composite
178 composite.layout();
179 }
180
181
182 /**
183 *
184 */
185 private void createDragSupport() {
186 // Listen for names being dragged outside of existing homotypic groups -
187 // user wants to create a new group
188 Transfer[] types = new Transfer[] {WidgetTransfer.getInstance()};
189 int operations = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT;
190 DropTarget target = new DropTarget(parent, operations);
191 target.setTransfer(types);
192 target.addDropListener(new DropTargetAdapter() {
193
194 public void drop(DropTargetEvent event) {
195
196 if (event.data instanceof GroupedComposite) {
197 final GroupedComposite composite = (GroupedComposite) event.data;
198 if (composite.getDragSource() != null) {
199
200 // Execute operations at end of drag event
201 composite.getDragSource().addListener(DND.DragEnd, new Listener() {
202
203 public void handleEvent(Event event) {
204 IUndoableOperation operation = null;
205
206 // Synonym being dropped
207 if(composite instanceof SynonymComposite){
208 Synonym synonym = ((SynonymComposite)composite).getSynonym();
209 operation = new ChangeHomotypicGroupOperation
210 ("change type", getUndoContext(),
211 getTaxon(), synonym, HomotypicalGroup.NewInstance(), TaxonNameEditor.this);
212 }
213
214 // Misapplied name being dropped
215 if(composite instanceof MisappliedNameComposite){
216 Taxon misapplication = ((MisappliedNameComposite)composite).getMisappliedName();
217 operation = new ChangeConceptToSynonymOperation
218 ("change misapplied name to synonym", getUndoContext(),
219 getTaxon(), misapplication, HomotypicalGroup.NewInstance(), TaxonNameEditor.this);
220 }
221
222 // Execute operation if it's been init'ed
223 if (operation == null) {
224 logger.warn("User unsuccessfully tried to drop " + composite.getClass());
225 } else {
226 EditorUtil.executeOperation(operation);
227 }
228 }
229 });
230 }
231 }
232
233
234 }
235 });
236 }
237
238 public Composite getAcceptedName() {
239 // accepted name should always reside in firstGroupComposite
240 if(firstGroupedComposite instanceof AcceptedNameComposite){
241 return firstGroupedComposite;
242 }
243
244 // for(Composite c : getGroupedComposites()){
245 // if(c instanceof AcceptedNameComposite){
246 // return c;
247 // }
248 // }
249 return null;
250 }
251
252 /**
253 * @return
254 */
255 private Map<HomotypicalGroup, HomotypicalGroupComposite> getHomotypicGroups() {
256 if(homotypicGroupComposites == null){
257 homotypicGroupComposites = new HashMap<HomotypicalGroup, HomotypicalGroupComposite>();
258 }
259 return homotypicGroupComposites;
260 }
261
262 public HomotypicalGroupComposite getHomotypicGroup(HomotypicalGroup group) {
263 return getHomotypicGroups().get(group);
264 }
265
266
267 public Composite getMisappliedGroup() {
268 return misappliedGroupComposite;
269 }
270
271
272 public Composite getMisappliedName(Taxon misappliedName) {
273 for(Control child : getMisappliedGroup().getChildren()){
274 if(child instanceof MisappliedNameComposite){
275 return (MisappliedNameComposite) child;
276 }
277 }
278 return null;
279 }
280
281
282 public Composite getSynonym(Synonym synonym) {
283
284 GroupComposite groupComposite = getHomotypicGroup(synonym.getHomotypicGroup());
285
286 for (Control child : groupComposite.getChildren()){
287 if(child instanceof SynonymComposite
288 && synonym.equals(((SynonymComposite) child).getSynonym())){
289 return (SynonymComposite) child;
290 }
291 }
292
293 return null;
294 }
295
296
297 public Composite getConceptGroup() {
298 return conceptGroupComposite;
299 }
300
301
302 public Composite getConcept(Taxon relatedConcept) {
303 for (Control child : getConceptGroup().getChildren()){
304 if(child instanceof ConceptComposite
305 && relatedConcept.equals
306 (((ConceptComposite) child).getRelatedTaxon())){
307 return (ConceptComposite) child;
308 }
309 }
310
311 return null;
312 }
313
314 /* (non-Javadoc)
315 * @see eu.etaxonomy.taxeditor.editor.AbstractTaxonEditor#getID()
316 */
317 @Override
318 public String getID() {
319 return TaxonNameEditor.ID;
320 }
321
322
323 /***********************************************************************/
324
325 private GroupedComposite createAcceptedTaxon() {
326 // Create a homotypic group composite for the accepted taxon
327 HomotypicalGroup group = getTaxon().getHomotypicGroup();
328 Assert.isNotNull(group, "Taxon does not have a homotypic group");
329
330 createHomotypicalGroup(group);
331
332 // Create a name composite for the accepted taxon
333 return new AcceptedNameComposite(this, getHomotypicGroup(group));
334 }
335
336 private HomotypicalGroupComposite createHomotypicalGroup(HomotypicalGroup group) {
337
338 // Create the group composite
339 HomotypicalGroupComposite groupComposite = new HomotypicalGroupComposite(this, getTopLevelComposite(), group);
340
341
342 //groupComposite.addFocusListener(new CompositeBorderDecorator(groupComposite, editor.getManagedForm()));
343
344 groupComposite.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER);
345 getManagedForm().getToolkit().paintBordersFor(groupComposite.getParent());
346
347 getHomotypicGroups().put(group, groupComposite);
348
349 return groupComposite;
350 }
351
352
353 private Composite createSynonym(Synonym synonym) {
354 // Get the synonym's homotypic group
355 HomotypicalGroup group = synonym.getHomotypicGroup();
356 Assert.isNotNull(group, "Synonym does not have a homotypic group");
357
358 // If the group doesn't yet have a composite, create one and add it to the repository
359 HomotypicalGroupComposite groupComposite = getHomotypicGroup(group);
360 if (groupComposite == null) {
361 groupComposite = createHomotypicalGroup(group);
362 }
363
364 // Create a synonym composite in the homotypical group
365 Composite synonymComposite = new SynonymComposite(this, groupComposite, synonym);
366
367 return synonymComposite;
368 }
369
370 public Composite createMisappliedName(Taxon misappliedName) {
371
372 // If there is no composite for misapplied names,
373 // create one and add it to the repository
374 Composite groupComposite = getMisappliedGroup();
375 if (groupComposite == null) {
376 groupComposite = createMisappliedGroup();
377 }
378
379 // Create the name's composite
380 Composite composite = new MisappliedNameComposite(this, groupComposite, misappliedName);
381
382 return composite;
383 }
384
385
386 public MisappliedGroupComposite createMisappliedGroup() {
387 // Create the group composite
388 misappliedGroupComposite = new MisappliedGroupComposite(this, this.getTopLevelComposite());
389 misappliedGroupComposite.addFocusListener(new CompositeBorderDecorator(misappliedGroupComposite, this.getManagedForm()));
390
391 // Put the group composite before concept group composite, if any
392 Composite conceptGroupComposite = this.getConceptGroup();
393 if (conceptGroupComposite != null) {
394 misappliedGroupComposite.moveAbove(conceptGroupComposite);
395 }
396
397 return misappliedGroupComposite;
398 }
399
400
401 public Composite createConcept(TaxonRelationship relationship) {
402 // If there is no composite for misapplied names,
403 // create one and add it to the repository
404 Composite groupComposite = this.getConceptGroup();
405 if (groupComposite == null) {
406 groupComposite = createConceptGroup();
407 }
408
409 // Create the name's composite
410 Composite composite = ConceptComposite.getNewInstance(this, groupComposite, relationship);
411
412 return composite;
413 }
414
415
416 public Composite createConceptGroup() {
417 // Create the group composite
418 conceptGroupComposite = new ConceptGroupComposite(this, this.getTopLevelComposite());
419 conceptGroupComposite.addFocusListener(new CompositeBorderDecorator(conceptGroupComposite, this.getManagedForm()));
420
421 // Put the group composite after misapplied group composite, if any
422 Composite misappliedGroupComposite = this.getMisappliedGroup();
423 if (misappliedGroupComposite != null) {
424 conceptGroupComposite.moveBelow(misappliedGroupComposite);
425 }
426
427 return conceptGroupComposite;
428
429 }
430 }