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