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
.taxeditor
.datasource
.CdmTransactionController
;
43 import eu
.etaxonomy
.taxeditor
.editor
.name
.CdmParserController
;
44 import eu
.etaxonomy
.taxeditor
.navigation
.RecentNamesView
;
51 public class CdmSessionDataRepository
implements ICdmSessionDataRepository
{
52 private static final Logger logger
= Logger
53 .getLogger(CdmSessionDataRepository
.class);
55 private static ICdmSessionDataRepository repository
;
58 * This map of taxa to their taxonomic children is used by
59 * NameTreeContentProvider's getChildren method.
61 * key = taxon, value = key's child taxa Note that a map can have a key ==
62 * null, i.e. no parent taxon
64 private HashMap
<Taxon
, Set
<Taxon
>> taxonomicChildrenMap
;
66 private CdmApplicationController applicationController
;
68 private IObservableSet observableTaxonSet
;
70 private List
<ICdmTaxonSetListener
> listeners
;
72 private TermVocabulary
<Feature
> features
;
74 private SortedSet
<Rank
> ranks
;
76 private TermVocabulary
<NomenclaturalStatusType
> nomStatus
;
78 private SortedSet
<NameRelationshipType
> nameRelationshipTypes
;
80 public static ICdmSessionDataRepository
getDefault() {
82 if (repository
== null) {
83 repository
= new CdmSessionDataRepository();
90 private CdmSessionDataRepository() {
91 getObservableTaxa().addSetChangeListener(new observableTaxaListener());
95 public void clearAllData() {
101 public void clearTaxonData() {
104 // Clear "recent names" list
105 RecentNamesView
.clearRecentNames();
109 public void clearNonTaxonData() {
114 // Parser is also transaction-, and therefore session-, dependent
115 CdmParserController
.clearNonViralNameParser();
119 public void setApplicationController(CdmApplicationController applicationController
) {
120 this.applicationController
= applicationController
;
123 private Map
<Taxon
, Set
<Taxon
>> getTaxonomicChildrenMap() {
124 if (taxonomicChildrenMap
== null) {
125 taxonomicChildrenMap
= new HashMap
<Taxon
, Set
<Taxon
>>();
127 return taxonomicChildrenMap
;
130 private CdmApplicationController
getApplicationController() {
131 // Make sure the app controller has been set
132 if (applicationController
== null) {
133 throw new IllegalStateException("CdmApplicationController not yet set.");
135 return applicationController
;
139 public ReferenceBase
getDefaultSec() {
140 // TODO why is this returning null? and of course, replace w the real deal
141 return getApplicationController().getReferenceService().getReferenceByUuid(
142 UUID
.fromString("f3593c18-a8d2-4e51-bdad-0befbf8fb2d1"));
146 public Set
<Taxon
> getRootTaxa() {
147 return getTaxonomicChildren(null);
151 public Set
<Taxon
> getTaxonomicChildren(Taxon parentTaxon
) {
153 // Check whether the map contains children for parentTaxon
154 if (!getTaxonomicChildrenMap().containsKey(parentTaxon
)) {
156 // Make a new child taxa set to ensure deleted taxa
157 // don't re-appear as NULL children
158 Set
<Taxon
> childTaxa
= new HashSet
<Taxon
>();
160 // Root taxa have parentTaxon = NULL
161 if (parentTaxon
== null) {
163 // Get root taxa from data source
164 boolean onlyWithChildren
= false;
165 boolean withMisapplications
= true;
166 childTaxa
.addAll(getApplicationController().getTaxonService().getRootTaxa(
167 getDefaultSec(), onlyWithChildren
, withMisapplications
));
171 // Get children from taxon
172 childTaxa
.addAll(parentTaxon
.getTaxonomicChildren());
175 // Iterate through all child taxa, throwing out NULLs and saving the rest to internal collections
176 Set
<Taxon
> nullTaxa
= new HashSet
<Taxon
>();
177 for (Taxon taxon
: childTaxa
) {
179 // Some imports resulted in NULL child taxa
181 if (parentTaxon
== null) {
182 logger
.warn("NULL taxon in root taxa.");
184 logger
.warn("Taxon " + parentTaxon
.toString() + " has a NULL child taxon.");
189 // Add the taxon to internal collections
190 addTaxonIntern(taxon
);
193 childTaxa
.removeAll(nullTaxa
);
195 // Put the new set in the parent-children map
196 getTaxonomicChildrenMap().put(parentTaxon
, childTaxa
);
198 return getTaxonomicChildrenMap().get(parentTaxon
);
201 private void addTaxonIntern(Taxon taxon
) {
203 // Add it to the transaction
204 CdmTransactionController
.addTaxonToTransaction(taxon
);
206 // Remove then re-add session taxon
207 getObservableTaxa().add(taxon
);
211 public void addTaxon(Taxon taxon
) {
213 // Add taxon to its parent's child map
214 Taxon parentTaxon
= taxon
.getTaxonomicParent();
215 getTaxonomicChildren(parentTaxon
).add(taxon
);
217 // Add taxon to internal collections
218 addTaxonIntern(taxon
);
222 public IObservableSet
getObservableTaxa() {
223 if (observableTaxonSet
== null) {
224 Realm realm
= SWTObservables
.getRealm(Display
.getDefault());
225 observableTaxonSet
= new WritableSet(realm
);
227 return observableTaxonSet
;
231 public boolean deleteTaxon(Taxon taxon
) {
233 // Remove taxon from repository collections
236 // If taxon has been saved before, delete it from the data source
237 if (isInPersistentDataSource(taxon
)) {
238 getApplicationController().getTaxonService().removeTaxon(taxon
);
241 // If parent taxon has been saved before, save it to reflect loss of child
242 Taxon parentTaxon
= taxon
.getTaxonomicParent();
243 if (parentTaxon
!= null && isInPersistentDataSource(parentTaxon
)) {
244 getApplicationController().getTaxonService().saveTaxon(parentTaxon
);
250 private boolean isInPersistentDataSource(Taxon taxon
) {
251 UUID taxonUuid
= taxon
.getUuid();
252 if (getApplicationController().getTaxonService()
253 .getTaxonByUuid(taxonUuid
) != null) {
261 public void removeTaxon(Taxon taxon
) {
263 // Remove from session taxa
264 getObservableTaxa().remove(taxon
);
266 // Recursively remove all children, children's children, etc.
267 clearTaxonomicChildren(taxon
);
269 // Remove from parent and from parent's child map
270 Taxon parentTaxon
= taxon
.getTaxonomicParent();
271 if (parentTaxon
!= null) {
272 removeTaxonomicChild(taxon
, parentTaxon
);
275 // Remove from recent names list
276 RecentNamesView
.removeRecentName(taxon
);
279 private void removeTaxonomicChild(Taxon taxon
, Taxon parentTaxon
) {
280 parentTaxon
.removeTaxonomicChild(taxon
);
281 getTaxonomicChildren(parentTaxon
).remove(taxon
);
284 private void clearTaxonomicChildren(Taxon taxon
) {
285 Set
<Taxon
> children
= getTaxonomicChildren(taxon
);
286 if (children
!= null) {
287 for (Taxon child
: children
) {
288 clearTaxonomicChildren(child
);
290 getTaxonomicChildrenMap().remove(taxon
);
291 getObservableTaxa().removeAll(children
);
296 public Collection
<Taxon
> getAllTaxa() {
297 return getObservableTaxa();
301 public void removeAllTaxa() {
302 taxonomicChildrenMap
.clear();
303 observableTaxonSet
.clear();
308 public boolean saveTaxon(Taxon taxon
) {
310 // If this is not in the list of observable taxa, add
311 if (!isInRepository(taxon
)) {
315 // Save taxon to CDM layer
316 CdmUtil
.getTaxonService().saveTaxon(taxon
);
318 // Notify taxon listeners in case name has been updated -
319 // updates editor view tab and recent names
320 taxon
.firePropertyChange("name", null, null);
325 private boolean isInRepository(Taxon taxon
) {
326 return observableTaxonSet
.contains(taxon
);
330 public void setTaxonomicParent(Taxon taxon
, Taxon newParentTaxon
) {
332 // Get old taxonomic parent
333 Taxon oldParentTaxon
= taxon
.getTaxonomicParent();
335 // Set new taxonomic parent
336 taxon
.setTaxonomicParent(newParentTaxon
, null, null);
338 // Update child taxa collection
339 getTaxonomicChildren(oldParentTaxon
).remove(taxon
);
340 getTaxonomicChildren(newParentTaxon
).add(taxon
);
342 // Notify listeners that taxon has moved
343 if (listeners
!= null) {
344 for (ICdmTaxonSetListener listener
: listeners
) {
345 listener
.taxonMoved(taxon
, newParentTaxon
);
351 public TermVocabulary
<Feature
> getFeatures() {
352 if (features
== null) {
353 features
= getApplicationController().getDescriptionService().
354 getDefaultFeatureVocabulary();
360 public SortedSet
<Rank
> getRanks() {
363 OrderedTermVocabulary
<Rank
> rankVocabulary
=
364 getApplicationController().getNameService().getRankVocabulary();
365 ranks
= rankVocabulary
.getOrderedTerms(null);
371 public TermVocabulary
<NomenclaturalStatusType
> getNomStatus() {
372 if (nomStatus
== null) {
373 nomStatus
= getApplicationController().getNameService()
374 .getStatusTypeVocabulary();
380 public SortedSet
<NameRelationshipType
> getNameRelationshipTypes() {
381 if (nameRelationshipTypes
== null) {
382 TermVocabulary
<NameRelationshipType
> nameRelationshipTypesUnsorted
=
383 getApplicationController().getNameService()
384 .getNameRelationshipTypeVocabulary();
386 // Add all terms manually to transaction
387 ITermService termService
= getApplicationController().getTermService();
388 for (NameRelationshipType type
: nameRelationshipTypesUnsorted
) {
389 termService
.saveTerm(type
);
392 // Get sorted list of types
393 nameRelationshipTypes
= nameRelationshipTypesUnsorted
.
394 getTermsOrderedByLabels(Language
.DEFAULT());
396 return nameRelationshipTypes
;
400 public void addTaxonSetListener(ICdmTaxonSetListener listener
) {
402 if (listeners
== null) {
403 listeners
= new ArrayList
<ICdmTaxonSetListener
>();
405 listeners
.add(listener
);
408 class observableTaxaListener
implements ISetChangeListener
{
410 public void handleSetChange(SetChangeEvent event
) {
411 if (event
.diff
!= null) {
412 Set
<Taxon
> additions
= event
.diff
.getAdditions();
413 Set
<Taxon
> removals
= event
.diff
.getRemovals();
415 if (listeners
!= null) {
416 for (ICdmTaxonSetListener listener
: listeners
) {
418 if (additions
.size() > 0) {
419 listener
.taxaAdded(additions
);
422 if (removals
.size() > 0) {
423 listener
.taxaRemoved(removals
);