2 * Copyright (C) 2007 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
10 package eu
.etaxonomy
.taxeditor
.model
;
12 import java
.util
.ArrayList
;
13 import java
.util
.Collection
;
14 import java
.util
.HashMap
;
15 import java
.util
.HashSet
;
16 import java
.util
.List
;
19 import java
.util
.SortedSet
;
20 import java
.util
.UUID
;
22 import org
.apache
.log4j
.Logger
;
23 import org
.eclipse
.core
.databinding
.observable
.Realm
;
24 import org
.eclipse
.core
.databinding
.observable
.set
.IObservableSet
;
25 import org
.eclipse
.core
.databinding
.observable
.set
.ISetChangeListener
;
26 import org
.eclipse
.core
.databinding
.observable
.set
.SetChangeEvent
;
27 import org
.eclipse
.core
.databinding
.observable
.set
.WritableSet
;
28 import org
.eclipse
.jface
.databinding
.swt
.SWTObservables
;
29 import org
.eclipse
.swt
.widgets
.Display
;
31 import eu
.etaxonomy
.cdm
.api
.application
.CdmApplicationController
;
32 import eu
.etaxonomy
.cdm
.api
.service
.ITermService
;
33 import eu
.etaxonomy
.cdm
.model
.common
.Language
;
34 import eu
.etaxonomy
.cdm
.model
.common
.OrderedTermVocabulary
;
35 import eu
.etaxonomy
.cdm
.model
.common
.TermVocabulary
;
36 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
37 import eu
.etaxonomy
.cdm
.model
.name
.NameRelationshipType
;
38 import eu
.etaxonomy
.cdm
.model
.name
.NomenclaturalStatusType
;
39 import eu
.etaxonomy
.cdm
.model
.name
.Rank
;
40 import eu
.etaxonomy
.cdm
.model
.reference
.ReferenceBase
;
41 import eu
.etaxonomy
.cdm
.model
.taxon
.Taxon
;
42 import eu
.etaxonomy
.cdm
.model
.taxon
.TaxonRelationshipType
;
43 import eu
.etaxonomy
.taxeditor
.datasource
.CdmTransactionController
;
44 import eu
.etaxonomy
.taxeditor
.editor
.name
.CdmParserController
;
45 import eu
.etaxonomy
.taxeditor
.navigation
.QuickNameTaxon
;
46 import eu
.etaxonomy
.taxeditor
.navigation
.RecentNamesView
;
53 public class CdmSessionDataRepository
implements ICdmSessionDataRepository
{
54 private static final Logger logger
= Logger
55 .getLogger(CdmSessionDataRepository
.class);
57 private static ICdmSessionDataRepository repository
;
60 * This map of taxa to their taxonomic children is used by
61 * NameTreeContentProvider's getChildren method.
63 * key = taxon, value = key's child taxa Note that a map can have a key ==
64 * null, i.e. no parent taxon
66 private HashMap
<Taxon
, Set
<Taxon
>> taxonomicChildrenMap
;
68 private CdmApplicationController applicationController
;
70 private IObservableSet observableTaxonSet
;
72 private List
<ICdmTaxonSetListener
> listeners
;
74 private TermVocabulary
<Feature
> features
;
76 private SortedSet
<Rank
> ranks
;
78 private TermVocabulary
<NomenclaturalStatusType
> nomStatus
;
80 private SortedSet
<NameRelationshipType
> nameRelationshipTypes
;
82 private OrderedTermVocabulary
<TaxonRelationshipType
> taxonRelationshipTypes
;
84 private Set
<TaxonRelationshipType
> conceptRelationshipTypes
;
86 public static ICdmSessionDataRepository
getDefault() {
88 if (repository
== null) {
89 repository
= new CdmSessionDataRepository();
96 private CdmSessionDataRepository() {
97 getObservableTaxa().addSetChangeListener(new observableTaxaListener());
101 public void clearAllData() {
107 public void clearTaxonData() {
110 // Clear "recent names" list
111 RecentNamesView
.clearRecentNames();
115 public void clearNonTaxonData() {
119 taxonRelationshipTypes
= null;
120 nameRelationshipTypes
= null;
121 conceptRelationshipTypes
= null;
123 // Parser is also transaction-, and therefore session-, dependent
124 CdmParserController
.clearNonViralNameParser();
128 public void setApplicationController(CdmApplicationController applicationController
) {
129 this.applicationController
= applicationController
;
132 private Map
<Taxon
, Set
<Taxon
>> getTaxonomicChildrenMap() {
133 if (taxonomicChildrenMap
== null) {
134 taxonomicChildrenMap
= new HashMap
<Taxon
, Set
<Taxon
>>();
136 return taxonomicChildrenMap
;
139 private CdmApplicationController
getApplicationController() {
140 // Make sure the app controller has been set
141 if (applicationController
== null) {
142 throw new IllegalStateException("CdmApplicationController not yet set.");
144 return applicationController
;
148 public ReferenceBase
getDefaultSec() {
149 // TODO why is this returning null? and of course, replace w the real deal
150 return getApplicationController().getReferenceService().getReferenceByUuid(
151 UUID
.fromString("f3593c18-a8d2-4e51-bdad-0befbf8fb2d1"));
155 public Set
<Taxon
> getRootTaxa() {
156 return getTaxonomicChildren(null);
160 public Set
<Taxon
> getTaxonomicChildren(Taxon parentTaxon
) {
162 // Check whether the map contains children for parentTaxon
163 if (!getTaxonomicChildrenMap().containsKey(parentTaxon
)) {
165 // Make a new child taxa set to ensure deleted taxa
166 // don't re-appear as NULL children
167 Set
<Taxon
> childTaxa
= new HashSet
<Taxon
>();
169 // Root taxa have parentTaxon = NULL
170 if (parentTaxon
== null) {
172 // Get root taxa from data source
173 boolean onlyWithChildren
= false;
174 boolean withMisapplications
= true;
175 childTaxa
.addAll(getApplicationController().getTaxonService().getRootTaxa(
176 getDefaultSec(), onlyWithChildren
, withMisapplications
));
180 // Get children from taxon
181 childTaxa
.addAll(parentTaxon
.getTaxonomicChildren());
184 // Iterate through all child taxa, throwing out NULLs and saving the rest to internal collections
185 Set
<Taxon
> nullTaxa
= new HashSet
<Taxon
>();
186 for (Taxon taxon
: childTaxa
) {
188 // Some imports resulted in NULL child taxa
190 if (parentTaxon
== null) {
191 logger
.warn("NULL taxon in root taxa.");
193 logger
.warn("Taxon " + parentTaxon
.toString() + " has a NULL child taxon.");
198 // Add the taxon to internal collections
199 addTaxonIntern(taxon
);
202 childTaxa
.removeAll(nullTaxa
);
204 // Put the new set in the parent-children map
205 getTaxonomicChildrenMap().put(parentTaxon
, childTaxa
);
207 return getTaxonomicChildrenMap().get(parentTaxon
);
210 private void addTaxonIntern(Taxon taxon
) {
212 // Add it to the transaction if it's a persistent taxon
213 if (!(taxon
instanceof QuickNameTaxon
)) {
214 CdmTransactionController
.addTaxonToTransaction(taxon
);
217 // Remove then re-add session taxon
218 getObservableTaxa().add(taxon
);
222 public void addTaxon(Taxon taxon
) {
224 // Add taxon to its parent's child map
225 Taxon parentTaxon
= taxon
.getTaxonomicParent();
226 getTaxonomicChildren(parentTaxon
).add(taxon
);
228 // Add taxon to internal collections
229 addTaxonIntern(taxon
);
233 public IObservableSet
getObservableTaxa() {
234 if (observableTaxonSet
== null) {
235 Realm realm
= SWTObservables
.getRealm(Display
.getDefault());
236 observableTaxonSet
= new WritableSet(realm
);
238 return observableTaxonSet
;
242 public boolean deleteTaxon(Taxon taxon
) {
244 // Remove taxon from repository collections
247 // If taxon has been saved before, delete it from the data source
248 if (isInPersistentDataSource(taxon
)) {
249 getApplicationController().getTaxonService().removeTaxon(taxon
);
252 // If parent taxon has been saved before, save it to reflect loss of child
253 Taxon parentTaxon
= taxon
.getTaxonomicParent();
254 if (parentTaxon
!= null && isInPersistentDataSource(parentTaxon
)) {
255 getApplicationController().getTaxonService().saveTaxon(parentTaxon
);
261 private boolean isInPersistentDataSource(Taxon taxon
) {
262 UUID taxonUuid
= taxon
.getUuid();
263 if (getApplicationController().getTaxonService()
264 .getTaxonByUuid(taxonUuid
) != null) {
272 public void removeTaxon(Taxon taxon
) {
274 // Recursively remove all children, children's children, etc.
275 clearTaxonomicChildren(taxon
);
277 // Remove from parent and from parent's child map
278 Taxon parentTaxon
= taxon
.getTaxonomicParent();
279 if (parentTaxon
!= null) {
280 removeTaxonomicChild(taxon
, parentTaxon
);
283 // Remove from session taxa
284 getObservableTaxa().remove(taxon
);
286 // Remove from recent names list
287 RecentNamesView
.removeRecentName(taxon
);
290 private void removeTaxonomicChild(Taxon taxon
, Taxon parentTaxon
) {
291 parentTaxon
.removeTaxonomicChild(taxon
);
292 getTaxonomicChildren(parentTaxon
).remove(taxon
);
295 private void clearTaxonomicChildren(Taxon taxon
) {
296 Set
<Taxon
> children
= getTaxonomicChildren(taxon
);
297 if (children
!= null) {
298 for (Taxon child
: children
) {
299 clearTaxonomicChildren(child
);
301 getTaxonomicChildrenMap().remove(taxon
);
302 getObservableTaxa().removeAll(children
);
307 public Collection
<Taxon
> getAllTaxa() {
308 return getObservableTaxa();
312 public void removeAllTaxa() {
313 taxonomicChildrenMap
.clear();
314 observableTaxonSet
.clear();
319 public boolean saveTaxon(Taxon taxon
) {
321 // If this is not in the list of observable taxa, add
322 if (!isInRepository(taxon
)) {
326 // Save taxon to CDM layer
327 CdmUtil
.getTaxonService().saveTaxon(taxon
);
329 // Notify taxon listeners in case name has been updated -
330 // updates editor view tab and recent names
331 taxon
.firePropertyChange("name", null, null);
336 private boolean isInRepository(Taxon taxon
) {
337 return observableTaxonSet
.contains(taxon
);
341 public void setTaxonomicParent(Taxon taxon
, Taxon newParentTaxon
) {
343 // Get old taxonomic parent
344 Taxon oldParentTaxon
= taxon
.getTaxonomicParent();
346 // Set new taxonomic parent
347 taxon
.setTaxonomicParent(newParentTaxon
, null, null);
349 // Update child taxa collection
350 getTaxonomicChildren(oldParentTaxon
).remove(taxon
);
351 getTaxonomicChildren(newParentTaxon
).add(taxon
);
353 // Notify listeners that taxon has moved
354 if (listeners
!= null) {
355 for (ICdmTaxonSetListener listener
: listeners
) {
356 listener
.taxonMoved(taxon
, newParentTaxon
);
362 public TermVocabulary
<Feature
> getFeatures() {
363 if (features
== null) {
364 features
= getApplicationController().getDescriptionService().
365 getDefaultFeatureVocabulary();
371 public SortedSet
<Rank
> getRanks() {
374 OrderedTermVocabulary
<Rank
> rankVocabulary
=
375 getApplicationController().getNameService().getRankVocabulary();
376 ranks
= rankVocabulary
.getOrderedTerms(null);
382 public TermVocabulary
<NomenclaturalStatusType
> getNomStatus() {
383 if (nomStatus
== null) {
384 nomStatus
= getApplicationController().getNameService()
385 .getStatusTypeVocabulary();
391 public SortedSet
<NameRelationshipType
> getNameRelationshipTypes() {
392 if (nameRelationshipTypes
== null) {
393 TermVocabulary
<NameRelationshipType
> nameRelationshipTypesUnsorted
=
394 getApplicationController().getNameService()
395 .getNameRelationshipTypeVocabulary();
397 // Add all terms manually to transaction
398 ITermService termService
= getApplicationController().getTermService();
399 for (NameRelationshipType type
: nameRelationshipTypesUnsorted
) {
400 termService
.saveTerm(type
);
403 // Get sorted list of types
404 nameRelationshipTypes
= nameRelationshipTypesUnsorted
.
405 getTermsOrderedByLabels(Language
.DEFAULT());
407 return nameRelationshipTypes
;
411 public void addTaxonSetListener(ICdmTaxonSetListener listener
) {
413 if (listeners
== null) {
414 listeners
= new ArrayList
<ICdmTaxonSetListener
>();
416 listeners
.add(listener
);
419 class observableTaxaListener
implements ISetChangeListener
{
421 public void handleSetChange(SetChangeEvent event
) {
422 if (event
.diff
!= null) {
423 Set
<Taxon
> additions
= event
.diff
.getAdditions();
424 Set
<Taxon
> removals
= event
.diff
.getRemovals();
426 if (listeners
!= null) {
427 for (ICdmTaxonSetListener listener
: listeners
) {
429 if (additions
.size() > 0) {
430 listener
.taxaAdded(additions
);
433 if (removals
.size() > 0) {
434 listener
.taxaRemoved(removals
);
443 public OrderedTermVocabulary
<TaxonRelationshipType
> getTaxonRelationshipTypes() {
444 if (taxonRelationshipTypes
== null) {
445 taxonRelationshipTypes
= getApplicationController().getTaxonService().
446 getTaxonRelationshipTypeVocabulary();
448 return taxonRelationshipTypes
;
452 public Set
<TaxonRelationshipType
> getConceptRelationshipTypes() {
453 if (conceptRelationshipTypes
== null) {
454 conceptRelationshipTypes
= getTaxonRelationshipTypes().getTerms();
455 conceptRelationshipTypes
.remove(TaxonRelationshipType
.MISAPPLIED_NAME_FOR());
456 conceptRelationshipTypes
.remove(TaxonRelationshipType
.TAXONOMICALLY_INCLUDED_IN());
458 return conceptRelationshipTypes
;